summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE202
-rw-r--r--NOTICE24
-rw-r--r--README51
-rw-r--r--apps/common/cli.h123
-rw-r--r--apps/common/crt0_arm.S13
-rw-r--r--apps/common/crt0_bfin.S34
-rw-r--r--apps/common/crt0_cf.S11
-rw-r--r--apps/common/crt0_mb.S14
-rw-r--r--apps/common/crt0_mips.s25
-rw-r--r--apps/common/crt0_ppc.S16
-rw-r--r--apps/common/cygprof.c26
-rw-r--r--apps/common/monlib.c1115
-rw-r--r--apps/common/monlib.h239
-rw-r--r--apps/common/tfs.h187
-rwxr-xr-xapps/common/timer.h46
-rw-r--r--apps/demo/README7
-rw-r--r--apps/demo/bashrc8
-rw-r--r--apps/demo/cfg.h1
-rw-r--r--apps/demo/main.c250
-rw-r--r--apps/demo/makefile229
-rw-r--r--apps/demo/strace.c100
-rw-r--r--main/common/alttfsdevtbl.S67
-rw-r--r--main/common/aout.h53
-rw-r--r--main/common/arp.c650
-rw-r--r--main/common/bits.h67
-rw-r--r--main/common/bmem.h38
-rw-r--r--main/common/boardinfo.c320
-rw-r--r--main/common/boardinfo.h56
-rw-r--r--main/common/cache.c119
-rw-r--r--main/common/cache.h66
-rw-r--r--main/common/cast.c412
-rw-r--r--main/common/cf.c207
-rw-r--r--main/common/cf.h39
-rw-r--r--main/common/chario.c543
-rw-r--r--main/common/cli.h130
-rw-r--r--main/common/cmdtbl.c484
-rw-r--r--main/common/coff.h114
-rw-r--r--main/common/cstart.c148
-rw-r--r--main/common/dallasdate.c362
-rw-r--r--main/common/date.c160
-rw-r--r--main/common/date.h46
-rw-r--r--main/common/devices.c149
-rw-r--r--main/common/devices.h65
-rw-r--r--main/common/dhcp_00.c259
-rw-r--r--main/common/dhcp_01.c246
-rw-r--r--main/common/dhcp_02.c89
-rw-r--r--main/common/dhcp_03.c101
-rw-r--r--main/common/dhcpboot.c1328
-rwxr-xr-xmain/common/dns.c760
-rw-r--r--main/common/docmd.c940
-rw-r--r--main/common/edit.c722
-rw-r--r--main/common/elf.h159
-rw-r--r--main/common/endian.h68
-rwxr-xr-xmain/common/env.c858
-rw-r--r--main/common/ether.h714
-rw-r--r--main/common/etheraddr.S37
-rw-r--r--main/common/ethernet.c1808
-rwxr-xr-xmain/common/fbi.c1728
-rwxr-xr-xmain/common/fbi.h51
-rwxr-xr-xmain/common/flash.c1399
-rwxr-xr-xmain/common/flash.h125
-rw-r--r--main/common/flashram.c60
-rwxr-xr-xmain/common/font.c6751
-rwxr-xr-xmain/common/font.h47
-rw-r--r--main/common/gdb.c686
-rw-r--r--main/common/genlib.h269
-rw-r--r--main/common/i2c.c159
-rw-r--r--main/common/i2c.h127
-rw-r--r--main/common/icmp.c646
-rwxr-xr-xmain/common/if.c812
-rw-r--r--main/common/igmp.c200
-rw-r--r--main/common/inc_check.h412
-rw-r--r--main/common/jffs2.c2336
-rw-r--r--main/common/ledit_vi.c737
-rw-r--r--main/common/ledit_vt100.c462
-rw-r--r--main/common/malloc.c763
-rw-r--r--main/common/mallocdebug.h47
-rw-r--r--main/common/memcmds.c1259
-rw-r--r--main/common/memtrace.c379
-rw-r--r--main/common/misc.c528
-rw-r--r--main/common/misccmds.c578
-rw-r--r--main/common/monbuilt.c46
-rw-r--r--main/common/moncom.c427
-rw-r--r--main/common/moncomptr.S39
-rw-r--r--main/common/monflags.h56
-rw-r--r--main/common/monlib.c1133
-rw-r--r--main/common/monlib.h253
-rw-r--r--main/common/monprof.c646
-rw-r--r--main/common/monprof.h39
-rw-r--r--main/common/mprintf.c691
-rw-r--r--main/common/msbin.h87
-rwxr-xr-xmain/common/nand.c350
-rw-r--r--main/common/nand.h34
-rw-r--r--main/common/password.c289
-rw-r--r--main/common/pci.c747
-rw-r--r--main/common/pci.h363
-rw-r--r--main/common/redirect.c265
-rw-r--r--main/common/reg_cache.c218
-rw-r--r--main/common/sbrk.c144
-rw-r--r--main/common/sd.c561
-rw-r--r--main/common/sd.h237
-rw-r--r--main/common/spif.c456
-rw-r--r--main/common/spif.h69
-rw-r--r--main/common/start.c496
-rw-r--r--main/common/stddefs.h62
-rw-r--r--main/common/struct.c783
-rw-r--r--main/common/symtbl.c215
-rw-r--r--main/common/syslog.c337
-rw-r--r--main/common/tcpstuff.c168
-rw-r--r--main/common/term.c160
-rw-r--r--main/common/term.h61
-rw-r--r--main/common/tfs.c3379
-rw-r--r--main/common/tfs.h213
-rw-r--r--main/common/tfsapi.c622
-rwxr-xr-xmain/common/tfsclean1.c2195
-rw-r--r--main/common/tfsclean2.c180
-rw-r--r--main/common/tfsclean3.c153
-rw-r--r--main/common/tfscli.c939
-rw-r--r--main/common/tfsloader.c523
-rw-r--r--main/common/tfslog.c171
-rw-r--r--main/common/tfsprivate.h328
-rw-r--r--main/common/tftp.c1542
-rwxr-xr-xmain/common/time.h42
-rw-r--r--main/common/timer.h71
-rwxr-xr-xmain/common/timestuff.c386
-rwxr-xr-xmain/common/tsi.c231
-rw-r--r--main/common/tsi.h35
-rw-r--r--main/common/umongpio.h65
-rw-r--r--main/common/version.h170
-rw-r--r--main/common/warmstart.h34
-rw-r--r--main/common/xmodem.c855
-rw-r--r--main/cpu/arm/arm.h78
-rw-r--r--main/cpu/arm/cache_arm.c124
-rw-r--r--main/cpu/arm/except_arm.c94
-rw-r--r--main/cpu/arm/gdbregs_arm.c36
-rw-r--r--main/cpu/arm/ldatags.c441
-rw-r--r--main/cpu/arm/misc_arm.c64
-rw-r--r--main/cpu/arm/misc_arm.h28
-rw-r--r--main/cpu/arm/regs_arm.c32
-rw-r--r--main/cpu/arm/strace_arm.c156
-rw-r--r--main/cpu/arm/vectors_arm.S65
-rw-r--r--main/cpu/template/except_template.c87
-rw-r--r--main/cpu/template/strace_template.c124
-rw-r--r--main/dev/bp27
-rw-r--r--main/dev/fb_draw.c261
-rw-r--r--main/dev/fb_draw.h8
-rw-r--r--main/dev/fb_fonts.h237
-rw-r--r--main/dev/smsc911x.c392
-rw-r--r--main/dev/smsc911x.h304
-rw-r--r--main/dev/uart16550.c195
-rw-r--r--main/dev/uart16550.h137
-rw-r--r--main/dev/vga_lookup.h51
-rw-r--r--main/flash/README16
-rw-r--r--main/flash/devices/s29gl512n_16x1.c763
-rw-r--r--main/flash/devices/s29gl512n_16x1.h12
-rw-r--r--main/glib/abs.c43
-rw-r--r--main/glib/asctime.c19
-rw-r--r--main/glib/atoi.c42
-rw-r--r--main/glib/crc16.c59
-rw-r--r--main/glib/crc32.c155
-rw-r--r--main/glib/div.c77
-rwxr-xr-xmain/glib/getglib49
-rw-r--r--main/glib/getopt.c139
-rwxr-xr-xmain/glib/inrange.c71
-rw-r--r--main/glib/ldiv.c56
-rw-r--r--main/glib/list34
-rw-r--r--main/glib/memccpy.c53
-rw-r--r--main/glib/memchr.c54
-rw-r--r--main/glib/memcmp.c57
-rw-r--r--main/glib/memcpy.c108
-rw-r--r--main/glib/memset.c128
-rwxr-xr-xmain/glib/pollconsole.c44
-rwxr-xr-xmain/glib/prascii.c22
-rwxr-xr-xmain/glib/printmem.c40
-rwxr-xr-xmain/glib/smemcpy.c150
-rwxr-xr-xmain/glib/smemset.c71
-rw-r--r--main/glib/strcasecmp.c67
-rw-r--r--main/glib/strcat.c46
-rw-r--r--main/glib/strchr.c54
-rw-r--r--main/glib/strcmp.c51
-rw-r--r--main/glib/strcpy.c45
-rw-r--r--main/glib/strlen.c18
-rw-r--r--main/glib/strncat.c63
-rw-r--r--main/glib/strncmp.c53
-rw-r--r--main/glib/strncpy.c63
-rw-r--r--main/glib/strnlen.c42
-rw-r--r--main/glib/strpbrk.c54
-rw-r--r--main/glib/strrchr.c55
-rw-r--r--main/glib/strstr.c62
-rw-r--r--main/glib/strtok.c136
-rw-r--r--main/glib/strtol.c143
-rwxr-xr-xmain/glib/strtolower.c33
-rw-r--r--main/glib/strtoul.c120
-rwxr-xr-xmain/glib/swap.c18
-rwxr-xr-xmain/glib/ticktock.c48
-rwxr-xr-xmain/make/common.make132
-rw-r--r--main/make/defaults.make23
-rw-r--r--main/make/objects.make25
-rw-r--r--main/make/rules.make461
-rw-r--r--main/zlib/README25
-rw-r--r--main/zlib/adler32.c46
-rw-r--r--main/zlib/adler_mail_1.txt23
-rw-r--r--main/zlib/adler_mail_2.txt12
-rw-r--r--main/zlib/deflate.h316
-rw-r--r--main/zlib/gzio.c455
-rw-r--r--main/zlib/infblock.c400
-rw-r--r--main/zlib/infblock.h39
-rw-r--r--main/zlib/infcodes.c257
-rw-r--r--main/zlib/infcodes.h27
-rw-r--r--main/zlib/inffast.c170
-rw-r--r--main/zlib/inffast.h17
-rw-r--r--main/zlib/inffixed.h151
-rw-r--r--main/zlib/inflate.c370
-rw-r--r--main/zlib/inftrees.c457
-rw-r--r--main/zlib/inftrees.h58
-rw-r--r--main/zlib/infutil.c88
-rw-r--r--main/zlib/infutil.h98
-rw-r--r--main/zlib/trees.c1212
-rw-r--r--main/zlib/trees.h128
-rw-r--r--main/zlib/uncompr.c56
-rw-r--r--main/zlib/zconf.h277
-rw-r--r--main/zlib/zcrc32.c33
-rw-r--r--main/zlib/zlib.h893
-rw-r--r--main/zlib/zutil.c236
-rw-r--r--main/zlib/zutil.h217
-rwxr-xr-xports/csb740/.vimrc13
-rwxr-xr-xports/csb740/CSB740_boot.ldt63
-rwxr-xr-xports/csb740/CSB740_ramtst.ldt59
-rwxr-xr-xports/csb740/_vimrc13
-rwxr-xr-xports/csb740/ad7843.c334
-rwxr-xr-xports/csb740/ad7843.h35
-rwxr-xr-xports/csb740/ads7846.c180
-rwxr-xr-xports/csb740/ads7846.h56
-rwxr-xr-xports/csb740/bashrc12
-rwxr-xr-xports/csb740/bdi2000.cfg188
-rwxr-xr-xports/csb740/config.h202
-rwxr-xr-xports/csb740/cpu.h25
-rwxr-xr-xports/csb740/cpu_gpio.h113
-rwxr-xr-xports/csb740/cpu_i2c.c322
-rwxr-xr-xports/csb740/cpu_i2c.h269
-rwxr-xr-xports/csb740/cpuio.c313
-rwxr-xr-xports/csb740/cpuio.h76
-rwxr-xr-xports/csb740/etherdev.c241
-rwxr-xr-xports/csb740/fbidemo163
-rwxr-xr-xports/csb740/font8x16.h3679
-rwxr-xr-xports/csb740/gdbregs.c1
-rwxr-xr-xports/csb740/lcd_lut.h289
-rwxr-xr-xports/csb740/makefile129
-rw-r--r--ports/csb740/nand740.c333
-rwxr-xr-xports/csb740/omap3530.h497
-rwxr-xr-xports/csb740/omap3530_gpio.c329
-rwxr-xr-xports/csb740/omap3530_iomux.c530
-rwxr-xr-xports/csb740/omap3530_iomux.h1077
-rwxr-xr-xports/csb740/omap3530_lcd.c342
-rwxr-xr-xports/csb740/omap3530_lcd.h75
-rwxr-xr-xports/csb740/omap3530_mem.h184
-rwxr-xr-xports/csb740/omap3530_sdmmc.c505
-rwxr-xr-xports/csb740/ram_reset.S211
-rwxr-xr-xports/csb740/regnames.c1
-rwxr-xr-xports/csb740/rom_reset.S418
-rwxr-xr-xports/csb740/target_version.h17
-rwxr-xr-xports/csb740/tfsdev.h31
-rwxr-xr-xports/csb740/xcmddcl.h34
-rwxr-xr-xports/csb740/xcmdtbl.h19
-rw-r--r--ports/template/OLD_TO_NEW.txt100
-rw-r--r--ports/template/README.txt10
-rw-r--r--ports/template/TEMPLATE_boot.ldt69
-rw-r--r--ports/template/TEMPLATE_ramtst.ldt69
-rw-r--r--ports/template/_vimrc13
-rw-r--r--ports/template/bashrc16
-rw-r--r--ports/template/config.h199
-rw-r--r--ports/template/cpu.h3
-rw-r--r--ports/template/cpuio.c192
-rw-r--r--ports/template/cpuio.h3
-rw-r--r--ports/template/etherdev.c247
-rw-r--r--ports/template/except_template.c78
-rwxr-xr-xports/template/flashtest.scr122
-rw-r--r--ports/template/makefile212
-rw-r--r--ports/template/regnames.c10
-rw-r--r--ports/template/reset.S110
-rw-r--r--ports/template/strace_template.c116
-rw-r--r--ports/template/target_version.h8
-rw-r--r--ports/template/tfsdev.h36
-rw-r--r--ports/template/xcmddcl.h14
-rw-r--r--ports/template/xcmdtbl.h12
285 files changed, 83325 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..e634c5b
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,24 @@
+ Micromonitor Embedded System Boot Monitor
+
+ This package contains code primarily developed at
+ Bell Laboratories, Alcatel-Lucent Technologies
+ (http:http://www.alcatel-lucent.com/).
+
+ This software contains code derived from the Freebsd project
+ (https://www.freebsd.org/).
+
+ The compression/decomppresion support is provided by the Zlib
+ project (www.zlib.net).
+
+ Some files from both Freebsd and Zlib have been modified
+ to build in the Micromonitor environment.
+
+ Some port/cpu/device-specific files are from Mike Kelly
+ Cogent Computer Systems (http://www.cogcomp.com).
+
+ An SMC ethernet driver from Jay Monkman
+ (www.lopingdog.com).
+
+ Some improvements to original JFFS2 code from Bill Gatliff
+ (www.billgatliff.com).
+
diff --git a/README b/README
new file mode 100644
index 0000000..73fda36
--- /dev/null
+++ b/README
@@ -0,0 +1,51 @@
+This is the top-level of the MicroMonitor source tree.
+
+There are three main directories:
+umon_main:
+ This is the common code reusable on various targets as the core
+ of MicroMonitor's functionality.
+umon_ports:
+ This directory contains the public ports of MicroMonitor. Each
+ subdirectory contains the makefile and target-specific code for
+ one uMon port.
+umon_apps:
+ This code provides a few different application examples for use
+ after the bootmonitor is built and running on your target. The
+ best place to go there is umon_apps/demo. This directory contains
+ the source and makefile that support building a basic application
+ for any target supported by MicroMonitor.
+
+For a quick introduction refer to:
+ http://www.umonfw.com/docs/white_paper.pdf
+For a lot more than you'll ever care to read about it refer to:
+ http://www.umonfw.com/docs/umon_user_manual.pdf
+OR...
+
+To get started, refer to umon_main/README.
+
+-----------------------------------------------------------------------
+
+Re-release of Micromonitor (aka uMon) under the Apache 2.0 license...
+
+Starting with the original umon1.19 code I referred to
+
+http://www.apache.org/dev/apply-license.html#new
+
+to do what was necessary to re-release a new smaller version of the
+uMon code under the Apache 2.0 license. This was originally motivated
+by a request from a GSOC (Google Summer of Code) student wanting to
+port uMon to the BeagleBone Black board as an alternative bootloader
+for use by the RTEMS embedded operating system.
+
+I copied http://www.apache.org/licenses/LICENSE-2.0.txt
+to this local LICENSE file.
+
+I started with https://www.apache.org/licenses/example-NOTICE.txt
+to create an appropriate NOTICE file.
+
+This README file was last modified on Mar 28, 2015.
+
+Primary contact:
+Ed Sutter ed.sutter@alcatel-lucent.com
+
+-----------------------------------------------------------------------
diff --git a/apps/common/cli.h b/apps/common/cli.h
new file mode 100644
index 0000000..6384816
--- /dev/null
+++ b/apps/common/cli.h
@@ -0,0 +1,123 @@
+/* cli.h:
+ * Header file for Command Line Interface related stuff.
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Note1: the majority of this code was edited with 4-space tabs.
+ * Note2: as more and more contributions are accepted, the term "author"
+ * is becoming a mis-representation of credit.
+ *
+ * Original author: Ed Sutter
+ * Email: esutter@lucent.com
+ * Phone: 908-582-2351
+ */
+#ifndef _cli_h
+#define _cli_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Command table structure used by the monitor:
+ */
+struct monCommand {
+ char *name; /* Name of command seen by user. */
+ int (*func)(int,char **); /* Called when command is invoked. */
+ char **helptxt; /* Help text (see notes below). */
+ long flags; /* Single-bit flags for various uses */
+ /* (see the CMDFLAG_XXX macros). */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Bits currently assigned to command flags used in the monCommand
+ * structure...
+ */
+#define CMDFLAG_NOMONRC 1
+
+/* Maximum size of a command line:
+ */
+#ifndef CMDLINESIZE
+#define CMDLINESIZE 128
+#endif
+
+/* Maximum number of arguments in a command line:
+ */
+#define ARGCNT 24
+
+/* Definitions for docommand() return values:
+ *
+ * Note that the CMD_SUCCESS, CMD_FAILURE and CMD_PARAM_ERROR are return
+ * values used by the local command code also. The remaining errors
+ * (CMD_LINE_ERROR, CMD_ULVL_DENIED and CMD_NOT_FOUND) are used only by
+ # the docommand() function.
+ *
+ * CMD_SUCCESS:
+ * Everything worked ok.
+ * CMD_FAILURE:
+ * Command parameters were valid, but command itself failed for some other
+ * reason. The docommand() function does not print a message here, it
+ * is assumed that the error message was printed by the local function.
+ * CMD_PARAM_ERROR:
+ * Command line did not parse properly. Control was passed to a
+ * local command function, but argument syntax caused it to choke.
+ * In this case docommand() will print out the generic CLI syntax error
+ * message.
+ * CMD_LINE_ERROR:
+ * Command line itself was invalid. Too many args, invalid shell var
+ * syntax, etc.. Somekind of command line error prior to checking for
+ * the command name-to-function match.
+ * CMD_ULVL_DENIED:
+ * Command's user level is higher than current user level, so access
+ * is denied.
+ * CMD_NOT_FOUND:
+ * Since these same return values are used for each command function
+ * plus the docommand() function, this error indicates that docommand()
+ * could not even find the command in the command table.
+ * CMD_MONRC_DENIED:
+ * The command cannot execute because it is considered illegal
+ * when run from within the monrc file.
+ */
+#define CMD_SUCCESS 0
+#define CMD_FAILURE -1
+#define CMD_PARAM_ERROR -2
+#define CMD_LINE_ERROR -3
+#define CMD_ULVL_DENIED -4
+#define CMD_NOT_FOUND -5
+#define CMD_MONRC_DENIED -6
+
+/* Notes on help text array:
+ * The monitor's CLI processor assumes that every command's help text
+ * array abides by a few basic rules...
+ * First of all, it assumes that every array has AT LEAST two strings.
+ * The first string in the array of strings is assumed to be a one-line
+ * abstract describing the command.
+ * The second string in the array of strings is assumed to be a usage
+ * message that describes the syntax of the arguments needed by the command.
+ * If this second string is an empty string (""), the docommand() prints out
+ * a generic usage string indicating that there are no options or arguements
+ * to apply to the command.
+ * All remaining lines are formatted based on the needs of the individual
+ * command and the final string is a null pointer to let the CLI processor
+ * know where the end is.
+ * Following is an example help text array...
+ *
+ * char *HelpHelp[] = {
+ * "Display command set",
+ * "-[d] [commandname]",
+ * "Options:",
+ * " -d list commands and descriptions",
+ * 0,
+ * };
+ *
+ */
+#endif
diff --git a/apps/common/crt0_arm.S b/apps/common/crt0_arm.S
new file mode 100644
index 0000000..6e49597
--- /dev/null
+++ b/apps/common/crt0_arm.S
@@ -0,0 +1,13 @@
+#include "cfg.h"
+
+ .extern AppStack
+ .extern Cstart
+ .global start
+
+ /* Set stack pointer to end of AppStack and jump to Cstart:
+ */
+start:
+ ldr sp, =(AppStack + APPSTACKSIZE - 4)
+
+jump_to_c:
+ bl Cstart
diff --git a/apps/common/crt0_bfin.S b/apps/common/crt0_bfin.S
new file mode 100644
index 0000000..dda3a82
--- /dev/null
+++ b/apps/common/crt0_bfin.S
@@ -0,0 +1,34 @@
+#include "cfg.h"
+
+ .extern _AppStack
+ .extern _Cstart
+ .global start
+
+ .text
+
+start:
+ /* Clear all DAG registers:
+ */
+ R0 = 0
+ I0 = R0
+ I1 = R0
+ I2 = R0
+ I3 = R0
+ L0 = R0
+ L1 = R0
+ L2 = R0
+ L3 = R0
+ B0 = R0
+ B1 = R0
+ B2 = R0
+ B3 = R0
+ M0 = R0
+ M1 = R0
+ M2 = R0
+ M3 = R0
+ LC0 = R0;
+ LC1 = R0;
+
+ sp.h = _AppStack+(APPSTACKSIZE-32)
+ sp.l = _AppStack+(APPSTACKSIZE-32)
+ jump _Cstart
diff --git a/apps/common/crt0_cf.S b/apps/common/crt0_cf.S
new file mode 100644
index 0000000..929c7ce
--- /dev/null
+++ b/apps/common/crt0_cf.S
@@ -0,0 +1,11 @@
+#include "cfg.h"
+
+ .extern AppStack
+ .extern Cstart
+ .global start
+
+ .text
+
+start:
+ move.l #AppStack+(APPSTACKSIZE-32),%sp
+ jsr Cstart
diff --git a/apps/common/crt0_mb.S b/apps/common/crt0_mb.S
new file mode 100644
index 0000000..9894b9a
--- /dev/null
+++ b/apps/common/crt0_mb.S
@@ -0,0 +1,14 @@
+#include "cfg.h"
+
+ .extern AppStack
+ .extern Cstart
+ .global start
+
+ /* Set stack pointer to end of AppStack and jump to Cstart:
+ */
+start:
+ addi r1, r0, AppStack
+ addi r1, r1, (APPSTACKSIZE-16)
+
+jump_to_c:
+ brai Cstart
diff --git a/apps/common/crt0_mips.s b/apps/common/crt0_mips.s
new file mode 100644
index 0000000..a4e4a4e
--- /dev/null
+++ b/apps/common/crt0_mips.s
@@ -0,0 +1,25 @@
+#include "cfg.h"
+
+#define sp $29
+#define k0 $26
+#define KSEG_MSK 0xE0000000
+#define K0BASE 0x80000000
+#define KSEG1A(reg) \
+ and reg, ~KSEG_MSK; \
+ or reg, K1BASE;
+
+ .extern AppStack
+ .global start
+
+ .text
+ .set noreorder
+
+start:
+ la sp, AppStack
+ addiu sp, APPSTACKSIZE
+ addiu sp, -4*4
+
+goToC:
+ la k0,Cstart
+ j k0
+ nop
diff --git a/apps/common/crt0_ppc.S b/apps/common/crt0_ppc.S
new file mode 100644
index 0000000..80ef3db
--- /dev/null
+++ b/apps/common/crt0_ppc.S
@@ -0,0 +1,16 @@
+#include "cfg.h"
+#define sp 1
+#define r0 0
+#define r7 7
+
+ .extern AppStack
+ .extern Cstart
+ .globl start
+
+start:
+ lis sp, (AppStack+(APPSTACKSIZE-4))@h
+ addi sp, sp, (AppStack+(APPSTACKSIZE-4))@l
+ addi r7, r0, -8
+ and sp, sp, r7 /* 8-byte aligned (EABI spec) */
+ ba Cstart
+ nop
diff --git a/apps/common/cygprof.c b/apps/common/cygprof.c
new file mode 100644
index 0000000..b10bff2
--- /dev/null
+++ b/apps/common/cygprof.c
@@ -0,0 +1,26 @@
+/* This file supports the GCC option '-finstrument-functions' to
+ * insert per-function entry and exit calls...
+ * Every function that is recompiled with that option on will call
+ * __cyg_profile_func_enter() at the entrypoint and __cyg_profile_func_exit()
+ * at the exitpoint.
+ * This can be an extremely powerful capability for diagnosing various
+ * problems with system because it provides a trace of all functions
+ * executed. The disadvantage is time and space (minor detail)!
+ */
+int cyg_prof_on;
+
+void
+__cyg_profile_func_enter (void *this_fn, void *call_site)
+{
+ if (cyg_prof_on) {
+ mon_memtrace("IN: %x %x\n", this_fn, call_site);
+ }
+}
+
+void
+__cyg_profile_func_exit (void *this_fn, void *call_site)
+{
+ if (cyg_prof_on) {
+ mon_memtrace("OUT: %x %x\n", this_fn, call_site);
+ }
+}
diff --git a/apps/common/monlib.c b/apps/common/monlib.c
new file mode 100644
index 0000000..33c05e4
--- /dev/null
+++ b/apps/common/monlib.c
@@ -0,0 +1,1115 @@
+/* monlib.c:
+ * This file is part of the monitor code, but it is actually linked into
+ * the application. It is built with (but not linked with) the monitor,
+ * then the monlib.o file is linked with the application.
+ * The only requirement on the application is that it know where the address
+ * of the monCom function is in the monitor's space.
+ * The monCom function will be accessible in some "well-known" way (processor
+ * and platform dependent) so that this will not be a problem.
+ *
+ * This monlib.c file is a replacement for the older mechanism that was
+ * a bit more error-prone... A table of function pointers existed at some
+ * well-known location in the monitor, and the content of that table was
+ * assumed to also be "well-known". This new version only assumes that the
+ * pointer to monCom is well-known; everything else will work based on the
+ * fact that the monitor and application will share the monlib.h header
+ * file.
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Note1: the majority of this code was edited with 4-space tabs.
+ * Note2: as more and more contributions are accepted, the term "author"
+ * is becoming a mis-representation of credit.
+ *
+ * Original author: Ed Sutter
+ * Email: esutter@lucent.com
+ * Phone: 908-582-2351
+ */
+#include "monlib.h"
+
+static int (*_tfsseek)(int,int,int);
+static int (*_tfsgetline)(int,char *,int);
+static int (*_tfsipmod)(char *,char *,int,int);
+static int (*_tfsinit)(void);
+static int (*_tfsadd)(char *,char *,char *,unsigned char *,int);
+static int (*_tfsunlink)(char *);
+static int (*_tfsrun)(char **,int);
+static int (*_tfsread)(int,char *,int);
+static int (*_tfswrite)(int,char *,int);
+static int (*_tfsopen)(char *,long,char *);
+static int (*_tfsclose)(int,char *);
+static int (*_printf)();
+static int (*_cprintf)();
+static int (*_sprintf)();
+static int (*_monrestart)(int);
+static int (*_rputchar)(unsigned char c);
+static int (*_getchar)(void);
+static int (*_gotachar)(void);
+static int (*_getbytes)(char *,int,int);
+static int (*_addcommand)(struct monCommand *,char *);
+static int (*_docommand)(char *,int);
+static int (*_getline)(char *,int,int);
+static int (*_tfsfstat)(char *,struct tfshdr *);
+static int (*_tfseof)(int);
+static int (*_decompress)(char *,int,char *);
+static int (*_tfstruncate)(int,long);
+static int (*_heapextend)(char *,int);
+static int (*_tfslink)(char *,char *);
+static int (*_pcicfgwrite)(int,int,int,int,int,unsigned long);
+static int (*_i2cwrite)(int,int,unsigned char *,int);
+static int (*_i2cread)(int,int,unsigned char *,int);
+static int (*_flashwrite)(char *,char *,int);
+static int (*_flasherase)(int);
+static int (*_flashinfo)(int,int *,char **);
+static int (*_flashoverride)(void *,int,int);
+static int (*_sendenet)(char *,int);
+static int (*_recvenet)(char *,int);
+static int (*_printpkt)(char *,int,int);
+static int (*_setenv)(char *,char *);
+static int (*_watchdog)(void);
+static int (*_timeofday)(int,void *);
+static int (*_montimer)(int cmd, void *arg);
+
+static char *(*_getenv)(char *);
+static char *(*_version)(void);
+static char *(*_getenvp)(void);
+#ifdef MALLOC_DEBUG
+static char *(*_malloc)(int,char *,int);
+static char *(*_realloc)(char *buf,int,char *,int);
+#else
+static char *(*_malloc)(int);
+static char *(*_realloc)(char *,int);
+#endif
+static char *(*_getsym)(char *,char *,int);
+
+static void (*_intsrestore)(unsigned long);
+static void (*_appexit)(int);
+static void (*_free)(char *);
+static void (*_getargv)(int *,char ***);
+static void (*_profiler)(void *);
+static void (*_bbc)(char *,int);
+static void (*_memtrace)();
+static void (*_appwarmstart)(unsigned long);
+static void (*_mondelay)(long);
+static void (*_printmem)(char *,int,int);
+
+static long (*_tfsctrl)(int,long,long);
+static long (*_tfstell)(int);
+static long (*_portcmd)(int,void *);
+
+static struct tfshdr *(*_tfsnext)(struct tfshdr *);
+static struct tfshdr *(*_tfsstat)(char *);
+
+static unsigned long (*_i2cctrl)(int,int,unsigned long,unsigned long);
+static unsigned long (*_pcicfgread)(int,int,int,int,int);
+static unsigned long (*_pcictrl)(int,int,unsigned long,unsigned long);
+static unsigned long (*_crc32)(unsigned char *,unsigned long);
+static unsigned long (*_intsoff)(void);
+static unsigned long (*_assign_handler)(long,unsigned long,unsigned long);
+
+static unsigned short (*_xcrc16)(unsigned char *,unsigned long);
+
+
+static void (*_monlock)(void);
+static void (*_monunlock)(void);
+static int (*_moncom)(int,void *,void *, void *);
+
+/**************************************************************************
+ *
+ * The following macros support the default monitor lock/unlock mechanism when
+ * they point to monLock and monUnlock. If something other than the default
+ * is to be used, then simply redefine them here. Refer to the monitor
+ * app note that discusses multi-tasking access to the monitor API for more
+ * information.
+ *
+ * TFS_MONLOCK/UNLOCK:
+ * Lock/unlock for functions that access TFS flash space:
+ */
+#define TFS_MONLOCK monLock
+#define TFS_MONUNLOCK monUnlock
+
+/* ENV_MONLOCK/UNLOCK:
+ * Lock/unlock for functions that access monitor shell variables:
+ */
+#define ENV_MONLOCK monLock
+#define ENV_MONUNLOCK monUnlock
+
+/* CONSOLE_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that deal with console output.
+ */
+#define CONSOLE_MONLOCK monLock
+#define CONSOLE_MONUNLOCK monUnlock
+
+/* HEAP_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that deal with the heap.
+ */
+#define HEAP_MONLOCK monLock
+#define HEAP_MONUNLOCK monUnlock
+
+/* BLOCKING_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that block waiting for
+ * console input.
+ */
+#define BLOCKING_MONLOCK monLock
+#define BLOCKING_MONUNLOCK monUnlock
+
+/* GENERIC_MONLOCK/UNLOCK:
+ * Lock/unlock for all functions not covered by the above macros.
+ */
+#define GENERIC_MONLOCK monLock
+#define GENERIC_MONUNLOCK monUnlock
+
+/**************************************************************************
+ *
+ * monConnect():
+ * This must be the first call by the application code to talk to the
+ * monitor. It is expecting three incoming function pointers:
+ *
+ * mon: Points to the monitor's _moncom function;
+ * This is a "well-known" address because the monitor and
+ * application code (two separately linked binaries) must
+ * know it.
+ * lock: Points to a function in the application code that will be
+ * used by the monitor as a lock-out function (some kind of
+ * semaphore in the application).
+ * unlock: Points to a function in the application code that will be
+ * used by the monitor as an un-lock-out function (undo whatever
+ * lock-out mechanism was done by lock).
+ */
+int
+monConnect(int (*mon)(int,void *,void *,void *),
+ void (*lock)(void), void (*unlock)(void))
+{
+ int rc = 0;
+
+ /* Assign incoming lock and unlock functions... */
+ _monlock = lock;
+ _monunlock = unlock;
+
+ /* If the mon pointer is non-zero, then make the mon_ connections... */
+ if (mon) {
+
+ _moncom = mon;
+
+ /* Make the connections between "mon_" functions that are */
+ /* symbolically accessible by the application and the corresponding */
+ /* functions that exists in the monitor. */
+ rc += _moncom(GETMONFUNC_PUTCHAR,&_rputchar,0,0);
+ rc += _moncom(GETMONFUNC_GETCHAR,&_getchar,0,0);
+ rc += _moncom(GETMONFUNC_GOTACHAR,&_gotachar,0,0);
+ rc += _moncom(GETMONFUNC_GETBYTES,&_getbytes,0,0);
+ rc += _moncom(GETMONFUNC_PRINTF,&_printf,0,0);
+ rc += _moncom(GETMONFUNC_CPRINTF,&_cprintf,0,0);
+ rc += _moncom(GETMONFUNC_SPRINTF,&_sprintf,0,0);
+ rc += _moncom(GETMONFUNC_RESTART,&_monrestart,0,0);
+ rc += _moncom(GETMONFUNC_GETENV,&_getenv,0,0);
+ rc += _moncom(GETMONFUNC_SETENV,&_setenv,0,0);
+ rc += _moncom(GETMONFUNC_TFSINIT,&_tfsinit,0,0);
+ rc += _moncom(GETMONFUNC_TFSADD,&_tfsadd,0,0);
+ rc += _moncom(GETMONFUNC_TFSUNLINK,&_tfsunlink,0,0);
+ rc += _moncom(GETMONFUNC_TFSRUN,&_tfsrun,0,0);
+ rc += _moncom(GETMONFUNC_TFSNEXT,&_tfsnext,0,0);
+ rc += _moncom(GETMONFUNC_TFSSTAT,&_tfsstat,0,0);
+ rc += _moncom(GETMONFUNC_TFSREAD,&_tfsread,0,0);
+ rc += _moncom(GETMONFUNC_TFSWRITE,&_tfswrite,0,0);
+ rc += _moncom(GETMONFUNC_TFSOPEN,&_tfsopen,0,0);
+ rc += _moncom(GETMONFUNC_TFSCLOSE,&_tfsclose,0,0);
+ rc += _moncom(GETMONFUNC_TFSSEEK,&_tfsseek,0,0);
+ rc += _moncom(GETMONFUNC_TFSGETLINE,&_tfsgetline,0,0);
+ rc += _moncom(GETMONFUNC_TFSIPMOD,&_tfsipmod,0,0);
+ rc += _moncom(GETMONFUNC_TFSCTRL,&_tfsctrl,0,0);
+ rc += _moncom(GETMONFUNC_ADDCOMMAND,&_addcommand,0,0);
+ rc += _moncom(GETMONFUNC_DOCOMMAND,&_docommand,0,0);
+ rc += _moncom(GETMONFUNC_GETARGV,&_getargv,0,0);
+ rc += _moncom(GETMONFUNC_CRC16,&_xcrc16,0,0);
+ rc += _moncom(GETMONFUNC_CRC32,&_crc32,0,0);
+ rc += _moncom(GETMONFUNC_INTSOFF,&_intsoff,0,0);
+ rc += _moncom(GETMONFUNC_INTSRESTORE,&_intsrestore,0,0);
+ rc += _moncom(GETMONFUNC_APPEXIT,&_appexit,0,0);
+ rc += _moncom(GETMONFUNC_MALLOC,&_malloc,0,0);
+ rc += _moncom(GETMONFUNC_FREE,&_free,0,0);
+ rc += _moncom(GETMONFUNC_GETLINE,&_getline,0,0);
+ rc += _moncom(GETMONFUNC_TFSFSTAT,&_tfsfstat,0,0);
+ rc += _moncom(GETMONFUNC_TFSEOF,&_tfseof,0,0);
+ rc += _moncom(GETMONFUNC_DECOMPRESS,&_decompress,0,0);
+ rc += _moncom(GETMONFUNC_TFSTRUNCATE,&_tfstruncate,0,0);
+ rc += _moncom(GETMONFUNC_HEAPXTEND,&_heapextend,0,0);
+ rc += _moncom(GETMONFUNC_PROFILER,&_profiler,0,0);
+ rc += _moncom(GETMONFUNC_TFSLINK,&_tfslink,0,0);
+ rc += _moncom(GETMONFUNC_BBC,&_bbc,0,0);
+ rc += _moncom(GETMONFUNC_MEMTRACE,&_memtrace,0,0);
+ rc += _moncom(GETMONFUNC_TFSTELL,&_tfstell,0,0);
+ rc += _moncom(GETMONFUNC_VERSION,&_version,0,0);
+ rc += _moncom(GETMONFUNC_WARMSTART,&_appwarmstart,0,0);
+ rc += _moncom(GETMONFUNC_PCICFGREAD,&_pcicfgread,0,0);
+ rc += _moncom(GETMONFUNC_PCICFGWRITE,&_pcicfgwrite,0,0);
+ rc += _moncom(GETMONFUNC_PCICONTROL,&_pcictrl,0,0);
+ rc += _moncom(GETMONFUNC_I2CREAD,&_i2cread,0,0);
+ rc += _moncom(GETMONFUNC_I2CWRITE,&_i2cwrite,0,0);
+ rc += _moncom(GETMONFUNC_I2CCONTROL,&_i2cctrl,0,0);
+ rc += _moncom(GETMONFUNC_MONDELAY,&_mondelay,0,0);
+ rc += _moncom(GETMONFUNC_GETENVP,&_getenvp,0,0);
+ rc += _moncom(GETMONFUNC_REALLOC,&_realloc,0,0);
+ rc += _moncom(GETMONFUNC_SENDENETPKT,&_sendenet,0,0);
+ rc += _moncom(GETMONFUNC_RECVENETPKT,&_recvenet,0,0);
+ rc += _moncom(GETMONFUNC_GETSYM,&_getsym,0,0);
+ rc += _moncom(GETMONFUNC_PRINTPKT,&_printpkt,0,0);
+ rc += _moncom(GETMONFUNC_FLASHWRITE,&_flashwrite,0,0);
+ rc += _moncom(GETMONFUNC_FLASHERASE,&_flasherase,0,0);
+ rc += _moncom(GETMONFUNC_FLASHINFO,&_flashinfo,0,0);
+ rc += _moncom(GETMONFUNC_ASSIGNHDLR,&_assign_handler,0,0);
+ rc += _moncom(GETMONFUNC_WATCHDOG,&_watchdog,0,0);
+ rc += _moncom(GETMONFUNC_PRINTMEM,&_printmem,0,0);
+ rc += _moncom(GETMONFUNC_PORTCMD,&_portcmd,0,0);
+ rc += _moncom(GETMONFUNC_TIMEOFDAY,&_timeofday,0,0);
+ rc += _moncom(GETMONFUNC_TIMER,&_montimer,0,0);
+ rc += _moncom(GETMONFUNC_FLASHOVRRD,&_flashoverride,0,0);
+ }
+ return(rc);
+}
+
+/* ignorelock:
+ * Used as a back-door to disable the monLock()/monUnlock() stuff.
+ * This is useful if the application CLI falls through to the monitor's
+ * CLI and you are using the "call" command in the monitor to execute some
+ * function that has a mon_xxx function in it. In this case, the fact that
+ * the application has fallen through to the monitor means that the lock
+ * is already active, so when the function tries to call some other mon_xxx
+ * function it won't be able to because of the lock already being set.
+ *
+ * With these functions in the application space, the user can do the
+ * following:
+ * call %DisableLock
+ * call %Func_with_monXXX_in_it
+ * call %EnableLock
+ *
+ * Note that this is NOT to be used by application code, it is simply a
+ * back-door mechanism to allow "call" from the CLI to invoke functions
+ * that have mon_XXX functionality in them.
+ */
+static int ignorelock = 0;
+
+void
+DisableMonLock(void)
+{
+ ignorelock = 2;
+}
+
+void
+EnableMonLock(void)
+{
+ ignorelock = 0;
+}
+
+/* monLock() & monUnlock():
+ * Used by all of the wrapper functions below this point to call
+ * the function pointed to by _monlock & _monunlock function pointers
+ * (if set).
+ * These functions must test both the function pointer and the state
+ * of the ignorelock variable. The function DisableMonLock() sets the
+ * ignorelock variable to 2 because it is being executed through "call"
+ * which means that the lock is active.
+ */
+static void
+monLock()
+{
+ if (_monlock) {
+ switch(ignorelock) {
+ case 1:
+ break;
+ case 2:
+ ignorelock--;
+ break;
+ default:
+ _monlock();
+ break;
+ }
+ }
+}
+
+static void
+monUnlock()
+{
+ if (_monunlock) {
+ switch(ignorelock) {
+ case 1:
+ break;
+ case 2:
+ ignorelock--;
+ default:
+ _monunlock();
+ break;
+ }
+ }
+}
+
+int
+mon_com(int cmd, void *arg1, void *arg2, void *arg3)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _moncom(cmd,arg1,arg2,arg3);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_putchar(char c)
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _rputchar(c);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_getchar(void)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getchar();
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_gotachar(void)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _gotachar();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_getbytes(char *buf,int cnt,int block)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getbytes(buf,cnt,block);
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt, *buf;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_restart(int val)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _monrestart(val);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getenvp(void)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getenvp();
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getenv(char *name)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getenv(name);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_setenv(char *name,char *val)
+{
+ int ret;
+
+ ENV_MONLOCK();
+ ret = _setenv(name,val);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getsym(char *name,char *buf, int bufsize)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getsym(name,buf,bufsize);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsinit(void)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsinit();
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsadd(char *name, char *info, char *flags, unsigned char *src, int size)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsadd(name,info,flags,src,size);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfslink(char *src, char *target)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfslink(src,target);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsunlink(char *name)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsunlink(name);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsrun(char **name,int verbose)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsrun(name,verbose);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+struct tfshdr *
+mon_tfsnext(struct tfshdr *fp)
+{
+ struct tfshdr *ret;
+
+ TFS_MONLOCK();
+ ret = _tfsnext(fp);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfstruncate(int tfd, long len)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfstruncate(tfd,len);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfseof(int tfd)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfseof(tfd);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsfstat(char *name, struct tfshdr *fp)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsfstat(name,fp);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+struct tfshdr *
+mon_tfsstat(char *name)
+{
+ struct tfshdr *ret;
+
+ TFS_MONLOCK();
+ ret = _tfsstat(name);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsread(int fd, char *buf, int cnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsread(fd,buf,cnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfswrite(int fd, char *buf, int cnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfswrite(fd,buf,cnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsopen(char *file,long flagmode,char *buf)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsopen(file,flagmode,buf);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsclose(int fd,char *info)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsclose(fd,info);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsseek(int fd, int offset, int whence)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsseek(fd,offset,whence);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsgetline(int fd,char *bp,int max)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsgetline(fd,bp,max);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsipmod(char *name,char *buf,int offset,int size)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsipmod(name,buf,offset,size);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+long
+mon_tfsctrl(int rqst,long arg1,long arg2)
+{
+ long ret;
+
+ TFS_MONLOCK();
+ ret = _tfsctrl(rqst,arg1,arg2);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+long
+mon_tfstell(int fd)
+{
+ long ret;
+
+ TFS_MONLOCK();
+ ret = _tfstell(fd);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_addcommand(struct monCommand *cmdlist, char *cmdlvl)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _addcommand(cmdlist,cmdlvl);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_docommand(char *cmdline,int verbose)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _docommand(cmdline,verbose);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_getargv(int *argc,char ***argv)
+{
+ GENERIC_MONLOCK();
+ _getargv(argc,argv);
+ GENERIC_MONUNLOCK();
+}
+
+unsigned short
+mon_xcrc16(char *buf,long nbytes)
+{
+ unsigned short ret;
+
+ GENERIC_MONLOCK();
+ ret = _xcrc16((unsigned char *)buf,nbytes);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+unsigned long
+mon_intsoff(void)
+{
+ unsigned long ret;
+
+ GENERIC_MONLOCK();
+ ret = _intsoff();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_intsrestore(unsigned long msr)
+{
+ GENERIC_MONLOCK();
+ _intsrestore(msr);
+ GENERIC_MONUNLOCK();
+}
+
+void
+mon_appexit(int val)
+{
+ GENERIC_MONLOCK();
+ _appexit(val);
+ GENERIC_MONUNLOCK();
+}
+
+#ifdef MALLOC_DEBUG
+char *
+mon_malloc(int size,char *fname,int fline)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _malloc(size,fname,fline);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_realloc(char *buf, int size, char *fname, int fline)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _realloc(buf,size, fname, fline);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+#else
+char *
+mon_malloc(int size)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _malloc(size);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_realloc(char *buf, int size)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _realloc(buf,size);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+#endif
+
+void
+mon_free(char *cp)
+{
+ HEAP_MONLOCK();
+ _free(cp);
+ HEAP_MONUNLOCK();
+}
+
+int
+mon_getline(char *buf,int max,int ledit)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getline(buf,max,ledit);
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_decompress(char *src,int srcsize,char *dest)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _decompress(src,srcsize,dest);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_heapextend(char *base,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _heapextend(base,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_bbc(char *filename, int lineno)
+{
+ _bbc(filename, lineno);
+}
+
+void
+mon_profiler(void *pdata)
+{
+ _profiler(pdata);
+}
+
+void
+mon_memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ _memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+}
+
+char *
+mon_version(void)
+{
+ char *ret;
+
+ GENERIC_MONLOCK();
+ ret = _version();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_warmstart(unsigned long mask)
+{
+ GENERIC_MONLOCK();
+ _appwarmstart(mask);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg,
+ unsigned long val)
+{
+ int retval;
+
+ GENERIC_MONLOCK();
+ retval = _pcicfgwrite(interface,bus,dev,func,reg,val);
+ GENERIC_MONUNLOCK();
+ return(retval);
+}
+
+unsigned long
+mon_pcicfgread(int interface,int bus,int dev, int func,int reg)
+{
+ unsigned long retval;
+
+ GENERIC_MONLOCK();
+ retval = _pcicfgread(interface,bus,dev,func,reg);
+ GENERIC_MONUNLOCK();
+ return(retval);
+}
+
+unsigned long
+mon_pcictrl(int interface, int cmd, unsigned long arg1, unsigned long arg2)
+{
+ unsigned long val;
+
+ GENERIC_MONLOCK();
+ val = _pcictrl(interface,cmd,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+unsigned long
+mon_i2cctrl(int interface, int cmd, unsigned long arg1, unsigned long arg2)
+{
+ unsigned long val;
+
+ GENERIC_MONLOCK();
+ val = _i2cctrl(interface,cmd,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+int
+mon_i2cwrite(int interface, int bigaddr, unsigned char *data, int len)
+{
+ int val;
+
+ GENERIC_MONLOCK();
+ val = _i2cwrite(interface,bigaddr,data,len);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+int
+mon_i2cread(int interface, int bigaddr, unsigned char *data, int len)
+{
+ int val;
+
+ GENERIC_MONLOCK();
+ val = _i2cread(interface,bigaddr,data,len);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+void
+mon_delay(long msec)
+{
+ GENERIC_MONLOCK();
+ _mondelay(msec);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_timer(int cmd, void *arg)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _montimer(cmd, arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_sendenetpkt(char *pkt,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _sendenet(pkt,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_recvenetpkt(char *pkt,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _recvenet(pkt,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_printpkt(char *buf,int size, int incoming)
+{
+ GENERIC_MONLOCK();
+ _printpkt(buf,size,incoming);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_flashoverride(void *flashinfo,int get,int bank)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashoverride(flashinfo,get,bank);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flashwrite(char *dest,char *src,int bytecnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashwrite(dest,src,bytecnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flasherase(int snum)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flasherase(snum);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flashinfo(int snum, int *size, char **base)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashinfo(snum,size,base);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+unsigned long
+mon_assignhandler(long hnum, unsigned long arg1, unsigned long arg2)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _assign_handler(hnum,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_watchdog(void)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _watchdog();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_printmem(char *mem, int size, int ascii)
+{
+ GENERIC_MONLOCK();
+ _printmem(mem,size,ascii);
+ GENERIC_MONUNLOCK();
+}
+
+long
+mon_portcmd(int cmd, void *arg)
+{
+ long ret;
+
+ GENERIC_MONLOCK();
+ ret = _portcmd(cmd,arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_timeofday(int cmd, void *arg)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _timeofday(cmd,arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
diff --git a/apps/common/monlib.h b/apps/common/monlib.h
new file mode 100644
index 0000000..10e37f4
--- /dev/null
+++ b/apps/common/monlib.h
@@ -0,0 +1,239 @@
+/* monlib.h:
+ * This header file is used by both the monitor and the application that
+ * may reside on top of the monitor.
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Note1: the majority of this code was edited with 4-space tabs.
+ * Note2: as more and more contributions are accepted, the term "author"
+ * is becoming a mis-representation of credit.
+ *
+ * Original author: Ed Sutter
+ * Email: esutter@lucent.com
+ * Phone: 908-582-2351
+ */
+#ifndef _MONLIB_H_
+#define _MONLIB_H_
+
+#include "tfs.h"
+#include "cli.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern int monConnect(int (*monptr)(int,void *,void *,void *),
+ void (*lock)(void),void (*unlock)(void));
+extern void mon_getargv(int *argc,char ***argv);
+extern void mon_intsrestore(unsigned long oldval);
+extern void mon_appexit(int exit_value);
+extern void mon_free(char *buffer);
+extern void mon_profiler(void *pdata);
+extern void mon_bbc(char *filename, int linenum);
+extern void mon_warmstart(unsigned long mask);
+extern void mon_delay(long msec);
+extern void mon_printpkt(char *buf, int size, int incoming);
+extern void mon_printmem(char *mem, int size, int ascii);
+
+
+extern int mon_com(int cmd,void *arg1,void *arg2,void *arg3);
+extern int mon_timer(int cmd, void * arg);
+extern int mon_setenv(char *varname,char *value);
+extern int mon_putchar(char c);
+extern int mon_getchar(void);
+extern int mon_gotachar(void);
+extern int mon_getbytes(char *buf,int count,int block);
+extern int mon_restart(int restart_value);
+extern int mon_tfsinit(void);
+extern int mon_tfsunlink(char *filename);
+extern int mon_tfslink(char *source, char *target);
+extern int mon_tfsrun(char **arglist,int verbosity);
+extern int mon_tfsfstat(char *filename,struct tfshdr *tfp);
+extern int mon_tfseof(int file_descriptor);
+extern int mon_tfstruncate(int file_descriptor,long length);
+extern int mon_tfsread(int file_descriptor,char *buffer,int size);
+extern int mon_tfswrite(int file_descriptor,char *buffer,int size);
+extern int mon_tfsopen(char *filename,long mode,char *buffer);
+extern int mon_tfsclose(int file_descriptor,char *info);
+extern int mon_tfsseek(int file_descriptor,int offset,int whence);
+extern int mon_tfsgetline(int file_descriptor,char *buffer,int bufsize);
+extern int mon_tfsipmod(char *name,char *buffer,int offset,int size);
+extern int mon_addcommand(struct monCommand *command_list,char *);
+extern int mon_docommand(char *cmdline,int verbosity);
+extern int mon_getline(char *buffer,int max,int ledit);
+extern int mon_decompress(char *src,int srcsize,char *dest);
+extern int mon_heapextend(char *base,int size);
+extern int mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg,
+ unsigned long val);
+extern int mon_tfsadd(char *filename, char *info, char *flags,
+ unsigned char *src, int size);
+extern int mon_i2cwrite(int interface, int bigaddr, unsigned char *data,
+ int len);
+extern int mon_i2cread(int interface, int bigaddr, unsigned char *data,
+ int len);
+extern int mon_sendenetpkt(char *pkt, int len);
+extern int mon_recvenetpkt(char *pkt, int len);
+extern int mon_flashoverride(void *flashinfo, int get, int bank);
+extern int mon_flasherase(int snum);
+extern int mon_flashwrite(char *dest,char *src, int bytecnt);
+extern int mon_flashinfo(int snum,int *size, char **base);
+extern int mon_watchdog(void);
+extern int mon_timeofday(int cmd, void *arg);
+
+extern char *mon_getsym(char *symname, char *buf, int bufsize);
+extern char *mon_getenv(char *varname);
+extern char *mon_getenvp(void);
+extern char *mon_version(void);
+#ifdef MALLOC_DEBUG
+extern char *mon_malloc(int size,char *file, int line);
+extern char *mon_realloc(char *buf,int size,char *file, int line);
+#else
+extern char *mon_malloc(int size);
+extern char *mon_realloc(char *buf,int size);
+#endif
+
+extern long mon_tfsctrl(int command,long arg1,long arg2);
+extern long mon_tfstell(int file_descriptor);
+extern long mon_portcmd(int cmd, void *arg);
+
+extern unsigned short mon_xcrc16(char *buffer,long length);
+
+extern unsigned long mon_intsoff(void);
+
+extern unsigned long mon_pcicfgread(int interface,int bus,int dev,
+ int func,int reg);
+
+extern unsigned long mon_pcictrl(int interface, int cmd,
+ unsigned long arg1, unsigned long arg2);
+
+extern unsigned long mon_i2cctrl(int interface, int cmd,
+ unsigned long arg1, unsigned long arg2);
+
+extern unsigned long mon_assignhandler(long hnum,
+ unsigned long arg1,unsigned long arg2);
+
+extern struct tfshdr *mon_tfsnext(struct tfshdr *tfp);
+extern struct tfshdr *mon_tfsstat(char *filename);
+
+#if SHOWVARARGS
+extern void mon_memtrace(char *fmt, ...);
+extern int mon_printf(char *fmt, ...);
+extern int mon_cprintf(char *fmt, ...);
+extern int mon_sprintf(char *,char *fmt, ...);
+#else
+extern void mon_memtrace();
+extern int mon_printf();
+extern int mon_cprintf();
+extern int mon_sprintf();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* defines used by monConnect():
+ */
+#define GETMONFUNC_PUTCHAR 1
+#define GETMONFUNC_GETCHAR 2
+#define GETMONFUNC_GOTACHAR 3
+#define GETMONFUNC_GETBYTES 4
+#define GETMONFUNC_PRINTF 5
+#define GETMONFUNC_CPRINTF 6
+#define GETMONFUNC_SPRINTF 7
+#define GETMONFUNC_RESTART 8
+#define GETMONFUNC_GETENV 9
+#define GETMONFUNC_SETENV 10
+#define GETMONFUNC_TFSINIT 11
+#define GETMONFUNC_TFSADD 12
+#define GETMONFUNC_TFSUNLINK 13
+#define GETMONFUNC_TFSRUN 14
+#define GETMONFUNC_TFSNEXT 15
+#define GETMONFUNC_TFSSTAT 16
+#define GETMONFUNC_TFSREAD 17
+#define GETMONFUNC_TFSWRITE 18
+#define GETMONFUNC_TFSOPEN 19
+#define GETMONFUNC_TFSCLOSE 20
+#define GETMONFUNC_TFSSEEK 21
+#define GETMONFUNC_TFSGETLINE 22
+#define GETMONFUNC_TFSIPMOD 23
+#define GETMONFUNC_TFSCTRL 24
+#define GETMONFUNC_ADDCOMMAND 25
+#define GETMONFUNC_DOCOMMAND 26
+#define GETMONFUNC_GETARGV 27
+#define GETMONFUNC_CRC16 28
+#define GETMONFUNC_CRC32 29
+#define GETMONFUNC_PIOGET 30 /* NA (removed as of 1.0) */
+#define GETMONFUNC_PIOSET 31 /* NA (removed as of 1.0) */
+#define GETMONFUNC_PIOCLR 32 /* NA (removed as of 1.0) */
+#define GETMONFUNC_INTSOFF 33
+#define GETMONFUNC_INTSRESTORE 34
+#define GETMONFUNC_APPEXIT 35
+#define GETMONFUNC_MALLOC 36
+#define GETMONFUNC_FREE 37
+#define GETMONFUNC_GETLINE 38
+#define GETMONFUNC_TFSFSTAT 39
+#define GETMONFUNC_TFSEOF 40
+#define GETMONFUNC_DECOMPRESS 41
+#define GETMONFUNC_TFSTRUNCATE 42
+#define GETMONFUNC_HEAPXTEND 43
+#define GETMONFUNC_PROFILER 44
+#define GETMONFUNC_TFSLINK 45
+#define GETMONFUNC_BBC 46
+#define GETMONFUNC_MEMTRACE 47
+#define GETMONFUNC_TFSTELL 48
+#define GETMONFUNC_VERSION 49
+#define GETMONFUNC_WARMSTART 50
+#define GETMONFUNC_PCICFGREAD 51
+#define GETMONFUNC_PCICFGWRITE 52
+#define GETMONFUNC_PCICONTROL 53
+#define GETMONFUNC_I2CREAD 54
+#define GETMONFUNC_I2CWRITE 55
+#define GETMONFUNC_I2CCONTROL 56
+#define GETMONFUNC_MONDELAY 57
+#define GETMONFUNC_GETENVP 58
+#define GETMONFUNC_REALLOC 59
+#define GETMONFUNC_SENDENETPKT 60
+#define GETMONFUNC_RECVENETPKT 61
+#define GETMONFUNC_GETSYM 62
+#define GETMONFUNC_PRINTPKT 63
+#define GETMONFUNC_FLASHWRITE 64
+#define GETMONFUNC_FLASHERASE 65
+#define GETMONFUNC_FLASHINFO 66
+#define GETMONFUNC_ASSIGNHDLR 67
+#define GETMONFUNC_WATCHDOG 68
+#define GETMONFUNC_PRINTMEM 69
+#define GETMONFUNC_PORTCMD 70
+#define GETMONFUNC_TIMEOFDAY 71
+#define GETMONFUNC_TIMER 72
+#define GETMONFUNC_FLASHOVRRD 73
+
+#define CACHEFTYPE_DFLUSH 200
+#define CACHEFTYPE_IINVALIDATE 201
+
+#define CHARFUNC_PUTCHAR 300
+#define CHARFUNC_GETCHAR 301
+#define CHARFUNC_GOTACHAR 302
+#define CHARFUNC_RAWMODEON 303
+#define CHARFUNC_RAWMODEOFF 304
+
+#define ASSIGNFUNC_GETUSERLEVEL 400
+
+
+/* Defines used by mon_warmstart():
+ */
+#define WARMSTART_IOINIT 0x00000001
+#define WARMSTART_BSSINIT 0x00000002
+#define WARMSTART_RUNMONRC 0x00000004
+#define WARMSTART_MONHEADER 0x00000008
+#define WARMSTART_TFSAUTOBOOT 0x00000010
+#define WARMSTART_BOARDINFO 0x00000020
+#define WARMSTART_ALL 0xffffffff
+#endif
diff --git a/apps/common/tfs.h b/apps/common/tfs.h
new file mode 100644
index 0000000..f83d518
--- /dev/null
+++ b/apps/common/tfs.h
@@ -0,0 +1,187 @@
+/* tfs.h:
+ * Header file for TFS transactions, used by both application and monitor.
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Note1: the majority of this code was edited with 4-space tabs.
+ * Note2: as more and more contributions are accepted, the term "author"
+ * is becoming a mis-representation of credit.
+ *
+ * Original author: Ed Sutter
+ * Email: esutter@lucent.com
+ * Phone: 908-582-2351
+ */
+#ifndef _tfs_h
+#define _tfs_h
+
+#define TFSINFOSIZE 23 /* Max size of info string (mod4-1). */
+
+#ifndef TFSNAMESIZE /* This specifies the maximum size of a file */
+#define TFSNAMESIZE 23 /* name that can be used in TFS. */
+#endif /* This MUST be some value mod4 - 1. */
+
+#ifndef TFS_CHANGELOG_FILE /* Information used for change-log */
+#define TFS_CHANGELOG_SIZE 0 /* facility within tfs. */
+#define TFS_CHANGELOG_FILE ".tfschlog"
+#endif
+
+#ifndef SYMFILE /* This specifies the default filename */
+#define SYMFILE "symtbl" /* used by the monitor for the symbol */
+#endif /* table. */
+
+#define MINUSRLEVEL 0 /* Minimum user level supported. */
+#define MAXUSRLEVEL 3 /* Maximum user level supported. */
+
+#ifndef TFS_RESERVED
+#define TFS_RESERVED 4 /* Number of "reserved" entries (ulong) */
+#endif /* in the TFS header. */
+
+
+/* Flags: */
+#define TFS_EXEC 0x00000001 /* 'e': Executable script. */
+#define TFS_BRUN 0x00000002 /* 'b': To be executed at boot. */
+#define TFS_QRYBRUN 0x00000004 /* 'B': To be executed at boot if */
+ /* query passes. */
+#define TFS_SYMLINK 0x00000008 /* 'l': Symbolic link file. */
+#define TFS_EBIN 0x00000010 /* 'E': Executable binary (coff/elf/a.out). */
+#define TFS_CPRS 0x00000040 /* 'c': File is compressed. */
+#define TFS_IPMOD 0x00000080 /* 'i': File is in-place modifiable. */
+#define TFS_UNREAD 0x00000100 /* 'u': File is not even readable if the */
+ /* user-level requirement is not met; */
+ /* else, it is read-only. */
+#define TFS_ULVLMSK 0x00000600 /* User level mask defines 4 access levels: */
+#define TFS_ULVL0 0x00000000 /* '0' level 0 */
+#define TFS_ULVL1 0x00000200 /* '1' level 1 */
+#define TFS_ULVL2 0x00000400 /* '2' level 2 */
+#define TFS_ULVL3 0x00000600 /* '3' level 3 */
+#define TFS_NSTALE 0x00000800 /* File is NOT stale, invisible to user.
+ * When this bit is clear, the file is
+ * considered stale (see notes in tfsadd()).
+ * See notes in tfsclose() for this.
+ */
+#define TFS_ACTIVE 0x00008000 /* Used to indicate that file is not deleted. */
+
+#define TFS_ULVLMAX TFS_ULVL3
+#define TFS_USRLVL(f) ((f->flags & TFS_ULVLMSK) >> 9)
+
+/* Open modes */
+#define TFS_RDONLY 0x00010000 /* File is opened for reading. */
+#define TFS_CREATE 0x00020000 /* File is to be created. Error if file */
+ /* with the same name already exists. */
+#define TFS_APPEND 0x00040000 /* Append to existing file. If OR'ed */
+ /* with TFS_CREATE, then create if */
+ /* necessary. */
+#define TFS_ALLFFS 0x00080000 /* File is created with all FFs. */
+#define TFS_CREATERM 0x00100000 /* File is to be created. If file with */
+ /* same name already exists, then allow */
+ /* tfsadd() to remove it if necessary. */
+
+/* The function tfsrunrc() will search through the current file set and */
+/* if the file defined by TFS_RCFILE exists, it will be executed. */
+/* If this file exists, it will NOT be run by tfsrunboot(). */
+#define TFS_RCFILE "monrc"
+
+/* Requests that can be made to tfsctrl(): */
+#define TFS_ERRMSG 1
+#define TFS_MEMUSE 2
+#define TFS_MEMDEAD 3
+#define TFS_DEFRAG 4
+#define TFS_TELL 5
+#define TFS_UNOPEN 7
+#define TFS_FATOB 8
+#define TFS_FBTOA 9
+#define TFS_MEMAVAIL 10
+#define TFS_TIMEFUNCS 11
+#define TFS_DOCOMMAND 12
+#define TFS_INITDEV 13
+#define TFS_CHECKDEV 14
+#define TFS_DEFRAGDEV 15
+#define TFS_DEFRAGOFF 16
+#define TFS_DEFRAGON 17
+#define TFS_HEADROOM 18
+#define TFS_FCOUNT 19
+
+/* struct tfshdr:
+ * It is in FLASH as part of the file system to record the attributes of
+ * the file at the time of creation.
+ */
+struct tfshdr {
+ unsigned short hdrsize; /* Size of this header. */
+ unsigned short hdrvrsn; /* Header version #. */
+ long filsize; /* Size of the file. */
+ long flags; /* Flags describing the file. */
+ unsigned long filcrc; /* 32 bit CRC of file. */
+ unsigned long hdrcrc; /* 32 bit CRC of the header. */
+ unsigned long modtime; /* Time when file was last modified. */
+ struct tfshdr *next; /* Pointer to next file in list. */
+ char name[TFSNAMESIZE+1]; /* Name of file. */
+ char info[TFSINFOSIZE+1]; /* Miscellaneous info field. */
+#if TFS_RESERVED
+ unsigned long rsvd[TFS_RESERVED];
+#endif
+};
+
+#define TFSHDRSIZ sizeof(struct tfshdr)
+
+/* TFS error returns. */
+#define TFS_OKAY 0
+#define TFSERR_NOFILE -1
+#define TFSERR_NOSLOT -2
+#define TFSERR_EOF -3
+#define TFSERR_BADARG -4
+#define TFSERR_NOTEXEC -5
+#define TFSERR_BADCRC -6
+#define TFSERR_FILEEXISTS -7
+#define TFSERR_FLASHFAILURE -8
+#define TFSERR_WRITEMAX -9
+#define TFSERR_RDONLY -10
+#define TFSERR_BADFD -11
+#define TFSERR_BADHDR -12
+#define TFSERR_CORRUPT -13
+#define TFSERR_MEMFAIL -14
+#define TFSERR_NOTIPMOD -16
+#define TFSERR_MUTEXFAILURE -17
+#define TFSERR_FLASHFULL -18
+#define TFSERR_USERDENIED -19
+#define TFSERR_NAMETOOBIG -20
+#define TFSERR_FILEINUSE -21
+#define TFSERR_NOTCPRS -22
+#define TFSERR_NOTAVAILABLE -23
+#define TFSERR_BADFLAG -24
+#define TFSERR_CLEANOFF -25
+#define TFSERR_FLAKEYSOURCE -26
+#define TFSERR_BADEXTENSION -27
+#define TFSERR_MIN -100
+
+/* TFS seek options. */
+#define TFS_BEGIN 1
+#define TFS_CURRENT 2
+#define TFS_END 3
+
+/* Macros: */
+#define TFS_DELETED(fp) (!((fp)->flags & TFS_ACTIVE))
+#define TFS_FILEEXISTS(fp) ((fp)->flags & TFS_ACTIVE)
+#define TFS_ISCPRS(fp) ((fp)->flags & TFS_CPRS)
+#define TFS_ISEXEC(fp) ((fp)->flags & TFS_EXEC)
+#define TFS_ISBOOT(fp) ((fp)->flags & TFS_BRUN)
+#define TFS_ISLINK(fp) ((fp)->flags & TFS_SYMLINK)
+#define TFS_STALE(fp) (!((fp)->flags & TFS_NSTALE))
+#define TFS_FLAGS(fp) ((fp)->flags)
+#define TFS_NAME(fp) ((fp)->name)
+#define TFS_SIZE(fp) ((fp)->filsize)
+#define TFS_TIME(fp) ((fp)->modtime)
+#define TFS_INFO(fp) ((fp)->info)
+#define TFS_NEXT(fp) ((fp)->next)
+#define TFS_CRC(fp) ((fp)->filcrc)
+#define TFS_ENTRY(fp) ((fp)->entry)
+#define TFS_BASE(fp) ((char *)(fp)+(fp)->hdrsize)
+
+typedef struct tfshdr TFILE;
+#endif
diff --git a/apps/common/timer.h b/apps/common/timer.h
new file mode 100755
index 0000000..e48ba52
--- /dev/null
+++ b/apps/common/timer.h
@@ -0,0 +1,46 @@
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+struct elapsed_tmr {
+ unsigned long start; // Start value of elapsed timeout.
+ unsigned long tmrval; // Running timer value
+ // (used by elapsed timeout)
+ unsigned long currenttmrval; // Current timer value
+ // (not used by elapsed timeout)
+ unsigned long tpm; // Ticks per millisecond
+
+ unsigned long elapsed_low;
+ unsigned long elapsed_high;
+
+ unsigned long timeout_low;
+ unsigned long timeout_high;
+
+ unsigned long tmrflags;
+};
+
+/* Timer flags:
+ */
+#define HWTMR_ENABLED (1 << 0)
+#define TIMEOUT_OCCURRED (1 << 1)
+
+/* Timer macros:
+ */
+#define HWRTMR_IS_ENABLED(tmr) \
+ ((tmr)->tmrflags & HWTMR_ENABLED)
+
+#define ELAPSED_TIMEOUT(tmr) \
+ ((tmr)->tmrflags & TIMEOUT_OCCURRED)
+
+/* uMon API timer commands:
+ */
+#define TIMER_START 1
+#define TIMER_ELAPSED 2
+#define TIMER_QUERY 3
+
+extern unsigned long target_timer(void);
+extern void startElapsedTimer(struct elapsed_tmr *tmr,long timeout);
+extern int msecElapsed(struct elapsed_tmr *tmr);
+extern unsigned long msecRemaining(struct elapsed_tmr *tmr);
+extern int monTimer(int cmd, void *arg);
+
+#endif
diff --git a/apps/demo/README b/apps/demo/README
new file mode 100644
index 0000000..69018dd
--- /dev/null
+++ b/apps/demo/README
@@ -0,0 +1,7 @@
+This directory contains source and makefile to build a small
+uMon-resident application that creates it's own stack area and
+also provides a few umon-ish demonstrations (particularly a
+stack trace demo).
+
+Refer to makefile for details on how to build for various CPU architectures
+and target configurations.
diff --git a/apps/demo/bashrc b/apps/demo/bashrc
new file mode 100644
index 0000000..d6f9ebe
--- /dev/null
+++ b/apps/demo/bashrc
@@ -0,0 +1,8 @@
+export PS1=uMonDemo:
+export EDITOR=vi
+export TITLE="MicroMonitor Demo Application"
+export UMONTOP=../../umon_main
+export HOME=`pwd`
+unset TERM
+. $UMONTOP/host/bin/umon_setup
+export TARGET_IP=192.168.1.110
diff --git a/apps/demo/cfg.h b/apps/demo/cfg.h
new file mode 100644
index 0000000..de4f34c
--- /dev/null
+++ b/apps/demo/cfg.h
@@ -0,0 +1 @@
+#define APPSTACKSIZE 0x2000
diff --git a/apps/demo/main.c b/apps/demo/main.c
new file mode 100644
index 0000000..d74a2d3
--- /dev/null
+++ b/apps/demo/main.c
@@ -0,0 +1,250 @@
+/*
+ * This file is a simple example of an application that could be run
+ * on top of the monitor.
+ *
+ * Cstart():
+ * The Cstart() function depends on the setting of MONCOMPTR in config.h.
+ * It demonstrates the use of monConnect and the first mon_XXX function
+ * typically called by an application, mon_getargv().
+ *
+ * main():
+ * The main() function demonstrates argument processing (thanks to
+ * the call to mon_getargv() in start()), environment variables and
+ * a simple use of TFS to dump the content of an ASCII file.
+ * Also, if the first argument is "strace_demo", then the strace_demo()
+ * function is called. Refer to strace.c for details.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "monlib.h"
+#include "tfs.h"
+#include "cfg.h"
+#include "timer.h"
+
+unsigned long AppStack[APPSTACKSIZE/4];
+
+extern void strace_demo(void);
+
+void
+hitakey(void)
+{
+ while(!mon_gotachar());
+ mon_getchar();
+}
+
+/* timer_demo():
+ * This function assumes that the underlying monitor has a relatively
+ * new uMon API hook call mon_timer().
+ * This demo shows how to do a few different elapsed timer operations
+ * using the API.
+ */
+void
+timer_demo(void)
+{
+ struct elapsed_tmr tmr;
+ unsigned long starttime, endtime;
+
+ /* Here are a few different ways (using the uMon API) to wait for
+ * three seconds...
+ *
+ * First make sure the underlying monitor has a Hardware-based
+ * timer. If it doesn't then this is worthless.
+ */
+ mon_timer(TIMER_QUERY,&tmr);
+ if ((HWRTMR_IS_ENABLED(&tmr)) == 0) {
+ mon_printf("This monitor doesn't have INCLUDE_HWTMR configured\n");
+ return;
+ }
+
+ mon_printf("Timer demo ready to start, hit a key to continue\n");
+ hitakey();
+
+ /*****************************************************************
+ *
+ * The first one, also the simplest, but least versatile is to just
+ * use mon_delay(). The mon_delay function just takes the number
+ * of milliseconds you want to wait, and uses the underlying hardware
+ * to busy wait on that duration...
+ */
+ mon_printf("1. Wait for 3 seconds...\n");
+ mon_delay(3000);
+ mon_printf("1. Done, hit a key to continue\n");
+ hitakey();
+
+ /*****************************************************************
+ *
+ * The second one, allows the user to specify the elapsed time
+ * (in milliseconds), then allows the user to poll waiting for that
+ * time to expire. Meanwhile, the application can do other things
+ * while it waits.
+ */
+ mon_printf("2. Wait for 3 seconds...\n");
+ tmr.start = 3000;
+ mon_timer(TIMER_START,&tmr);
+ while(mon_timer(TIMER_ELAPSED,&tmr) == 0) {
+ /* Do whatever you like here. */
+ }
+ mon_printf("2. Done, hit a key to continue\n");
+ hitakey();
+
+ /*****************************************************************
+ *
+ * The third method, uses the granularity of the hardware clock
+ * and the returned value of "ticks-per-millisecond". It provides
+ * the most versatility (without actually knowing the details of
+ * the hardware clock), but requires the most work. Note that we
+ * have to deal with the possiblity of 32-bit timer value wrap.
+ */
+ mon_printf("3. Wait for 3 seconds...\n");
+ mon_timer(TIMER_QUERY,&tmr);
+ starttime = tmr.currenttmrval;
+ endtime = starttime + 3000 * tmr.tpm;
+ if (endtime < starttime) {
+ do {
+ mon_timer(TIMER_QUERY,&tmr);
+ } while(tmr.currenttmrval > starttime);
+ do {
+ mon_timer(TIMER_QUERY,&tmr);
+ } while(tmr.currenttmrval < endtime);
+ }
+ else {
+ do {
+ mon_timer(TIMER_QUERY,&tmr);
+ } while((tmr.currenttmrval > starttime) &&
+ (tmr.currenttmrval < endtime));
+ }
+
+ mon_printf("3. Done, hit a key to continue\n");
+ while(!mon_gotachar());
+
+ mon_printf("Timer demo done\n");
+ mon_appexit(1);
+}
+
+/* Global variables added just to be able to use this
+ * app to demonstrate hookup with gdb...
+ */
+int argtot;
+long apprambase;
+
+int
+main(int argc,char *argv[])
+{
+ int i, tfd;
+ char line[80], *ab, *filename;
+
+ argtot = argc;
+
+ /* If argument count is greater than one, then dump out the
+ * set of CLI arguments...
+ */
+ if (argc > 1) {
+ if ((argc == 2) && (strcmp(argv[1],"strace_demo") == 0))
+ strace_demo();
+
+ if ((argc == 2) && (strcmp(argv[1],"timer") == 0))
+ timer_demo();
+
+ mon_printf("Argument list...\n");
+ for(i=0;i<argc;i++) {
+ mon_printf(" arg[%d]: %s\n",i,argv[i]);
+ if (strcmp(argv[i],"match") == 0)
+ mon_printf("got a match!\n");
+ }
+ }
+
+ /* Using the content of the shell variable APPRAMBASE, dump the
+ * memory starting at that location...
+ */
+ ab = mon_getenv("APPRAMBASE");
+ if (ab) {
+ char *addr = (char *)strtoul(ab,0,0);
+ apprambase = strtoul(ab,0,0);
+
+ mon_printf("Dumping memory at 0x%lx...\n",addr);
+ mon_printmem(addr,128,1);
+ }
+
+ filename = "monrc";
+
+ /* If the 'monrc' file exists, the assume it is ASCII and dump it
+ * line by line...
+ */
+ if (mon_tfsstat(filename)) {
+ mon_printf("Dumping content of '%s'...\n",filename);
+
+ tfd = mon_tfsopen(filename,TFS_RDONLY,0);
+ if (tfd >= 0) {
+ while(mon_tfsgetline(tfd,line,sizeof(line)))
+ mon_printf("%s",line);
+ mon_tfsclose(tfd,0);
+ }
+ else {
+ mon_printf("TFS error: %s\n",
+ (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
+ }
+ }
+ else {
+ mon_printf("File '%s' not found\n",filename);
+ }
+ return(0);
+}
+
+void
+__gccmain()
+{
+}
+
+int
+Cstart(void)
+{
+ char **argv;
+ int argc;
+
+ /* Connect the application to the monitor. This must be done
+ * prior to the application making any other attempts to use the
+ * "mon_" functions provided by the monitor.
+ */
+ monConnect((int(*)())(*(unsigned long *)MONCOMPTR),(void *)0,(void *)0);
+
+ /* When the monitor starts up an application, it stores the argument
+ * list internally. The call to mon_getargv() retrieves the arg list
+ * for use by this application...
+ */
+ mon_getargv(&argc,&argv);
+
+ /* Call main, then exit to monitor.
+ */
+ main(argc,argv);
+
+ mon_appexit(0);
+
+ /* Won't get here. */
+ return(0);
+}
+
+/* CstartAlt():
+ * Demonstrates the use of the "call -a" command in uMon.
+ * For example, if for some reason you wanted to do this...
+ * Load the application then load the symtbl file using
+ * "make TARGET_IP=1.2.3.4 sym", then issue these commands:
+ *
+ * tfs -v ld app
+ * call -a %CstartAlt one two three
+ *
+ * The "call -a" command in uMon correctly sets up the function
+ * call parameters so that the following function would see 4
+ * arguments (including arg0), with argv[1] thru argv[3] being
+ * pointers to each of the number strings (i.e. "one", "two", "three")
+ * and argv[0] being the ascii-coded-hex address of the function
+ * CstartAlt.
+ */
+int
+CstartAlt(int argc, char *argv[])
+{
+ monConnect((int(*)())(*(unsigned long *)MONCOMPTR),(void *)0,(void *)0);
+ main(argc,argv);
+ mon_appexit(0);
+ return(0);
+}
diff --git a/apps/demo/makefile b/apps/demo/makefile
new file mode 100644
index 0000000..549bf86
--- /dev/null
+++ b/apps/demo/makefile
@@ -0,0 +1,229 @@
+##########################################################################
+#
+# Basic, target/architecture independent makefile for building an
+# application that runs on its own stack.
+#
+# NOTE:
+# This is a template, and may need modification for different sites.
+#
+# The application code in main.c provides a target-independent example
+# of hooking up an application to a target running MicroMonitor.
+# Also, there is a self-induced exception branch (see strace_demo.c)
+# that can be invoked to force the application to take an exception.
+# The purpose of this is to allow the user to then use the monitor's
+# 'strace' command to see the function nesting that occurred prior to
+# the exception. This requires that the symbol table also be on-board.
+# To walk through this example, establish the site-dependent information
+# specified below, then execute "make" to build the image, and then
+# "make dld sym" to install it (and a symbol table) on the target.
+#
+# Site dependent information:
+# Adjust these values based on your system configuration.
+# ARCH:
+# Set ARCH to one of the accepted CPU architectures (i.e. MIPS
+# PPC, ARM, BLACKFIN, COLDFIRE, MICROBLAZE).
+# MONCOMPTR:
+# Set MONCOMPTR to the output of 'echo $MONCOMPTR' on your target.
+# APPRAMBASE:
+# Set APPRAMBASE to the output of 'echo $APPRAMBASE' on your target.
+# TARGET_IP:
+# Set TARGET_IP to the IP address of your target.
+#
+ARCH = ARM
+MONCOMPTR = 12345
+APPRAMBASE = 12345
+TARGET_IP =
+
+##########################################################################
+#
+# There should be no need to change anything below this point if
+# building for the csb350, csb472, csb337 or csb360...
+#
+APPNAME = app
+NM = $(TOOL_PREFIX)-nm
+AR = $(TOOL_PREFIX)-ar
+LD = $(TOOL_PREFIX)-ld
+ASM = $(TOOL_PREFIX)-as
+CC = $(TOOL_PREFIX)-gcc
+COMMON = ../common
+STRIP = $(TOOL_PREFIX)-strip
+OBJCOPY = $(TOOL_PREFIX)-objcopy
+OBJDUMP = $(TOOL_PREFIX)-objdump
+LIBGCC = `$(CC) --print-libgcc-file-name`
+LIBDIR = $(LIBGCC:/libgcc.a=)
+LIBPATH =
+COMMON_CFLAGS = -I $(COMMON) -fno-builtin -Wall
+
+ifeq ($(ARCH),MIPS)
+TOOL_PREFIX := mips-elf
+CFLAGS := $(COMMON_CFLAGS) -G 0 -march=r4600 -mips3 -mno-abicalls \
+ -fno-pic -c -g -O2 -EB -I .
+CRT0 := crt0_mips.o
+CPU := -D CPU_IS_MIPS=1
+endif
+
+ifeq ($(ARCH),PPC)
+TOOL_PREFIX := ppc-elf
+CFLAGS := $(COMMON_CFLAGS) -mno-sdata -msoft-float \
+ -c -O -g -I.
+CRT0 := crt0_ppc.o
+CPU := -D CPU_IS_PPC=1
+LIBGCC = `$(CC) --print-file-name=nof/libgcc.a`
+endif
+
+ifeq ($(ARCH),ARM)
+TOOL_PREFIX := arm-elf
+CFLAGS := $(COMMON_CFLAGS) -mcpu=arm1136j-s -fno-omit-frame-pointer \
+ -c -O -g -I.
+CRT0 := crt0_arm.o
+CPU := -D CPU_IS_ARM=1
+endif
+
+ifeq ($(ARCH),BLACKFIN)
+TOOL_PREFIX := bfin-elf
+CFLAGS := $(COMMON_CFLAGS) -mcsync-anomaly -c -O -g -I.
+CRT0 := crt0_bfin.o
+CPU := -D CPU_IS_BFIN=1
+endif
+
+ifeq ($(ARCH),MICROBLAZE)
+TOOL_PREFIX := C:/EDK/gnu/microblaze/nt/bin/mb
+LIBPATH := -L C:/xilinx/els_stuff/projects/avnet_spartan3_devkit/microblaze_0/lib
+CFLAGS := $(COMMON_CFLAGS) -mno-xl-soft-mul -c -O -g -I.
+CRT0 := crt0_mb.o
+CPU := -D CPU_IS_MICROBLAZE=1
+endif
+
+ifeq ($(ARCH),COLDFIRE)
+TOOL_PREFIX := m68k-elf
+CFLAGS := $(COMMON_CFLAGS) -msoft-float -m5200 -g -c -I.
+CRT0 := crt0_cf.o
+CPU := -D CPU_IS_68K=1
+#LIBGCC = `$(CC) -m5200 --print-libgcc-file-name`
+LIBGCC = /usr/lib/gcc-lib/m68k-elf/3.2/m5200/libgcc.a -L /usr/m68k-elf/lib/m5200
+endif
+
+OBJS=$(CRT0) main.o strace.o monlib.o
+
+#####
+#
+# $(APPNAME):
+# Top level target builds the application.
+#
+$(APPNAME): varcheck $(OBJS) makefile
+ echo tools: $(TOOL_PREFIX)
+ $(LD) -e start -o $(APPNAME) -Ttext $(APPRAMBASE) $(OBJS) $(LIBPATH) -lc $(LIBGCC)
+ $(NM) --numeric-sort $(APPNAME) >$(APPNAME).sym
+ $(OBJDUMP) --source --disassemble $(APPNAME) > $(APPNAME).dis
+ $(STRIP) $(APPNAME)
+
+#####
+#
+# Variable checks:
+# Verify that the necessary variables have been set on the make
+# command line.
+#
+varcheck:
+ifndef ARCH
+ @echo Must specify ARCH=XXX on command line.
+ @exit 1
+endif
+ifndef TOOL_PREFIX
+ @echo Invalid ARCH specification. Use PPC, ARM, MIPS, BLACKFIN or COLDFIRE.
+ @exit 1
+endif
+ifeq ($(TOOL_PREFIX),-)
+ @echo Invalid ARCH specification. Use PPC, ARM, MIPS, BLACKFIN or COLDFIRE.
+ @exit 1
+endif
+ifndef MONCOMPTR
+ @echo Must specify MONCOMPTR=XXX on command line.
+ @exit 1
+endif
+ifndef APPRAMBASE
+ @echo Must specify APPRAMBASE=XXX on command line.
+ @exit 1
+endif
+
+targetipcheck:
+ifndef TARGET_IP
+ @echo Must specify TARGET_IP=IPADDRESS on command line.
+ @exit 1
+endif
+
+
+#####
+#
+# Objects:
+#
+crt0_68k.o: $(COMMON)/crt0_68k.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_68k.S
+
+crt0_arm.o: $(COMMON)/crt0_arm.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_arm.S
+
+crt0_bfin.o: $(COMMON)/crt0_bfin.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_bfin.S
+
+crt0_mips.o: $(COMMON)/crt0_mips.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_mips.S
+
+crt0_mb.o: $(COMMON)/crt0_mb.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_mb.S
+
+crt0_ppc.o: $(COMMON)/crt0_ppc.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_ppc.S
+
+crt0_sh2.o: $(COMMON)/crt0_sh2.S
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_sh2.S
+
+main.o: main.c
+ $(CC) $(CFLAGS) -D MONCOMPTR=$(MONCOMPTR) -o $@ main.c
+
+monlib.o: $(COMMON)/monlib.c
+ $(CC) $(CFLAGS) -o $@ $(COMMON)/monlib.c
+
+strace.o: strace.c
+ $(CC) $(CFLAGS) $(CPU) -o $@ strace.c
+
+#####
+#
+# clean:
+# Remove all files created by this make.
+#
+clean:
+ rm -f *.o $(APPNAME) $(APPNAME).ezip $(APPNAME).sym $(APPNAME).dis symtbl
+
+#####
+#
+# sym:
+# Create and download the symbol table file that can be used by uMon
+# with this application...
+#
+sym: targetipcheck
+ @if ! test -f $(APPNAME).sym; then echo Must build $(APPNAME) first; exit 1; fi
+ monsym -p0x $(APPNAME).sym >symtbl
+ ttftp $(TARGET_IP) put symtbl
+
+
+
+#####
+#
+# dld:
+# Use the ttftp tool (supplied with MicroMonitor) to download the
+# application to the target.
+#
+dld: targetipcheck
+ @if ! test -f $(APPNAME); then echo Must build $(APPNAME) first; exit 1; fi
+ ttftp $(TARGET_IP) put $(APPNAME) $(APPNAME),E
+
+#####
+#
+# zdld:
+# Compress the elf file using the 'elf' tool (supplied with MicroMonitor)
+# The output of this is "$(APPNAME).ezip", then download that compressed file.
+#
+zdld: targetipcheck
+ @if ! test -f $(APPNAME); then echo Must build $(APPNAME) first; exit 1; fi
+ elf -z6 $(APPNAME)
+ ttftp $(TARGET_IP) put $(APPNAME).ezip $(APPNAME),Ec
diff --git a/apps/demo/strace.c b/apps/demo/strace.c
new file mode 100644
index 0000000..a2fcb0f
--- /dev/null
+++ b/apps/demo/strace.c
@@ -0,0 +1,100 @@
+/* strace.c:
+ * This file provides a simple, self-induced exception that can
+ * be caught by MicroMonitor. After catching the exception, the
+ * monitor will not attempt any automatic restart because the
+ * NO_EXCEPTION_RESTART shell variable is set at the top of
+ * strace_demo() below (typically this environment variable would
+ * be set during development in the monrc file).
+ *
+ * After the exception has completed, at the uMON> prompt type the
+ * "strace" command. Assuming your monitor is built with INCLUDE_STRACE
+ * set (refer to config.h for your monitor's port), then the output
+ * should be something like this...
+ *
+ * 1: uMON>app strace_demo
+ * 2: strace_demo
+ * 3: func1
+ * 4: func2
+ * 5: func3 exception now!
+ * 6:
+ * 7: EXCEPTION: 'Syscall'
+ * 8: Occurred near 0xa0051240 (within func3)
+ * 9:
+ * 10: uMON>strace
+ * 11: 0xa0051240: func3() + 0x1c
+ * 12: 0xa0051284: func2() + 0x28
+ * 13: 0xa00512b4: func1() + 0x1c
+ * 14: 0xa00512f4: strace_demo() + 0x30
+ * 15: 0xa00511d0: main() + 0x1b4
+ * 16: 0xa005120c: Cstart() + 0x34
+ * 17:
+ * 18: uMON>
+ *
+ * Line 1 : shows the invocation of the application 'app'.
+ * Lines 2-5 : show the output of the strace.c mon_printf calls.
+ * Lines 7-8 : show uMon catching the exception.
+ * Line 10 : shows the invocation of the 'strace' command.
+ * Lines 11-16 : show the output of strace giving the user the exact
+ * call-stack that caused the exception.
+
+ * Note1:
+ * The strace facility (INCLUDE_STRACE in config.h) in the
+ * monitor requires that the symbol table facility (INCLUDE_SYMTBL in
+ * the config.h file) also be enabled.
+ * Note2:
+ * Depending on the version of GCC you're using, you may have to specify
+ * -fno-omit-frame-pointer on the command line; otherwise the stack trace
+ * function will not work properly.
+ */
+#include "monlib.h"
+
+#if CPU_IS_MIPS
+#define EXCEPTION() asm("syscall 99"); /* System call */
+#elif CPU_IS_68K
+#define EXCEPTION() asm("trap #3"); /* Trap */
+#elif CPU_IS_SH
+#define EXCEPTION() asm("trap #3"); /* Trap */
+#elif CPU_IS_BFIN
+#define EXCEPTION() asm("excpt 5"); /* Force exception */
+#elif CPU_IS_MICROBLAZE
+#define EXCEPTION() asm("bralid r15,8"); /* User exception */
+#elif CPU_IS_PPC
+#define EXCEPTION() asm("sc"); /* System call */
+#elif CPU_IS_ARM
+#define EXCEPTION() asm("swi"); /* Software interrupt */
+#else
+#error: Must specify CPU type for exception demo.
+#endif
+
+int
+func3(int i)
+{
+ mon_printf("func3 exception now!\n");
+ EXCEPTION();
+ return(i+5);
+}
+
+int
+func2(int i)
+{
+ mon_printf("func2\n");
+ func3(i+3);
+ return(99);
+}
+
+int
+func1(void)
+{
+ mon_printf("func1\n");
+ func2(3);
+ return(88);
+}
+
+int
+strace_demo(void)
+{
+ mon_printf("strace_demo\n");
+ mon_setenv("NO_EXCEPTION_RESTART","TRUE");
+ func1();
+ return(77);
+}
diff --git a/main/common/alttfsdevtbl.S b/main/common/alttfsdevtbl.S
new file mode 100644
index 0000000..1e198b8
--- /dev/null
+++ b/main/common/alttfsdevtbl.S
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * alttfsdevtbl.S:
+ *
+ * The use of alt_tfsdevtbl_base within uMon allows the "tfs cfg"
+ * command to be used by versions of uMon that are relocated to
+ * RAM. This applies to the "ramtst" build for a given port,
+ * but more importantly, it applies to those ports that have to
+ * relocate themselves to RAM just to successfully boot.
+ *
+ * The reason this is needed is because this block of empty flash
+ * is placed at a fixed location in the memory space (usually
+ * next to moncomptr and etheradd) so that other non-flash-based
+ * versions can find this location through a tag in the linker
+ * map file. That tag must be set to point to the physical location
+ * at which alt_tfsdevtbl_base is placed (similar to etheradd).
+ *
+ * So, when building with the following line in config.h...
+ *
+ * #define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base
+ *
+ * the linker map file used by any run-from-ram version of that
+ * port must contain the tag that initializes this base address
+ * something like this (where ALTTFSDEVTBLBASE is replaced by
+ * some fixed address)...
+ *
+ * alt_tfsdevtbl_base = ALTTFSDEVTBLBASE;
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+ .global alt_tfsdevtbl_base
+
+ .balign 0x10
+
+alt_tfsdevtbl_base:
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+alt_tfsdevtbl_end:
diff --git a/main/common/aout.h b/main/common/aout.h
new file mode 100644
index 0000000..e90160b
--- /dev/null
+++ b/main/common/aout.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * aout.h:
+ *
+ * Header file for the AOUT file format used by TFS.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _AOUT_H_
+#define _AOUT_H_
+
+struct exec {
+ unsigned short a_mid;
+ unsigned short a_magic;
+ unsigned long a_text; /* Size of text segment in bytes */
+ unsigned long a_data; /* Size of data segment in bytes */
+ unsigned long a_bss; /* Size of bss segment in bytes */
+ unsigned long a_syms; /* Size of symbol table in bytes */
+ unsigned long a_entry; /* Entry point address */
+ unsigned long a_trsize; /* Size of text relocation table */
+ unsigned long a_drsize; /* Size of data relocation table */
+};
+
+struct relocation_info {
+ int r_address;
+ ulong r_info;
+};
+
+/* Fields within r_info: */
+#define SYMNUM_MSK 0xffffff00
+#define PCREL_MSK 0x00000080
+#define LENGTH_MSK 0x00000060
+#define EXTERN_MSK 0x00000010
+#endif
diff --git a/main/common/arp.c b/main/common/arp.c
new file mode 100644
index 0000000..0c8d762
--- /dev/null
+++ b/main/common/arp.c
@@ -0,0 +1,650 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * arp.c:
+ * This code supports some basic arp/rarp stuff.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_ETHERNET
+#include "endian.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "timer.h"
+
+static void ArpFlush(void);
+static void ArpShow(char *);
+static void llas(char *);
+static int ArpStore(uchar *,uchar *);
+static int IpIsOnThisNet(uchar *);
+
+static unsigned long probeIP;
+static char probeAbort;
+
+/* Constants used by Dynamic IPV4 Local-Link Address setup...
+ * (see RFC 3927)
+ */
+#define PROBE_WAIT 1000 /* (msec) */
+#define PROBE_NUM 3
+#define PROBE_MIN 1000 /* (msec) */
+#define PROBE_MAX 2000 /* (msec) */
+#define ANNOUNCE_WAIT 2000 /* (msec) */
+#define ANNOUNCE_NUM 2
+#define ANNOUNCE_INTERVAL 2000 /* (msec) */
+#define MAX_CONFLICTS 10
+#define RATE_LIMIT_INTERVAL 60000 /* (msec) */
+#define DEFEND_INTERVAL 10000 /* (msec) */
+
+/* arpcache[]:
+ * Used to store the most recent set of IP-to-MAC address correlations.
+ */
+struct arpcache {
+ uchar ip[4];
+ uchar ether[6];
+} ArpCache[SIZEOFARPCACHE];
+
+/* ArpIdx & ArpTot:
+ * Used for keeping track of current arp cache content.
+ */
+int ArpIdx, ArpTot;
+
+/* ArpStore():
+ * Called with binary ip and ethernet addresses.
+ * It will store that set away in the cache.
+ */
+int
+ArpStore(uchar *ip,uchar *ether)
+{
+ if (EtherFromCache(ip))
+ return(0);
+ if (ArpIdx >= SIZEOFARPCACHE)
+ ArpIdx=0;
+ memcpy((char *)ArpCache[ArpIdx].ip,(char *)ip,4);
+ memcpy((char *)ArpCache[ArpIdx].ether,(char *)ether,6);
+ ArpIdx++;
+ ArpTot++;
+ return(0);
+}
+
+/* EtherFromCache():
+ * Called with a binary (4-byte) ip address. If a match is found
+ * in the cache, return a pointer to that ethernet address; else
+ * return NULL.
+ */
+uchar *
+EtherFromCache(uchar *ip)
+{
+ int i;
+
+ for(i=0;i<SIZEOFARPCACHE;i++) {
+ if (!memcmp((char *)ArpCache[i].ip, (char *)ip,4))
+ return(ArpCache[i].ether);
+ }
+ return(0);
+}
+
+void
+ArpFlush(void)
+{
+ int i;
+
+ for(i=0;i<SIZEOFARPCACHE;i++) {
+ memset((char *)ArpCache[i].ip,0,4);
+ memset((char *)ArpCache[i].ether,0,6);
+ }
+ ArpIdx = ArpTot = 0;
+}
+
+/* ArpShow():
+ * Dump the content of the current arp cache.
+ */
+void
+ArpShow(char *ip)
+{
+ struct arpcache *ap, *end;
+
+ if (ArpTot < SIZEOFARPCACHE)
+ end = &ArpCache[ArpTot];
+ else
+ end = &ArpCache[SIZEOFARPCACHE];
+
+ for (ap=ArpCache;ap<end;ap++) {
+ if ((!ip) || (!memcmp((char *)ip, (char *)ap->ip,4))) {
+ printf("%02x:%02x:%02x:%02x:%02x:%02x = ",
+ ap->ether[0], ap->ether[1], ap->ether[2], ap->ether[3],
+ ap->ether[4], ap->ether[5]);
+ printf("%d.%d.%d.%d\n",
+ ap->ip[0], ap->ip[1], ap->ip[2], ap->ip[3]);
+ }
+ }
+}
+
+/* SendArpResp():
+ * Called in response to an ARP REQUEST. The incoming ethernet
+ * header pointer points to the memory area that contains the incoming
+ * ethernet packet that this function is called in response to.
+ * In other words, it is used to fill the majority of the response
+ * packet fields.
+ */
+int
+SendArpResp(struct ether_header *re)
+{
+ struct ether_header *te;
+ struct arphdr *ta, *ra;
+
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&(te->ether_shost), (char *)BinEnetAddr,6);
+ memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6);
+ te->ether_type = ecs(ETHERTYPE_ARP);
+
+ ta = (struct arphdr *) (te + 1);
+ ra = (struct arphdr *) (re + 1);
+ ta->hardware = ra->hardware;
+ ta->protocol = ra->protocol;
+ ta->hlen = ra->hlen;
+ ta->plen = ra->plen;
+ ta->operation = ARP_RESPONSE;
+ memcpy((char *)ta->senderha, (char *)BinEnetAddr,6);
+ memcpy((char *)ta->senderia, (char *)ra->targetia,4);
+ memcpy((char *)ta->targetha, (char *)ra->senderha,6);
+ memcpy((char *)ta->targetia, (char *)ra->senderia,4);
+ self_ecs(ta->hardware);
+ self_ecs(ta->protocol);
+ self_ecs(ta->operation);
+ sendBuffer(ARPSIZE);
+ return(0);
+}
+
+/* SendArpRequest():
+ * If 'probe' is non-zero, then the request is an arp-probe.
+ * Refer to RFC3927 for more on that.
+ */
+static int
+SendArpRequest(uchar *ip, int probe)
+{
+ struct ether_header *te;
+ struct arphdr *ta;
+
+ /* Populate the ethernet header: */
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&(te->ether_shost), (char *)BinEnetAddr,6);
+ memcpy((char *)&(te->ether_dhost), (char *)BroadcastAddr,6);
+ te->ether_type = ecs(ETHERTYPE_ARP);
+
+ /* Populate the arp header: */
+ ta = (struct arphdr *) (te + 1);
+ ta->hardware = ecs(1); /* 1 for ethernet */
+ ta->protocol = ecs(ETHERTYPE_IP);
+ ta->hlen = 6; /* Length of hdware (ethernet) address */
+ ta->plen = 4; /* Length of protocol (ip) address */
+ ta->operation = ecs(ARP_REQUEST);
+ memcpy((char *)ta->senderha, (char *)BinEnetAddr,6);
+ if (probe) {
+ memset((char *)ta->senderia,0,4);
+ memset((char *)ta->targetha,0,6);
+ }
+ else {
+ memcpy((char *)ta->senderia, (char *)BinIpAddr,4);
+ memcpy((char *)ta->targetha, (char *)BroadcastAddr,6);
+ }
+ memcpy((char *)ta->targetia, (char *)ip,4);
+ sendBuffer(ARPSIZE);
+ return(0);
+}
+
+/* GetBinNetMask():
+ * Return a subnet mask in binary form.
+ * Since this function needs a netmask, if NETMASK is not set, then
+ * it uses the default based on the upper 3 bits of the IP address
+ * (refer to TCP/IP Illustrated Volume 1 Pg8 for details).
+ */
+void
+GetBinNetMask(uchar *binnetmask)
+{
+ char *nm;
+
+ nm = getenv("NETMASK");
+ if (!nm) {
+ memset((char *)binnetmask,0xff,4);
+ if ((BinIpAddr[0] & 0xe0) == 0xc0) { /* Class C */
+ binnetmask[3] = 0;
+ }
+ else if ((BinIpAddr[0] & 0xc0) == 0x80) { /* Class B */
+ binnetmask[3] = 0;
+ binnetmask[2] = 0;
+ }
+ else if ((BinIpAddr[0] & 0x80) == 0x00) { /* Class A */
+ binnetmask[3] = 0;
+ binnetmask[2] = 0;
+ binnetmask[1] = 0;
+ }
+ }
+ else
+ IpToBin(nm,binnetmask);
+}
+
+/* IpIsOnThisNet():
+ * Return 1 if the incoming ip is on this subnet; else 0.
+ * For each bit in the netmask that is set to 1...
+ * If the corresponding bits in the incoming IP and this board's IP
+ * do not match, return 0; else return 1.
+ */
+int
+IpIsOnThisNet(uchar *ip)
+{
+ int i;
+ uchar binnetmask[8];
+
+ GetBinNetMask(binnetmask);
+
+ for(i=0;i<4;i++) {
+ if ((ip[i] & binnetmask[i]) != (BinIpAddr[i] & binnetmask[i])) {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+/* Arp():
+ * If no args, just dump the arp cache.
+ * If arg is present, then assume it to be an ip address.
+ * Check the arp cache for the presence of that ip<->correlation, if
+ * present, print it; else issue and arp request for that IP and wait
+ * for a response.
+ */
+
+char *ArpHelp[] = {
+ "Address resolution protocol",
+ "-[flps:v] [IP]",
+#if INCLUDE_VERBOSEHELP
+ " -f flush cache",
+ " -l dynamic config using link-local arp probe",
+ " -p proxy arp",
+ " -s{eadr} store eadr/IP into cache",
+#if INCLUDE_ETHERVERBOSE
+ " -v verbose",
+#endif
+#endif
+ 0,
+};
+
+int
+Arp(int argc,char *argv[])
+{
+ int opt, proxyarp, llad;
+ char binip[8], binether[8], *storeether;
+
+ llad = proxyarp = 0;
+ storeether = (char *)0;
+ while ((opt=getopt(argc,argv,"flps:v")) != -1) {
+ switch(opt) {
+ case 'f': /* Flush current arp cache */
+ ArpFlush();
+ break;
+ case 'l': /* Dynamic ip-config using link-local addressing */
+ llad = 1; /* (refer to RFC 3927) */
+ break;
+ case 's': /* Store specified IP/MAC combination in arp cache. */
+ storeether = optarg;
+ break;
+ case 'p': /* Assume gateway will run proxy arp */
+ proxyarp = 1;
+ break;
+#if INCLUDE_ETHERVERBOSE
+ case 'v': /* Enable verbosity for ARP. */
+ EtherVerbose |= SHOW_ARP;
+ break;
+#endif
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ /* If llad flag is set, then we do a dynamic configuration using the
+ * link-local protocol as described in RFC 3927...
+ */
+ if (llad) {
+ char buf[32];
+ struct elapsed_tmr tmr;
+ int i, retry, conflicts, psval;
+
+#if INCLUDE_DHCPBOOT
+ dhcpDisable();
+#endif
+ probeAbort = retry = conflicts = 0;
+
+ /* Use MAC address to establish a uniformly selected pseudo random
+ * value between 0 and 1000...
+ */
+ psval = (BinEnetAddr[5] * 4);
+
+ monDelay(psval);
+
+ if (argc == (optind+1))
+ IpToBin((char *)argv[optind],(unsigned char *)&probeIP);
+ else
+ llas((char *)&probeIP);
+
+nextllas:
+ SendArpRequest((uchar *)&probeIP,1);
+ startElapsedTimer(&tmr,ANNOUNCE_WAIT);
+ while(!msecElapsed(&tmr)) {
+ if (probeAbort) {
+ llas((char *)&probeIP);
+ probeAbort = retry = 0;
+ monDelay(psval + PROBE_MIN);
+ goto nextllas;
+ }
+ if (EtherFromCache((uchar *)&probeIP)) {
+ if (++conflicts > MAX_CONFLICTS)
+ monDelay(RATE_LIMIT_INTERVAL);
+ else
+ monDelay(psval + PROBE_MIN);
+ if (++retry == PROBE_NUM) {
+ llas((char *)&probeIP);
+ retry = 0;
+ }
+ goto nextllas;
+ }
+ pollethernet();
+ }
+ /* If we're here, then we found an IP address that is not being
+ * used on the local subnet...
+ */
+ setenv("IPADD",IpToString(probeIP,buf));
+ setenv("NETMASK","255.255.0.0");
+ setenv("GIPADD",0);
+#if INCLUDE_ETHERVERBOSE
+ EthernetStartup(EtherVerbose,0);
+#else
+ EthernetStartup(0,0);
+#endif
+ for(i=0;i<ANNOUNCE_NUM;i++) {
+ SendArpRequest(BinIpAddr,0);
+ monDelay(ANNOUNCE_INTERVAL);
+ }
+ }
+ else if (argc == (optind+1)) {
+ IpToBin((char *)argv[optind],(unsigned char *)binip);
+ if (storeether) {
+ EtherToBin((char *)storeether, (unsigned char *)binether);
+ ArpStore((unsigned char *)binip,(unsigned char *)binether);
+ }
+ else {
+ if (ArpEther((unsigned char *)binip,(unsigned char *)0,proxyarp))
+ ArpShow(binip);
+ }
+ }
+ else
+ ArpShow(0);
+#if INCLUDE_ETHERVERBOSE
+ EtherVerbose &= ~ SHOW_ARP;
+#endif
+ return(CMD_SUCCESS);
+}
+
+/* ArpEther():
+ * Retrieve the ethernet address that corresponds to the incoming IP
+ * address. First check the local ArpCache[], then if not found issue
+ * an ARP request... If the incoming IP is on this net, then issue the
+ * request for the MAC address of that IP; otherwise, issue the request
+ * for this net's GATEWAY.
+ */
+uchar *
+ArpEther(uchar *binip, uchar *ecpy, int proxyarp)
+{
+ char *gip;
+ struct elapsed_tmr tmr;
+ uchar gbinip[8], *Ip, *ep;
+ int timeoutsecs, retry;
+
+ if (!EtherIsActive) {
+ printf("Ethernet disabled\n");
+ return(0);
+ }
+
+ /* First check local cache. If found, return with pointer to MAC. */
+ ep = EtherFromCache(binip);
+ if (ep) {
+ if (ecpy) {
+ memcpy((char *)ecpy, (char *)ep,6);
+ ep = ecpy;
+ }
+ return(ep);
+ }
+
+ retry = 0;
+ RetransmitDelay(DELAY_INIT_ARP);
+ while(1) {
+ /* If IP is not on this net, then get the GATEWAY IP address. */
+ if (!proxyarp && !IpIsOnThisNet(binip)) {
+ gip = getenv("GIPADD");
+ if (gip) {
+ IpToBin(gip,gbinip);
+ if (!IpIsOnThisNet(gbinip)) {
+ printf("GIPADD/IPADD subnet confusion.\n");
+ return(0);
+ }
+ ep = EtherFromCache(gbinip);
+ if (ep) {
+ if (ecpy) {
+ memcpy((char *)ecpy, (char *)ep,6);
+ ep = ecpy;
+ }
+ return(ep);
+ }
+ SendArpRequest(gbinip,0);
+ Ip = gbinip;
+ }
+ else {
+ SendArpRequest(binip,0);
+ Ip = binip;
+ }
+ }
+ else {
+ SendArpRequest(binip,0);
+ Ip = binip;
+ }
+ if (retry) {
+ printf(" ARP Retry #%d (%d.%d.%d.%d)\n",retry,
+ binip[0],binip[1],binip[2],binip[3]);
+ }
+
+ /* Now that the request has been issued, wait for a while to see if
+ * the ARP cache is loaded with the result of the request.
+ */
+ timeoutsecs = RetransmitDelay(DELAY_OR_TIMEOUT_RETURN);
+ if (timeoutsecs == RETRANSMISSION_TIMEOUT)
+ break;
+ startElapsedTimer(&tmr,timeoutsecs*1000);
+ while(!msecElapsed(&tmr)) {
+ ep = EtherFromCache(Ip);
+ if (ep)
+ break;
+
+ pollethernet();
+ }
+ if (ep) {
+ if (ecpy) {
+ memcpy((char *)ecpy, (char *)ep,6);
+ ep = ecpy;
+ }
+ return(ep);
+ }
+ RetransmitDelay(DELAY_INCREMENT);
+ retry++;
+ }
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_ARP) && (retry))
+ printf(" ARP giving up\n");
+#endif
+ return(0);
+}
+
+/* processRARP();
+ * Called by the fundamental ethernet driver code to process a RARP
+ * request.
+ */
+int
+processRARP(struct ether_header *ehdr,ushort size)
+{
+ struct arphdr *arpp;
+
+ arpp = (struct arphdr *)(ehdr+1);
+ self_ecs(arpp->hardware);
+ self_ecs(arpp->protocol);
+ self_ecs(arpp->operation);
+
+ switch(arpp->operation) {
+ case RARP_RESPONSE:
+ if (!memcmp((char *)arpp->targetha, (char *)BinEnetAddr,6)) {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_ARP) {
+ printf(" RARP Response from %d.%d.%d.%d\n",
+ arpp->senderia[0],arpp->senderia[1],
+ arpp->senderia[2],arpp->senderia[3]);
+ printf(" MY IP: from %d.%d.%d.%d\n",
+ arpp->targetia[0],arpp->targetia[1],
+ arpp->targetia[2],arpp->targetia[3]);
+ }
+#endif
+ memcpy((char *)BinIpAddr, (char *)arpp->targetia,6);
+ }
+ break;
+ case RARP_REQUEST:
+ break;
+ default:
+ printf(" Invalid RARP operation: 0x%x\n",arpp->operation);
+ return(-1);
+ }
+ return(0);
+}
+
+/* processARP();
+ * Called by the fundamental ethernet driver code to process a ARP
+ * request.
+ */
+char *
+processARP(struct ether_header *ehdr,ushort size)
+{
+ struct arphdr *arpp;
+
+ arpp = (struct arphdr *)(ehdr+1);
+ self_ecs(arpp->hardware);
+ self_ecs(arpp->protocol);
+ self_ecs(arpp->operation);
+
+ /* If the sender IP address is all zeroes, then assume this is
+ * an arp probe. If we are currently doing a probe, and the
+ * address we are probing matches the target IP address of this
+ * probe, then set a flag that will abort the current probe.
+ */
+ if ((arpp->senderia[0] == 0) && (arpp->senderia[1] == 0) &&
+ (arpp->senderia[2] == 0) && (arpp->senderia[3] == 0)) {
+ if (memcmp((char *)arpp->targetia,(char *)&probeIP,4) == 0)
+ probeAbort = 1;
+ }
+
+ switch(arpp->operation) {
+ case ARP_REQUEST:
+ if (!memcmp((char *)arpp->targetia, (char *)BinIpAddr,4)) {
+ ArpStore(arpp->senderia,arpp->senderha);
+ SendArpResp(ehdr);
+ }
+ break;
+ case ARP_RESPONSE:
+ if (!memcmp((char *)arpp->targetia, (char *)BinIpAddr,4)) {
+ if (!memcmp((char *)arpp->targetia,(char *)arpp->senderia,4))
+ printf("WARNING: IP %s may be in use on network\n",IPadd);
+
+ ArpStore(arpp->senderia,arpp->senderha);
+ }
+ break;
+ default:
+ printf(" Invalid ARP operation: 0x%x\n",arpp->operation);
+ printPkt(ehdr,(int)size,ETHER_INCOMING);
+ return((char *)0);
+ }
+ return((char *)(arpp + 1));
+}
+
+/* sendGratuitousARP():
+ * As defined in RFC 3220...
+ *
+ * An ARP packet sent by a node in order to spontaneously
+ * cause other nodes to update an entry in their ARP cache.
+ *
+ * Issue a "gratuitous ARP" (RFC 3220) for two reasons...
+ * - make sure no other host is already using this IP address.
+ * - cause other devices on cable to update their arp cache.
+ */
+void
+sendGratuitousArp(void)
+{
+ SendArpRequest(BinIpAddr,0);
+}
+
+/* llas():
+ * Link local address selection.
+ * Referring to sec 2.1 of RFC3927, select an address using a pseudo-random
+ * number generator to assign a number in the range from
+ * 169.254.1.0 (0xa9fe0100) thru 169.254.254.255 (0xa9fefeff).
+ * To do this, we run a 32-bit CRC on the 6-byte MAC address, then add the
+ * least significant 8 bits of that value to the base of the address
+ * range. Each successive time this function is called, then increment
+ * by the least significant 4 bits of the LSB of the MAC.
+ */
+#define LLAD_BEGIN 0xa9fe0100
+#define LLAD_END 0xa9fefeff
+
+static void
+llas(char *ipptr)
+{
+ static char beenhere;
+ static unsigned long llad;
+ unsigned long pseudorandval, tmp;
+
+ if (beenhere == 0) {
+ pseudorandval = crc32(BinEnetAddr,6);
+ llad = LLAD_BEGIN + (pseudorandval & 0xff);
+ }
+ else {
+ pseudorandval = (unsigned long)(BinEnetAddr[5] & 0xf);
+ llad += pseudorandval;
+ if (llad >= LLAD_END)
+ llad = LLAD_BEGIN + pseudorandval + beenhere;
+ }
+ beenhere++;
+
+ printf("LLAD: %d.%d.%d.%d\n",
+ (llad & 0xff000000) >> 24, (llad & 0xff0000) >> 16,
+ (llad & 0xff00) >> 8, (llad & 0xff));
+
+ tmp = ecl(llad);
+
+ if (ipptr)
+ memcpy(ipptr,(char *)&tmp,4);
+}
+
+#endif
diff --git a/main/common/bits.h b/main/common/bits.h
new file mode 100644
index 0000000..3caffa3
--- /dev/null
+++ b/main/common/bits.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * bits.h
+ *
+ * This file contains the Bit position defines for ease of use
+ *
+ * Contributed by: Michael Kelly, Cogent Computers Systems, Inc.
+ *
+ */
+
+#ifndef _BITS_H_
+#define _BITS_H_
+/*
+ * Bit position defines
+ */
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+
+#endif
diff --git a/main/common/bmem.h b/main/common/bmem.h
new file mode 100644
index 0000000..ec891fa
--- /dev/null
+++ b/main/common/bmem.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * bmem.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+struct bmem {
+ int id;
+ char *name;
+ int pgsize;
+ int spsize;
+ int ppb;
+ int btot;
+ int (*bmemerase)(int bkno, int verbose);
+ int (*bmemread)(char *dest, int bkno, int pgno, int size, int verbose);
+ int (*bmemwrite)(char *src, int bkno, int pgno, int size, int verbose);
+};
+
+extern struct bmem bmemtbl[];
diff --git a/main/common/boardinfo.c b/main/common/boardinfo.c
new file mode 100644
index 0000000..f1ea412
--- /dev/null
+++ b/main/common/boardinfo.c
@@ -0,0 +1,320 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * boardinfo.c:
+ *
+ * When the boot monitor is updated (using newmon), only the sectors that
+ * are used by the monitor are re-written. If a sector in the flash is
+ * not being used by TFS, and is not being used by the monitor, then the
+ * strategy of the code in this file may be useful...
+ *
+ * The monrc file is used by the monitor to store various initialization
+ * parameters. At a minimum (on systems with ethernet), this will include
+ * an IP address, MAC address, Gateway IP address and Network Mask. It
+ * may also include some board/target-specific information. This is convenient
+ * because it is a file that can be updated on a per-board basis; however,
+ * the convenience can also be a pain in the butt. The user can easily
+ * modify the monrc file and change the IP address and MAC address (things
+ * that are usually not changed very often, especially the MAC address).
+ * To make some of this stuff a bit less convenient to change, these
+ * values (strings) can be put into some other portion of flash that is
+ * not used by the monitor or TFS. Hence, even if TFS is initialized or
+ * the monitor is updated, this information will remain in place.
+ *
+ * This file, in conjunction with a target-specific table called
+ * boardinfotbl[] supports the ability to store this data in a sector
+ * that is not being used by TFS or the monitor binary. When the target
+ * first comes up, it will check to see if this space is erased. If yes,
+ * then it will query the user for values to be loaded and they will then
+ * be stored away in a sector of flash that is not used by TFS or uMon.
+ * They will become shell variables at startup, and will not be changeable
+ * unless that sector is manually erased.
+ *
+ * Note that an inefficiency of this is that it assumes it has a sector
+ * dedicated to it. This "inefficiency" however; is what makes it less
+ * likely to be mistakenly erased.
+ *
+ * Following is an example boardinfotbl[]...
+ *
+ extern unsigned char etheraddr[], boardtag[];
+
+ struct boardinfo boardinfotbl[] = {
+ { etheraddr, 32, "ETHERADD", (char *)0, "MAC addr" },
+ { boardtag, 32, "BOARDTAG", (char *)0, "Board tag" },
+ { 0,0,0,0 }
+ };
+
+ *
+ * The externs "etheraddr" and "boardtag" are actually pointers into some
+ * portion of the flash sector that is to be used for this storage. These
+ * values can be placed in the linker map file or be hard-coded addresses
+ * in this file.
+ *
+ * Then, in config.h, the following two definitions must be established...
+ *
+
+ #define BOARDINFO_SECTOR 7
+ #define BOARDINFO_BUFMAX 32
+
+ *
+ * The value assigned to BOARDINFO_SECTOR is the sector number that is
+ * used for the storage and BOARDINFO_BUFMAX is the size of buf[] within
+ * the BoardInfoInit function below.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "boardinfo.h"
+#include "cli.h"
+
+#if INCLUDE_FLASH & INCLUDE_BOARDINFO
+
+#ifdef BOARDINFO_DEBUG
+#define BINFOPRINT(a) printf a
+#else
+#define BINFOPRINT(a)
+#endif
+
+/* boardinfo_error:
+ * Set if there was any kind of read error from the board info structure.
+ */
+int boardinfo_error;
+
+void
+BoardInfoInit(void)
+{
+ short len;
+ ushort crc;
+ struct boardinfo *bip;
+ int maxpromptsize, erased;
+ struct boardinfoverify *bipv;
+ uchar buf[BOARDINFO_BUFMAX];
+ char c, snum[8], prfmt[16], *prefill;
+
+ sprintf(snum,"%d",BOARDINFO_SECTOR);
+
+ /* Step through each bip entry and see if the data area is either
+ * empty or the crc16 passed. If either is true, then allow
+ * If every entry in the board-information area is either empty
+ * or the crc test passes, we can just return...
+ */
+ erased = 0;
+ maxpromptsize = 0;
+ boardinfo_error = 0;
+ bip = boardinfotbl;
+ while((bip->array) && (!boardinfo_error)) {
+ BINFOPRINT(("Boardinfo item: %s (%s)",bip->varname,bip->prompt));
+ if (bip->array[0] != 0xff) {
+ BINFOPRINT((" not"));
+ bipv = (struct boardinfoverify *)&bip->array[bip->size-BIVSIZE];
+
+ /* If len and crc are set, then use those fields to sanity
+ * check the data...
+ */
+ if ((bipv->len != 0xffff) && (bipv->crc16 != 0xffff)) {
+ if ((bipv->len > bip->size) ||
+ (xcrc16(bip->array,bipv->len) != bipv->crc16)) {
+ boardinfo_error = 1;
+ }
+ }
+ }
+ else
+ erased++;
+ BINFOPRINT((" erased\n"));
+
+ /* Gather data to determine the largest prompt... */
+ len = strlen(bip->prompt);
+ if (len > maxpromptsize)
+ maxpromptsize = len;
+ bip++;
+ }
+
+ /* If there was no error, and the board info area is not erased,
+ * we return here assuming the data is valid.
+ */
+ if ((boardinfo_error == 0) && (erased == 0)) {
+ sectorProtect(snum,1);
+ return;
+ }
+
+ /* If there was some kind of error reading any of the fields in the
+ * board-info area, then either return or clear the error and interact
+ * with the user to re-load the data...
+ */
+ if (boardinfo_error != 0) {
+#ifdef BOARDINFO_REENTER_ON_ERROR
+ printf("\nError reading board-info data, re-enter data...");
+ boardinfo_error = 0;
+#else
+ printf("\nError reading board-info data in sector %d.\n",
+ BOARDINFO_SECTOR);
+ return;
+#endif
+ }
+
+ sprintf(prfmt,"%%%ds : ",maxpromptsize);
+
+ printf("%s: board information field initialization...\n",PLATFORM_NAME);
+
+ /* Un-protect the sector used for board information...
+ */
+ sectorProtect(snum,0);
+
+ do {
+ /* Erase the sector used for board information...
+ */
+ if (AppFlashErase(BOARDINFO_SECTOR) < 0) {
+ boardinfo_error = 1;
+ break;
+ }
+
+ /* Step through each entry in the boardinfo table and query
+ * the user for input to be stored...
+ */
+ bip = boardinfotbl;
+ while(bip->array) {
+ bipv = (struct boardinfoverify *)&bip->array[bip->size-BIVSIZE];
+
+ if (bip->def)
+ prefill = bip->def;
+ else
+ prefill = 0;
+
+ printf(prfmt,bip->prompt);
+ len = 0;
+ if (getline_p((char *)buf,bip->size-BIVSIZE,0,prefill) != 0) {
+ len = strlen(buf)+1;
+ if (AppFlashWrite(bip->array,buf,len) < 0) {
+ boardinfo_error = 1;
+ break;
+ }
+ crc = xcrc16(buf,len);
+ }
+ if (len) {
+ if (AppFlashWrite((uchar *)(&bipv->len),
+ (uchar *)&len,sizeof(len)) < 0) {
+ boardinfo_error = 1;
+ break;
+ }
+ if (AppFlashWrite((uchar *)(&bipv->crc16),
+ (uchar *)&crc,sizeof(crc)) < 0) {
+ boardinfo_error = 1;
+ break;
+ }
+ }
+ bip++;
+ }
+ if (boardinfo_error)
+ break;
+
+ bip = boardinfotbl;
+ printf("\nNew system settings:\n\n");
+ while(bip->array) {
+#ifdef BOARDINFO_SHOW_RAW
+ printMem(bip->array,bip->size,1);
+#else
+ printf("%24s: %s\n",bip->prompt,
+ bip->array[0] == 0xff ? "" : (char *)bip->array);
+#endif
+ bip++;
+ }
+ putstr("\nHit ENTER to accept, any other key to re-enter...");
+ c = getchar();
+ putchar('\n');
+
+ } while((c != '\r') && (c != '\n'));
+
+ sectorProtect(snum,1);
+}
+
+void
+BoardInfoEnvInit(void)
+{
+ struct boardinfo *bip;
+
+ /* If an error was detected by BoardInfoInit() then we don't
+ * want to do any environmental initialization here...
+ */
+ if (boardinfo_error != 0) {
+ printf("Board info environment not initialized\n");
+ return;
+ }
+
+ bip = boardinfotbl;
+ while(bip->array) {
+ if ((bip->varname) && (bip->array[0] != 0xff))
+ setenv(bip->varname,bip->array);
+ bip++;
+ }
+}
+
+/* BoardInfoVar():
+ * Return 1 if the incoming variable name is a variable
+ * that is established by the BoardInfo facility; else zero.
+ */
+int
+BoardInfoVar(char *varname)
+{
+ struct boardinfo *bip;
+
+ bip = boardinfotbl;
+ while(bip->array) {
+ if (strcmp(varname,bip->varname) == 0)
+ return(1);
+ bip++;
+ }
+ return(0);
+}
+
+char *BinfoHelp[] = {
+ "Dump board-specific information",
+ "",
+#if INCLUDE_VERBOSEHELP
+#endif
+ 0,
+};
+
+int
+BinfoCmd(int argc, char *argv[])
+{
+ int i;
+ char *array;
+ struct boardinfo *bip;
+
+ i = 1;
+ bip = boardinfotbl;
+ printf("Boardinfo sector: %d\n",BOARDINFO_SECTOR);
+ printf(" # ADDRESS VALUE VARNAME DESCRIPTION\n");
+ while(bip->array) {
+ if (bip->array[0] == 0xff)
+ array = "-empty-";
+ else
+ array = bip->array;
+ printf(" %2d: 0x%08lx %-18s %-15s %s\n",i,
+ (long)bip->array,array,bip->varname,bip->prompt);
+ bip++;
+ i++;
+ }
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/boardinfo.h b/main/common/boardinfo.h
new file mode 100644
index 0000000..8a690b3
--- /dev/null
+++ b/main/common/boardinfo.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * boardinfo.h:
+ *
+ * Structures and data used by boardinfo facility.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _BOARDINFO_H_
+#define _BOARDINFO_H_
+
+struct boardinfo {
+ unsigned char *array;
+ short size;
+ char *varname;
+ char *def;
+ char *prompt;
+};
+
+struct boardinfoverify {
+ unsigned short len;
+ unsigned short crc16;
+};
+
+#define BISIZE sizeof(struct boardinfo)
+#define BIVSIZE sizeof(struct boardinfoverify)
+
+/* boardinfotbl[]:
+ * If the "boardinfo" facility in the monitor is to be used, then
+ * this table must be included in the target-specific portion of
+ * the monitor build.
+ */
+extern struct boardinfo boardinfotbl[];
+
+extern void BoardInfoInit(void), BoardInfoEnvInit(void);
+extern int BoardInfoVar(char *);
+#endif
diff --git a/main/common/cache.c b/main/common/cache.c
new file mode 100644
index 0000000..5f230bf
--- /dev/null
+++ b/main/common/cache.c
@@ -0,0 +1,119 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cache.c:
+ * This code is the front-end to CPU-specific code that may or may not
+ * support basic I & D cache operations. Various facilities in the
+ * monitor call the wrapper functions below for carrying out cpu-specific
+ * cache operations. This code provides that wrapper allowing the other
+ * portions of the monitor to be unaware of what the specific CPU actually
+ * supports.
+ *
+ * The cacheInit() function must be called at monitor startup, then
+ * cacheInit() calls cacheInitForTarget(), a function that must be provided
+ * by the target-specific code to fill in the CPU-specific functionality.
+ * This function should establish the cache as it is to be used in
+ * the monitor (typically i-cache enabled, d-cache disabled), plus, if
+ * applicable, the dcacheFlush and icacheInvalidate function pointers should
+ * be initialized to CPU-specific functions that match the API...
+ *
+ * int (*dcacheDisable)(void);
+ * int (*icacheDisable)(void);
+ * int (*dcacheFlush)(char *base,int size);
+ * int (*icacheInvalidate)(char *base, int size);
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "genlib.h"
+#include "cache.h"
+
+int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *, int);
+int (*dcacheDisable)(void), (*icacheDisable)(void);
+
+/* flushDcache():
+ * Flush the address range specified, or if address and size are both
+ * zero, flush the entire D-Cache.
+ */
+int
+flushDcache(char *addr, int size)
+{
+ /* The dcacheFlush function pointer should be initialized in the
+ * port-specific function "cacheInitForTarget".
+ */
+ if (dcacheFlush)
+ return(dcacheFlush(addr,size));
+ return(0);
+}
+
+/* disableDcache():
+ * Disable data cache.
+ */
+int
+disableDcache(void)
+{
+ /* The dcacheDisable function pointer should be initialized in the
+ * port-specific function "cacheInitForTarget".
+ */
+ if (dcacheDisable)
+ return(dcacheDisable());
+ return(0);
+}
+
+/* invalidateIcache():
+ * Invalidate the address range specified, or if address and size are both
+ * zero, invalidate the entire I-Cache.
+ */
+int
+invalidateIcache(char *addr, int size)
+{
+ /* The icacheInvalidate function pointer should be initialized in the
+ * port-specific function "cacheInitForTarget".
+ */
+ if (icacheInvalidate)
+ return(icacheInvalidate(addr,size));
+ return(0);
+}
+
+/* disableIcache():
+ * Disable instruction cache.
+ */
+int
+disableIcache(void)
+{
+ /* The icacheDisable function pointer should be initialized in the
+ * port-specific function "cacheInitForTarget".
+ */
+ if (icacheDisable)
+ return(icacheDisable());
+ return(0);
+}
+
+int
+cacheInit()
+{
+ dcacheDisable = (int(*)(void))0;
+ icacheDisable = (int(*)(void))0;
+ dcacheFlush = (int(*)(char *,int))0;
+ icacheInvalidate = (int(*)(char *,int))0;
+ cacheInitForTarget(); /* Target-specific initialization. */
+ return(0);
+}
diff --git a/main/common/cache.h b/main/common/cache.h
new file mode 100644
index 0000000..a7733ee
--- /dev/null
+++ b/main/common/cache.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cache.h:
+ *
+ * Refer to cache.c for comments.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+/* dcacheFlush, icacheInvalidate, dcacheDisable & icacheDisable:
+ * Function pointers that should be initialized by target-specific code
+ * to point to target-specific functions that can be accessed by the
+ * generic monitor source.
+ */
+extern int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *,int);
+extern int (*dcacheDisable)(void), (*icacheDisable)(void);
+
+/* flushDcache():
+ * Wrapper function for the target-specific d-cache flushing operation
+ * (if one is appropriate). If addr and size are both zero, then flush
+ * the entire D-cache.
+ */
+extern int flushDcache(char *addr, int size);
+
+/* invalidateIcache():
+ * Wrapper function for the target-specific i-cache invalidation operation
+ * (if one is appropriate). If addr and size are both zero, then invalidate
+ * the entire I-cache.
+ */
+extern int invalidateIcache(char *addr, int size);
+
+/* disableDcache() & disableIcache():
+ * Wrapper functions to call target-specific cache disable functions
+ * (if available).
+ */
+extern int disableDcache(void);
+extern int disableIcache(void);
+
+/* cacheInit():
+ * Called at startup. This function calls cacheInitForTarget() which
+ * establishes the cache configuration and initializes the above
+ * function pointers (if applicable).
+ */
+extern int cacheInit(void);
+#endif
diff --git a/main/common/cast.c b/main/common/cast.c
new file mode 100644
index 0000000..0bab527
--- /dev/null
+++ b/main/common/cast.c
@@ -0,0 +1,412 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cast.c:
+ *
+ * The cast command is used in the monitor to cast or overlay a structure
+ * onto a block of memory to display that memory in the format specified
+ * by the structure. The structure definition is found in the file
+ * "structfile" in TFS. Valid types within structfile are
+ * char, char.c, char.x, short, short.x, long, long.x and struct name.
+ * Default format is decimal. The '.x' extension tells cast to print
+ * in hex and the '.c' extension tells cast to print the actual character.
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+
+#if INCLUDE_CAST
+
+static ulong memAddr;
+static int castDepth;
+
+#define OPEN_BRACE '{'
+#define CLOSE_BRACE '}'
+
+#define STRUCT_SEARCH 1
+#define STRUCT_DISPLAY 2
+#define STRUCT_ALLDONE 3
+#define STRUCT_ERROR 4
+
+#define STRUCT_SHOWPAD (1<<0)
+#define STRUCT_SHOWADD (1<<1)
+#define STRUCT_VERBOSE (1<<2)
+
+
+#define STRUCTFILE "structfile"
+
+struct mbrinfo {
+ char *type;
+ char *format;
+ int size;
+ int mode;
+};
+
+struct mbrinfo mbrinfotbl[] = {
+ { "char", "%d", 1 }, /* decimal */
+ { "char.x", "0x%02x", 1 }, /* hex */
+ { "char.c", "%c", 1 }, /* character */
+ { "short", "%d", 2 }, /* decimal */
+ { "short.x", "0x%04x", 2 }, /* hex */
+ { "long", "%ld", 4 }, /* decimal */
+ { "long.x", "0x%08lx", 4 }, /* hex */
+ { 0,0,0 }
+};
+
+/* castIndent():
+ * Used to insert initial whitespace based on the depth of the
+ * structure nesting.
+ */
+void
+castIndent(void)
+{
+ int i;
+
+ for(i=0;i<castDepth;i++)
+ printf(" ");
+}
+
+/* strAddr():
+ * Called by showStruct(). It will populate the incoming buffer pointer
+ * with either NULL or the ascii-hex representation of the current address
+ * pointer.
+ */
+char *
+strAddr(long flags, char *buf)
+{
+ if (flags & STRUCT_SHOWADD)
+ sprintf(buf,"0x%08lx: ",memAddr);
+ else
+ buf[0] = 0;
+ return(buf);
+}
+
+/* showStruct():
+ * The workhorse of cast. This function parses the structfile looking for
+ * the structure type; then it attempts to display the memory block that
+ * begins at memAddr as if it was the structure. Note that there is no
+ * pre-processing done to verify valid syntax of the structure definition.
+ */
+int
+showStruct(int tfd,long flags,char *structtype,char *structname,char *linkname)
+{
+ struct mbrinfo *mptr;
+ ulong curpos, nextlink;
+ int i, state, snl, retval, tblsize;
+ char line[96], addrstr[16], format[64];
+ char *cp, *eol, *type, *eotype, *name, *bracket, *eoname, tmp;
+
+ type = (char *)0;
+ retval = nextlink = 0;
+ curpos = tfsctrl(TFS_TELL,tfd,0);
+ tfsseek(tfd,0,TFS_BEGIN);
+ castIndent();
+ if (structname)
+ printf("struct %s %s:\n",structtype,structname);
+ else
+ printf("struct %s @0x%lx:\n",structtype,memAddr);
+ castDepth++;
+
+ state = STRUCT_SEARCH;
+ snl = strlen(structtype);
+
+ while(1) {
+ if (tfsgetline(tfd,line,sizeof(line)-1) == 0) {
+ printf("Structure definition '%s' not found\n",structtype);
+ break;
+ }
+ if ((line[0] == '\r') || (line[0] == '\n')) /* empty line? */
+ continue;
+
+ eol = strpbrk(line,";#\r\n");
+ if (eol)
+ *eol = 0;
+
+ if (state == STRUCT_SEARCH) {
+ if (!strncmp(line,"struct",6)) {
+ cp = line+6;
+ while(isspace(*cp))
+ cp++;
+ if (!strncmp(cp,structtype,snl)) {
+ cp += snl;
+ while(isspace(*cp))
+ cp++;
+ if (*cp == OPEN_BRACE)
+ state = STRUCT_DISPLAY;
+ else {
+ retval = -1;
+ break;
+ }
+ }
+ }
+ }
+ else if (state == STRUCT_DISPLAY) {
+ type = line;
+ while(isspace(*type))
+ type++;
+
+ if (*type == CLOSE_BRACE) {
+ state = STRUCT_ALLDONE;
+ break;
+ }
+
+ eotype = type;
+ while(!isspace(*eotype))
+ eotype++;
+ *eotype = 0;
+ name = eotype+1;
+ while(isspace(*name))
+ name++;
+ bracket = strchr(name,'[');
+ if (bracket)
+ tblsize = atoi(bracket+1);
+ else
+ tblsize = 1;
+
+ if (*name == '*') {
+ castIndent();
+ printf("%s%-8s %s: ",strAddr(flags,addrstr),type,name);
+ if (!strcmp(type,"char.c"))
+ printf("\"%s\"\n",*(char **)memAddr);
+ else
+ printf("0x%lx\n",*(ulong *)memAddr);
+ memAddr += 4;
+ continue;
+ }
+ mptr = mbrinfotbl;
+ while(mptr->type) {
+ if (!strcmp(type,mptr->type)) {
+ castIndent();
+ eoname = name;
+ while(!isspace(*eoname))
+ eoname++;
+ tmp = *eoname;
+ *eoname = 0;
+
+ if (bracket) {
+ if (!strcmp(type,"char.c")) {
+ printf("%s%-8s %s: ",
+ strAddr(flags,addrstr),mptr->type,name);
+ cp = (char *)memAddr;
+ for(i=0;i<tblsize && isprint(*cp);i++)
+ printf("%c",*cp++);
+ printf("\n");
+ }
+ else
+ printf("%s%-8s %s\n",
+ strAddr(flags,addrstr),mptr->type,name);
+ memAddr += mptr->size * tblsize;
+ }
+ else {
+ sprintf(format,"%s%-8s %%s: %s\n",
+ strAddr(flags,addrstr),mptr->type,mptr->format);
+ switch(mptr->size) {
+ case 1:
+ printf(format,name,*(uchar *)memAddr);
+ break;
+ case 2:
+ printf(format,name,*(ushort *)memAddr);
+ break;
+ case 4:
+ printf(format,name,*(ulong *)memAddr);
+ break;
+ }
+ memAddr += mptr->size;
+ }
+ *eoname = tmp;
+ break;
+ }
+ mptr++;
+ }
+ if (!(mptr->type)) {
+ int padsize;
+ char *subtype, *subname, *eossn;
+
+ if (!strcmp(type,"struct")) {
+ subtype = eotype+1;
+ while(isspace(*subtype))
+ subtype++;
+ subname = subtype;
+ while(!isspace(*subname))
+ subname++;
+ *subname = 0;
+
+ subname++;
+ while(isspace(*subname))
+ subname++;
+ eossn = subname;
+ while(!isspace(*eossn))
+ eossn++;
+ *eossn = 0;
+ if (*subname == '*') {
+ castIndent();
+ printf("%s%s %s %s: 0x%08lx\n",strAddr(flags,addrstr),
+ type,subtype,subname,*(ulong *)memAddr);
+ if (linkname) {
+ if (!strcmp(linkname,subname+1))
+ nextlink = *(ulong *)memAddr;
+ }
+ memAddr += 4;
+ }
+ else {
+ for (i=0;i<tblsize;i++) {
+ if (bracket)
+ sprintf(bracket+1,"%d]",i);
+ if (showStruct(tfd,flags,subtype,subname,0) < 0) {
+ state = STRUCT_ALLDONE;
+ goto done;
+ }
+ }
+ }
+ }
+ else if (!strncmp(type,"pad[",4)) {
+ padsize = atoi(type+4);
+ if (flags & STRUCT_SHOWPAD) {
+ castIndent();
+ printf("%spad[%d]\n",strAddr(flags,addrstr),padsize);
+ }
+ memAddr += padsize;
+ }
+ else {
+ retval = -1;
+ break;
+ }
+ }
+ }
+ else {
+ state = STRUCT_ERROR;
+ break;
+ }
+ }
+done:
+
+ switch(state) {
+ case STRUCT_SEARCH:
+ printf("struct %s not found\n",structtype);
+ retval = -1;
+ break;
+ case STRUCT_DISPLAY:
+ printf("invalid member type: %s\n",type);
+ retval = -1;
+ break;
+ case STRUCT_ERROR:
+ printf("unknown error\n");
+ retval = -1;
+ break;
+ }
+ tfsseek(tfd,curpos,TFS_BEGIN);
+ if (linkname)
+ memAddr = nextlink;
+ castDepth--;
+ return(retval);
+}
+
+char *CastHelp[] = {
+ "Cast a structure definition across data in memory.",
+ "-[al:n:pt:] {struct type} {address}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -a show addresses",
+ " -l{linkname}",
+ " -n{structname}",
+ " -p show padding",
+ " -t{tablename}",
+#endif
+ 0,
+};
+
+int
+Cast(int argc,char *argv[])
+{
+ long flags;
+ int opt, tfd, index;
+ char *structtype, *structfile, *tablename, *linkname, *name;
+
+ flags = 0;
+ name = (char *)0;
+ linkname = (char *)0;
+ tablename = (char *)0;
+ while((opt=getopt(argc,argv,"apl:n:t:")) != -1) {
+ switch(opt) {
+ case 'a':
+ flags |= STRUCT_SHOWADD;
+ break;
+ case 'l':
+ linkname = optarg;
+ break;
+ case 'n':
+ name = optarg;
+ break;
+ case 'p':
+ flags |= STRUCT_SHOWPAD;
+ break;
+ case 't':
+ tablename = optarg;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ if (argc != optind + 2)
+ return(CMD_PARAM_ERROR);
+
+ structtype = argv[optind];
+ memAddr = strtoul(argv[optind+1],0,0);
+
+ /* Start by detecting the presence of a structure definition file... */
+ structfile = getenv("STRUCTFILE");
+ if (!structfile)
+ structfile = STRUCTFILE;
+
+ tfd = tfsopen(structfile,TFS_RDONLY,0);
+ if (tfd < 0) {
+ printf("Structure definition file '%s' not found\n",structfile);
+ return(CMD_FAILURE);
+ }
+
+ index = 0;
+ do {
+ castDepth = 0;
+ showStruct(tfd,flags,structtype,name,linkname);
+ index++;
+ if (linkname)
+ printf("Link #%d = 0x%lx\n",index,memAddr);
+ if (tablename || linkname) {
+ if (askuser("next?")) {
+ if (tablename)
+ printf("%s[%d]:\n",tablename,index);
+ }
+ else
+ tablename = linkname = (char *)0;
+ }
+ } while(tablename || linkname);
+
+ tfsclose(tfd,0);
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/cf.c b/main/common/cf.c
new file mode 100644
index 0000000..a0cbcd9
--- /dev/null
+++ b/main/common/cf.c
@@ -0,0 +1,207 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cf.c:
+ * This code is the user interface portion of the cf (compact flash)
+ * command for uMon.
+ * This command is intended to be the "interface" portion of some
+ * other command (for example "fatfs"). Refer to the discussion in
+ * fatfs.c for more details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#if INCLUDE_CF
+#include "stddefs.h"
+#include "genlib.h"
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cf.h"
+
+
+char *CfHelp[] = {
+ "Compact Flash Interface",
+ "[options] {operation} [args]...",
+#if INCLUDE_VERBOSEHELP
+ "",
+ "Options:",
+ " -v enable verbosity",
+ "",
+ "Operations:",
+ " init [prefix]",
+ " read {dest} {blk} {blktot}",
+ " write {blk} {src} {blktot}",
+#endif
+ 0
+};
+
+static int cfInum; /* Interface number: to support multiple CF interfaces.
+ * Typically this will always be zero.
+ */
+
+int
+CfCmd(int argc, char *argv[])
+{
+ char *cmd, *buf, *prefix, varname[16];
+ int opt, verbose, cfret, blknum, blkcnt;
+
+ verbose = 0;
+ while ((opt=getopt(argc,argv,"i:r:w:v")) != -1) {
+ switch(opt) {
+ case 'i':
+ cfInum = atoi(optarg); /* sticky */
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind + 1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (strcmp(cmd,"init") == 0) {
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ prefix = argv[optind+1];
+ if (strlen(prefix)+4 > sizeof(varname)) {
+ printf("prefix %s too long\n",prefix);
+ return(CMD_PARAM_ERROR);
+ }
+
+ cfret = cfInit(cfInum,verbose);
+ if (cfret < 0) {
+ printf("cfInit returned %d\n",cfret);
+ return(CMD_FAILURE);
+ }
+
+ sprintf(varname,"%s_RD",prefix);
+ shell_sprintf(varname,"0x%lx",(long)cfRead);
+
+ sprintf(varname,"%s_WR",prefix);
+ shell_sprintf(varname,"0x%lx",(long)cfWrite);
+
+ shell_sprintf("CF_BLKSIZ","0x%lx",CF_BLKSIZE);
+
+ if (verbose) {
+ printf("read: 0x%lx, write: 0x%lx, blksiz: 0x%lx\n",
+ (long)cfRead,(long)cfWrite,(long)CF_BLKSIZE,verbose);
+ }
+ }
+ else if (strcmp(cmd,"read") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+
+ buf = (char *)strtoul(argv[optind+1],0,0);
+ blknum = strtoul(argv[optind+2],0,0);
+ blkcnt = strtoul(argv[optind+3],0,0);
+
+ cfret = cfRead(cfInum,buf,blknum,blkcnt,verbose);
+ if (cfret < 0) {
+ printf("cfRead returned %d\n",cfret);
+ return(CMD_FAILURE);
+ }
+ }
+ else if (strcmp(cmd,"write") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ buf = (char *)strtoul(argv[optind+1],0,0);
+ blknum = strtoul(argv[optind+2],0,0);
+ blkcnt = strtoul(argv[optind+3],0,0);
+
+ cfret = cfWrite(cfInum,buf,blknum,blkcnt,verbose);
+ if (cfret < 0) {
+ printf("cfWrite returned %d\n",cfret);
+ return(CMD_FAILURE);
+ }
+ }
+ else {
+ printf("cf op <%s> not found\n",cmd);
+ return(CMD_FAILURE);
+ }
+
+ return(CMD_SUCCESS);
+}
+
+#ifdef INCLUDE_CF_DUMMY_FUNCS
+/* This code is included here just for simulating the CF
+ * interface (temporarily if a real one isn't ready. In a real system,
+ * the INCLUDE_CF_DUMMY_FUNCS definition would be off.
+ */
+
+int
+cfInit(int interface, int verbose)
+{
+ if (interface != 0) {
+ if (verbose)
+ printf("cfInit bad interface %d\n",interface);
+ return(-1);
+ }
+
+ return(0);
+}
+
+int
+cfRead(int interface, char *buf, int blk, int blkcnt, int verbose)
+{
+ char *from;
+ int size;
+
+ if (interface != 0) {
+ if (verbose)
+ printf("cfRead bad interface %d\n",interface);
+ return(-1);
+ }
+
+ from = (char *)(blk * CF_BLKSIZE);
+ size = blkcnt * CF_BLKSIZE;
+ memcpy(buf,from,size);
+ return(0);
+}
+
+int
+cfWrite(int interface, char *buf, int blk, int blkcnt, int verbose)
+{
+ char *to;
+ int size;
+
+ if (interface != 0) {
+ if (verbose)
+ printf("cfWrite bad interface %d\n",interface);
+ return(-1);
+ }
+
+ to = (char *)(blk * CF_BLKSIZE);
+ size = blkcnt * CF_BLKSIZE;
+ memcpy(to,buf,size);
+ return(0);
+}
+
+#endif
+
+#endif
diff --git a/main/common/cf.h b/main/common/cf.h
new file mode 100644
index 0000000..64fbff7
--- /dev/null
+++ b/main/common/cf.h
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cf.h:
+ *
+ * Header file supporting compact flash command.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#ifndef CF_BLKSIZE
+#define CF_BLKSIZE 512
+#endif
+
+
+/* These two functions must be supplied by the port-specific code.
+ */
+int cfInit(int interface,int verbose);
+int cfRead(int interface,char *buf,int bknum,int bkcnt,int verbose);
+int cfWrite(int interface,char *buf,int bknum,int bkcnt,int verbose);
+
diff --git a/main/common/chario.c b/main/common/chario.c
new file mode 100644
index 0000000..fb8fbae
--- /dev/null
+++ b/main/common/chario.c
@@ -0,0 +1,543 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * chario.c:
+ * This code supports some basic character io functionality.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "timer.h"
+#include "ether.h"
+#include "fbi.h"
+
+#define CTLC 0x03 /* control-c */
+
+int rawmode, ConsoleBaudRate;
+
+/* extWatchDog():
+ * This function pointer is used by the application to override the
+ * monitor's configured watchdog functionality. Refer to config.h
+ * in umon_ports/template for more information on the WATCHDOG macro.
+ */
+#ifdef WATCHDOG_ENABLED
+int (*remoteWatchDog)(void);
+#endif
+
+/* remotexxxx() function pointers:
+ * These function pointers provide the application with the ability to
+ * override the monitor's default putchar/getchar/gotachar functions.
+ * See comments above InitRemoteIO() function below for more info.
+ */
+int (*remoterawon)(void);
+int (*remoterawoff)(void);
+int (*remoteputchar)(int);
+int (*remotegetchar)(void);
+int (*remotegotachar)(void);
+
+static char console_echo_off;
+
+/* console_echo():
+ * Enable/disable the output of the console...
+ */
+void
+console_echo(int enable)
+{
+ if (enable)
+ console_echo_off = 0;
+ else
+ console_echo_off = 1;
+}
+
+/* putchar():
+ * Output a character to the stdout RS232 port.
+ * If console_echo_off is set, then we DON'T send the
+ * character to the console.
+ */
+int
+putchar(char c)
+{
+ /* If the remoteputchar function pointer is non-zero, then we
+ * assume that the default putchar function has been overridden
+ * by some overlaying application using mon_com(CHARFUNC_PUTCHAR,),
+ * so we use that redefined function instead...
+ */
+ if (remoteputchar) {
+ remoteputchar(c);
+ return((int)c);
+ }
+
+ if (rawmode) {
+ if (!console_echo_off)
+ target_putchar(c);
+ fbi_putchar(c);
+ return((int)c);
+ }
+
+ /* If redirection is active, the redirect the character to a file
+ * in TFS. Note that if INCLUDE_REDIRECT is 0, then this function
+ * is NULL (see genlib.h).
+ */
+ RedirectCharacter(c);
+
+ /* Call the target-specific function that puts the character out on
+ * the console port (precede '\n' with '\r').
+ * For each call to target_putchar(), call SendIPMonChar so that if
+ * this output is generated by moncmd, it will be sent back to the
+ * moncmd client. Note that if INCLUDE_ETHERNET is 0, then the
+ * function SendIPMonChar is NULL (see ether.h).
+ */
+ if (c == '\n') {
+ SendIPMonChar('\r',0);
+ fbi_putchar('\r');
+ if (!console_echo_off)
+ target_putchar('\r');
+ }
+ SendIPMonChar(c,0);
+ if (!console_echo_off)
+ target_putchar(c);
+ fbi_putchar(c);
+ WATCHDOG_MACRO;
+ return((int)c);
+}
+
+int
+getchar(void)
+{
+ /* If the remotegetchar function pointer is non-zero, then we
+ * assume that the default getchar function has been overridden
+ * by some overlaying application using mon_com(CHARFUNC_GETCHAR,),
+ * so we use that redefined function instead...
+ */
+ if (remotegetchar)
+ return(remotegetchar());
+
+ while(!gotachar()) {
+ /* While waiting for an incoming character, call pollethernet()
+ * to process any incoming packets. Note that if INCLUDE_ETHERNET
+ * is 0 in config.h, then this function is NULL (see ether.h).
+ */
+ WATCHDOG_MACRO;
+ pollethernet();
+ }
+
+ return(target_getchar());
+}
+
+int
+gotachar(void)
+{
+ /* If the remotegotachar function pointer is non-zero, then we
+ * assume that the default gotachar function has been overridden
+ * by some overlaying application using mon_com(CHARFUNC_GOTACHAR,),
+ * so we use that redefined function instead...
+ */
+ if (remotegotachar)
+ return(remotegotachar());
+
+ fbi_cursor();
+ WATCHDOG_MACRO;
+ return(target_gotachar());
+}
+
+/* flush_console_out():
+ * Call this function to wait for the console UART to flush all outgoing
+ * characters. Note that this function has a timeout in the loop.
+ */
+void
+flush_console_out(void)
+{
+ int timeout = 0;
+
+ if (remoteputchar)
+ return;
+
+ while(timeout++ < 50000) {
+ if (target_console_empty()) {
+ monDelay(10);
+ break;
+ }
+ }
+}
+
+/* flush_console_in(void):
+ * While there is input queued up from the console,
+ * flush it to the bit bucket...
+ */
+void
+flush_console_in(void)
+{
+ while(gotachar())
+ getchar();
+}
+
+
+/* rawon() & rawoff():
+ * Used primarily by xmodem. When xmodem runs, it must be assured that
+ * the interface is in RAW mode. For the case of the monitor alone, it
+ * will always be in a raw mode. These functions are primarily for use
+ * when an application has re-loaded the serial driver and may have put
+ * it in a non-raw mode. The mon_com() calls CHARFUNC_RAWMODEON and
+ * CHARFUNC_RAWMODEOFF establish these pointers.
+ */
+void
+rawon(void)
+{
+ if (remoterawon)
+ remoterawon();
+ rawmode = 1;
+}
+
+void
+rawoff(void)
+{
+ if (remoterawoff)
+ remoterawoff();
+ rawmode = 0;
+}
+
+/* puts() & putstr():
+ * Two string-output functions.
+ * puts: normal "puts" as is available in standard c libs.
+ * putstr: same as "puts", but no ending newline.
+ */
+
+void
+putstr(char *string)
+{
+ while(*string) {
+ putchar(*string);
+ string++;
+ }
+}
+
+void
+puts(char *string)
+{
+ putstr(string);
+ putchar('\n');
+}
+
+
+/* getfullline():
+ * Basic line retrieval; but with a few options...
+ * This function is accessed through the getline_xx functions
+ * below.
+ * Args...
+ * buf: pointer to buffer to be used to place the incoming characters.
+ * max: size of the buffer.
+ * ledit: if set, then allow the line-editor to be used if ESC is input.
+ * timeout: if positive, then after 'timeout' number of seconds waiting
+ * per character, giveup.
+ * if negative, then after 'timeout' number of seconds waiting
+ * total, giveup.
+ * if zero, then wait forever.
+ * prefill: if set, prefill the buffer with that string and show the user.
+ * echo: if set, characters are echoed as they are entered.
+ */
+int
+getfullline(char *buf,int max,int ledit, int timeout,char *prefill, int echo)
+{
+ char *base;
+ struct elapsed_tmr tmr;
+ static unsigned char crlf;
+ int tot, idx, cumulativetimeout;
+
+ cumulativetimeout = 0;
+ tot = idx = 0;
+ base = buf;
+ max -= 1; /* Make sure there is space for the null terminator. */
+
+ if (prefill) {
+ strcpy(base,prefill);
+ tot = strlen(prefill);
+ putstr(prefill);
+ buf += tot;
+ idx = tot;
+ }
+
+ /* If the timeout parameter is negative, then assume that this is
+ * to be run with a cumulative timeout rather than a timeout that
+ * is re-started after each character...
+ */
+ if (timeout < 0) {
+ cumulativetimeout = 1;
+ timeout = abs(timeout);
+ }
+
+ for(;idx<max;idx++) {
+ if (timeout > 0) {
+ startElapsedTimer(&tmr,timeout);
+ while(!msecElapsed(&tmr)) {
+ if (gotachar())
+ break;
+ pollethernet();
+ }
+ if (cumulativetimeout)
+ timeout = msecRemaining(&tmr);
+
+ if (ELAPSED_TIMEOUT(&tmr)) {
+ *buf = 0;
+ return(-1); /* Return negative to indicate timeout */
+ }
+ }
+ if (cumulativetimeout && timeout == 0) {
+ *buf = 0;
+ return(-1);
+ }
+
+ *buf = (char)getchar();
+
+ if (getenv("CLI_HEXOUT"))
+ printf("<%02x>",*buf);
+
+ if (!*buf) {
+ idx--;
+ continue;
+ }
+#if INCLUDE_LINEEDIT
+ if ((*buf == 0x1b) && (ledit)) {
+ (void)line_edit(base);
+ break;
+ }
+ else
+#endif
+ {
+ if ((*buf == '\r') || (*buf == '\n')) {
+ if ((crlf) && (*buf != crlf)) {
+ crlf = 0;
+ continue;
+ }
+ puts("\r");
+ crlf = *buf;
+ *buf = 0;
+ break;
+ }
+ if (*buf == '\b' || *buf == 0x7f) {
+ if (tot) {
+ idx -= 2;
+ buf--;
+ tot--;
+ if (echo)
+ putstr("\b \b");
+ }
+ }
+ else if (*buf == CTLC) {
+ puts("^C");
+ *base = 0;
+ return(0);
+ }
+ else {
+ if (echo)
+ putchar(*buf);
+ tot++;
+ buf++;
+ }
+ crlf = 0;
+ }
+ }
+ if (idx == max) {
+ printf((char *)"\007\nInput too long (exceeds %d bytes).\n",max);
+ *buf = 0;
+ return(0);
+ }
+#if INCLUDE_LINEEDIT
+ if (ledit)
+ historylog(base);
+#endif
+ return(strlen(base));
+}
+
+int
+getline(char *buf, int max, int ledit)
+{
+ return(getfullline(buf,max,ledit,0,0,1));
+}
+
+int
+getline_t(char *buf, int max, int timeout)
+{
+ return(getfullline(buf,max,0,timeout,0,1));
+}
+
+int
+getline_p(char *buf, int max, int ledit, char *prefill)
+{
+ return(getfullline(buf,max,ledit,0,prefill,1));
+}
+
+/* getpass():
+ */
+#if INCLUDE_USRLVL
+char *
+getpass(char *prompt,char *buf,int max, int timeout)
+{
+ putstr(prompt);
+ if (getfullline(buf,max,0,timeout*1000,0,0) == -1)
+ putchar('\n');
+ return(buf);
+}
+#endif
+
+/* getbytes():
+ * Similar to gets() except that the caller specifies the number
+ * of characters and whether or not to block.
+ * If the copy to the buffer fails, abort and return the current
+ * count.
+ */
+
+int
+getbytes(char *buf,int cnt,int block)
+{
+ int i;
+ volatile char *bp;
+ char c;
+
+ bp = (volatile char *)buf;
+
+ for(i=0;i<cnt;i++) {
+ if (!block && !gotachar())
+ break;
+ c = (char)getchar();
+ *bp = c;
+ if (*bp != c)
+ break;
+ bp++;
+ }
+ return(i);
+}
+
+/* getbytes_t():
+ * Similar to getbytes() except that the caller specifies the allowed
+ * timeout between two consecutive bytes received.
+ * If the copy to the buffer fails, or timeout occures, abort and return
+ * the current count.
+ */
+
+int
+getbytes_t(char *buf,int cnt,int timeout)
+{
+ int i;
+ struct elapsed_tmr tmr;
+ volatile char *bp;
+ char c;
+
+ bp = (volatile char *)buf;
+
+ for(i=0;i<cnt;i++) {
+ if (!gotachar()) {
+ startElapsedTimer(&tmr,timeout);
+ while(!gotachar() && !msecElapsed(&tmr));
+ if (!gotachar())
+ break;
+ }
+ c = (char)getchar();
+ *bp = c;
+ if (*bp != c)
+ break;
+ bp++;
+ }
+ return(i);
+}
+
+int
+putbytes(char *buf, int cnt)
+{
+ char *end;
+
+ end = buf + cnt;
+
+ while(buf < end) {
+ putchar(*buf++);
+ }
+ return(cnt);
+}
+
+int
+askuser(char *msg)
+{
+ int yes, len;
+
+#if INCLUDE_MONCMD
+ /* If command was issued from UDP (i.e. moncmd), then
+ * immediately return 1...
+ */
+ if (IPMonCmdActive)
+ return(1);
+#endif
+
+ putstr(msg);
+ len = strlen(msg);
+ switch((char)getchar()) {
+ case ' ':
+ case 'y':
+ case '\r':
+ case '\n':
+ yes = 1;
+ break;
+ default:
+ yes = 0;
+ break;
+ }
+ while(len) {
+ putstr("\b \b");
+ len--;
+ }
+ return(yes);
+}
+
+int
+More(void)
+{
+ return(askuser((char *)"more?"));
+}
+
+int
+hitakey(void)
+{
+ return(askuser((char *)"hit any key to continue..."));
+}
+
+/* RemoteIO functions:
+ * The idea of "remote io" is to allow the monitor commands to still
+ * run when the application has taken over the system. The monitor's
+ * connection to the serial port is a simple polled interface. When
+ * the application comes up, it is very likely that it will overlay a
+ * new driver onto the serial port. If this happens, and the user at
+ * the console interface of the application wants to execute a monitor
+ * command, then the monitor's putchar/getchar/gotachar functions must
+ * use functions that are part of the application. These remote io
+ * function pointers, if set, will point to those functions.
+ */
+
+void
+InitRemoteIO(void)
+{
+ /* Null out the remote put/getchar functions. */
+ remoterawon = 0;
+ remoterawoff = 0;
+ remoteputchar = 0;
+ remotegetchar = 0;
+ remotegotachar = 0;
+}
diff --git a/main/common/cli.h b/main/common/cli.h
new file mode 100644
index 0000000..9b661c6
--- /dev/null
+++ b/main/common/cli.h
@@ -0,0 +1,130 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cli.h:
+ *
+ * Header file for Command Line Interface related stuff.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _CLI_H_
+#define _CLI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Command table structure used by the monitor:
+ */
+struct monCommand {
+ char *name; /* Name of command seen by user. */
+ int (*func)(int,char **); /* Called when command is invoked. */
+ char **helptxt; /* Help text (see notes below). */
+ long flags; /* Single-bit flags for various uses */
+ /* (see the CMDFLAG_XXX macros). */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Bits currently assigned to command flags used in the monCommand
+ * structure...
+ */
+#define CMDFLAG_NOMONRC 1
+
+/* Maximum size of a command line:
+ */
+#ifndef CMDLINESIZE
+#define CMDLINESIZE 256
+#endif
+
+/* Maximum number of arguments in a command line:
+ */
+#define ARGCNT 24
+
+/* Definitions for docommand() return values:
+ *
+ * Note that the CMD_SUCCESS, CMD_FAILURE and CMD_PARAM_ERROR are return
+ * values used by the local command code also. The remaining errors
+ * (CMD_LINE_ERROR, CMD_ULVL_DENIED and CMD_NOT_FOUND) are used only by
+ # the docommand() function.
+ *
+ * CMD_SUCCESS:
+ * Everything worked ok.
+ * CMD_FAILURE:
+ * Command parameters were valid, but command itself failed for some other
+ * reason. The docommand() function does not print a message here, it
+ * is assumed that the error message was printed by the local function.
+ * CMD_PARAM_ERROR:
+ * Command line did not parse properly. Control was passed to a
+ * local command function, but argument syntax caused it to choke.
+ * In this case docommand() will print out the generic CLI syntax error
+ * message.
+ * CMD_LINE_ERROR:
+ * Command line itself was invalid. Too many args, invalid shell var
+ * syntax, etc.. Somekind of command line error prior to checking for
+ * the command name-to-function match.
+ * CMD_ULVL_DENIED:
+ * Command's user level is higher than current user level, so access
+ * is denied.
+ * CMD_NOT_FOUND:
+ * Since these same return values are used for each command function
+ * plus the docommand() function, this error indicates that docommand()
+ * could not even find the command in the command table.
+ * CMD_MONRC_DENIED:
+ * The command cannot execute because it is considered illegal
+ * when run from within the monrc file.
+ */
+#define CMD_SUCCESS 0
+#define CMD_FAILURE -1
+#define CMD_PARAM_ERROR -2
+#define CMD_LINE_ERROR -3
+#define CMD_ULVL_DENIED -4
+#define CMD_NOT_FOUND -5
+#define CMD_MONRC_DENIED -6
+
+/* Notes on help text array:
+ * The monitor's CLI processor assumes that every command's help text
+ * array abides by a few basic rules...
+ * First of all, it assumes that every array has AT LEAST two strings.
+ * The first string in the array of strings is assumed to be a one-line
+ * abstract describing the command.
+ * The second string in the array of strings is assumed to be a usage
+ * message that describes the syntax of the arguments needed by the command.
+ * If this second string is an empty string (""), the docommand() prints out
+ * a generic usage string indicating that there are no options or arguements
+ * to apply to the command.
+ * All remaining lines are formatted based on the needs of the individual
+ * command and the final string is a null pointer to let the CLI processor
+ * know where the end is.
+ * Following is an example help text array...
+ *
+ * char *HelpHelp[] = {
+ * "Display command set",
+ * "-[d] [commandname]",
+ * "Options:",
+ * " -d list commands and descriptions",
+ * 0,
+ * };
+ *
+ */
+#endif
diff --git a/main/common/cmdtbl.c b/main/common/cmdtbl.c
new file mode 100644
index 0000000..e2010c0
--- /dev/null
+++ b/main/common/cmdtbl.c
@@ -0,0 +1,484 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cmdtbl.c:
+ * This is the command table used by the monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+#include "genlib.h"
+#include "xcmddcl.h"
+
+#define ULVLCMD "ulvl"
+
+#if INCLUDE_MEMCMDS
+#define INCLUDE_PM 1
+#define INCLUDE_DM 1
+#define INCLUDE_FM 1
+#define INCLUDE_CM 1
+#define INCLUDE_SM 1
+#define INCLUDE_MT 1
+#endif
+
+extern int Arp(int, char **);
+extern int BbcCmd(int, char **);
+extern int BinfoCmd(int, char **);
+extern int BmemCmd(int, char **);
+extern int Call(int, char **);
+extern int Cast(int, char **);
+extern int Cm(int, char **);
+extern int CfCmd(int, char **);
+extern int Dis(int, char **);
+extern int Dm(int, char **);
+extern int Dhcp(int, char **);
+extern int DnsCmd(int, char **);
+extern int Echo(int, char **);
+extern int Edit(int, char **);
+extern int Ether(int, char **);
+extern int Exit(int, char **);
+extern int FatfsCmd(int, char **);
+extern int FbiCmd(int, char **);
+extern int FlashCmd(int, char **);
+extern int Fm(int, char **);
+extern int Gdb(int, char **);
+extern int Goto(int, char **);
+extern int Gosub(int, char **);
+extern int Heap(int, char **);
+extern int Help(int, char **);
+extern int History(int, char **);
+extern int Icmp(int, char **);
+extern int Ide(int, char **);
+extern int I2cCmd(int, char **);
+extern int If(int, char **);
+extern int Igmp(int, char **);
+extern int Item(int, char **);
+extern int Jffs2Cmd(int, char **);
+extern int Mt(int, char **);
+extern int MtraceCmd(int, char **);
+extern int Pm(int, char **);
+extern int Prof(int, char **);
+extern int Read(int, char **);
+extern int Reg(int, char **);
+extern int Reset(int, char **);
+extern int Return(int, char **);
+extern int SdCmd(int, char **);
+extern int Set(int, char **);
+extern int Sleep(int, char **);
+extern int Sm(int, char **);
+extern int SpifCmd(int, char **);
+extern int Strace(int, char **);
+extern int StructCmd(int, char **);
+extern int SyslogCmd(int, char **);
+extern int Tfs(int, char **);
+extern int Tftp(int, char **);
+extern int TsiCmd(int, char **);
+extern int Ulvl(int, char **);
+extern int Unzip(int, char **);
+extern int Version(int, char **);
+extern int WhatCmd(int, char **);
+extern int Xmodem(int, char **);
+
+extern char *ArpHelp[];
+extern char *BbcHelp[];
+extern char *BinfoHelp[];
+extern char *BmemHelp[];
+extern char *CallHelp[];
+extern char *CastHelp[];
+extern char *CfHelp[];
+extern char *CmHelp[];
+extern char *DisHelp[];
+extern char *DhcpHelp[];
+extern char *DmHelp[];
+extern char *DnsHelp[];
+extern char *EchoHelp[];
+extern char *EditHelp[];
+extern char *EtherHelp[];
+extern char *ExitHelp[];
+extern char *FatfsHelp[];
+extern char *FbiHelp[];
+extern char *FlashHelp[];
+extern char *FmHelp[];
+extern char *GdbHelp[];
+extern char *GosubHelp[];
+extern char *GotoHelp[];
+extern char *HelpHelp[];
+extern char *HeapHelp[];
+extern char *HistoryHelp[];
+extern char *IcmpHelp[];
+extern char *IdeHelp[];
+extern char *I2cHelp[];
+extern char *IfHelp[];
+extern char *IgmpHelp[];
+extern char *ItemHelp[];
+extern char *Jffs2Help[];
+extern char *MtHelp[];
+extern char *MtraceHelp[];
+extern char *PmHelp[];
+extern char *ProfHelp[];
+extern char *ReadHelp[];
+extern char *RegHelp[];
+extern char *ResetHelp[];
+extern char *ReturnHelp[];
+extern char *SdHelp[];
+extern char *SetHelp[];
+extern char *SleepHelp[];
+extern char *SmHelp[];
+extern char *SpifHelp[];
+extern char *StraceHelp[];
+extern char *StructHelp[];
+extern char *SyslogHelp[];
+extern char *TfsHelp[];
+extern char *TftpHelp[];
+extern char *TsiHelp[];
+extern char *UlvlHelp[];
+extern char *UnzipHelp[];
+extern char *VersionHelp[];
+extern char *WhatHelp[];
+extern char *XmodemHelp[];
+
+struct monCommand cmdlist[] = {
+#if INCLUDE_ETHERNET
+ { "arp", Arp, ArpHelp, CMDFLAG_NOMONRC },
+#endif
+#if INCLUDE_BBC
+ { "bbc", BbcCmd, BbcHelp, 0 },
+#endif
+#if INCLUDE_BMEM
+ { "bmem", BmemCmd, BmemHelp, 0 },
+#endif
+#if INCLUDE_BOARDINFO
+ { "brdinfo", BinfoCmd, BinfoHelp, 0 },
+#endif
+ { "call", Call, CallHelp, CMDFLAG_NOMONRC },
+#if INCLUDE_CAST
+ { "cast", Cast, CastHelp, 0 },
+#endif
+#if INCLUDE_CF
+ { "cf", CfCmd, CfHelp, 0 },
+#endif
+#if INCLUDE_CM
+ { "cm", Cm, CmHelp, 0 },
+#endif
+#if INCLUDE_DHCPBOOT
+ { "dhcp", Dhcp, DhcpHelp, CMDFLAG_NOMONRC },
+#endif
+#if INCLUDE_DISASSEMBLER
+ { "dis", Dis, DisHelp, 0 },
+#endif
+#if INCLUDE_DM
+ { "dm", Dm, DmHelp, 0 },
+#endif
+#if INCLUDE_DNS
+ { "dns", DnsCmd, DnsHelp, 0 },
+#endif
+#if INCLUDE_TFSSCRIPT
+ { "echo", Echo, EchoHelp, 0 },
+#endif
+#if INCLUDE_EDIT
+ { "edit", Edit, EditHelp, 0 },
+#endif
+#if INCLUDE_ETHERNET
+ { "ether", Ether, EtherHelp, CMDFLAG_NOMONRC },
+#endif
+#if INCLUDE_TFSSCRIPT
+ { "exit", Exit, ExitHelp, 0 },
+#endif
+#if INCLUDE_FATFS
+ { "fatfs", FatfsCmd, FatfsHelp, 0 },
+#endif
+#if INCLUDE_FBI
+ { "fbi", FbiCmd, FbiHelp, 0 },
+#endif
+#if INCLUDE_FLASH
+ { "flash", FlashCmd, FlashHelp, 0 },
+#endif
+#if INCLUDE_FM
+ { "fm", Fm, FmHelp, 0 },
+#endif
+
+#if INCLUDE_GDB
+ { "gdb", Gdb, GdbHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_TFSSCRIPT
+ { "gosub", Gosub, GosubHelp, 0 },
+ { "goto", Goto, GotoHelp, 0 },
+#endif
+
+#if INCLUDE_MALLOC
+ { "heap", Heap, HeapHelp, 0 },
+#endif
+
+ { "help", Help, HelpHelp, 0 },
+ { "?", Help, HelpHelp, 0 },
+
+#if INCLUDE_LINEEDIT
+ { "history", History, HistoryHelp, 0 },
+#endif
+
+#if INCLUDE_I2C
+ { "i2c", I2cCmd, I2cHelp, 0 },
+#endif
+
+#if INCLUDE_ICMP
+ { "icmp", Icmp, IcmpHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_IDE
+ { "ide", Ide, IdeHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_IGMP
+ { "igmp", Igmp, IgmpHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_TFSSCRIPT
+ { "if", If, IfHelp, 0 },
+#endif
+
+#if INCLUDE_TFSSCRIPT
+ { "item", Item, ItemHelp, 0 },
+#endif
+
+#if INCLUDE_JFFS2
+ { "jffs2", Jffs2Cmd, Jffs2Help, 0 },
+#endif
+
+#if INCLUDE_MT
+ { "mt", Mt, MtHelp, 0 },
+#endif
+
+#if INCLUDE_MEMTRACE
+ { "mtrace", MtraceCmd, MtraceHelp, 0 },
+#endif
+
+#if INCLUDE_PM
+ { "pm", Pm, PmHelp, 0 },
+#endif
+
+#if INCLUDE_PROFILER
+ { "prof", Prof, ProfHelp, 0 },
+#endif
+
+#if INCLUDE_TFSSCRIPT
+ { "read", Read, ReadHelp, 0 },
+#endif
+
+#if INCLUDE_STRACE
+ { "reg", Reg, RegHelp, 0 },
+#endif
+
+ { "reset", Reset, ResetHelp, 0 },
+
+#if INCLUDE_TFSSCRIPT
+ { "return", Return, ReturnHelp, 0 },
+#endif
+#if INCLUDE_SD
+ { "sd", SdCmd, SdHelp, 0 },
+#endif
+
+ { "set", Set, SetHelp, 0 },
+
+#if INCLUDE_TFSSCRIPT
+ { "sleep", Sleep, SleepHelp, 0 },
+#endif
+
+#if INCLUDE_SM
+ { "sm", Sm, SmHelp, 0 },
+#endif
+
+#if INCLUDE_SPIF
+ { "spif", SpifCmd, SpifHelp, 0 },
+#endif
+
+#if INCLUDE_STRACE
+ { "strace", Strace, StraceHelp, 0 },
+#endif
+
+#if INCLUDE_STRUCT
+ { "struct", StructCmd, StructHelp, 0 },
+#endif
+
+#if INCLUDE_SYSLOG
+ { "syslog", SyslogCmd, SyslogHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_USRLVL
+ { ULVLCMD, Ulvl, UlvlHelp, 0 },
+#endif
+
+#if INCLUDE_TFTP
+ { "tftp", Tftp, TftpHelp, CMDFLAG_NOMONRC },
+#endif
+
+#if INCLUDE_TFSCLI
+ { "tfs", Tfs, TfsHelp, 0 },
+#endif
+
+#if INCLUDE_TSI
+ { "tsi", TsiCmd, TsiHelp, 0 },
+#endif
+
+#if INCLUDE_UNZIP
+ { "unzip", Unzip, UnzipHelp, 0 },
+#endif
+
+#if INCLUDE_XMODEM
+ { "xmodem", Xmodem, XmodemHelp, 0 },
+#endif
+
+ { "version", Version, VersionHelp, 0 },
+
+#if INCLUDE_TFS
+ { "what", WhatCmd, WhatHelp, 0 },
+#endif
+
+#include "xcmdtbl.h" /* For non-generic commands that are */
+ /* specific to a particular target. */
+ { 0,0,0,0 },
+};
+
+#if INCLUDE_USRLVL
+
+/* cmdUlvl[]:
+ * This table stores one char per command that contains that command's
+ * user level. The default user level of all commands is 0, but can
+ * be re-defined by the ulvl -c command.
+ */
+char cmdUlvl[(sizeof(cmdlist)/sizeof(struct monCommand))];
+
+/* setCmdUlvl():
+ * The incoming string is a command name followed by a comma and a user
+ * level (ranging from 0 thru 4).
+ * Return 0 if pass, 1 if new level was user-level rejected, -1 if error.
+ */
+int
+setCmdUlvl(char *cmdlvl, int verbose)
+{
+ extern char *appcmdUlvl;
+ extern struct monCommand *appCmdlist;
+ struct monCommand *cptr;
+ int newlevel, idx, pass, doall;
+ char *comma, *lvlptr, buffer[32], *cmdandlevel;
+
+ /* Make a copy of the incoming string so that we can
+ * modify it...
+ */
+ if (strlen(cmdlvl) > (sizeof(buffer)-1))
+ goto showerr;
+
+ strcpy(buffer,cmdlvl);
+ cmdandlevel = buffer;
+
+ /* First verify that the comma is in the string... */
+ comma = strchr(cmdandlevel,',');
+ if (!comma)
+ goto showerr;
+
+ /* Retrieve and verify the new level to be assigned...
+ * If the level value is the string "off", then we assign a level
+ * value that is greater than MAXUSRLEVEL so that the command is
+ * essentially disabled as a built-in.
+ */
+ if (strcmp(comma+1,"off") == 0) {
+ newlevel = MAXUSRLEVEL+1;
+ }
+ else {
+ newlevel = atoi(comma+1);
+ if ((newlevel < MINUSRLEVEL) || (newlevel > MAXUSRLEVEL))
+ goto showerr;
+ }
+
+ *comma = 0;
+
+ /* Don't allow adjustment of the ulvl command itself. It must be
+ * able to run as user level 0 all the time...
+ */
+ if (!strcmp(cmdandlevel,ULVLCMD)) {
+ printf("Can't adjust '%s' user level.\n",ULVLCMD);
+ return(-1);
+ }
+
+ if (appCmdlist) {
+ pass = 0;
+ cptr = appCmdlist;
+ lvlptr = appcmdUlvl;
+ }
+ else {
+ pass = 1;
+ cptr = cmdlist;
+ lvlptr = cmdUlvl;
+ }
+
+ /* If the command string is "ALL" then we set all commands
+ * to the requested level.
+ */
+ if (!strcmp(cmdandlevel,"ALL"))
+ doall = 1;
+ else
+ doall = 0;
+
+ while(pass < 2) {
+ if ((cptr == cmdlist) && (cmdandlevel[0] == '_'))
+ cmdandlevel++;
+
+ /* Find the command in the table that is to be adjusted... */
+ for(idx=0;cptr->name;cptr++,idx++) {
+ if (doall || (!strcmp(cmdandlevel,cptr->name))) {
+ /* Even with doall set, we don't want to touch
+ * the ULVLCMD level...
+ */
+ if (doall && !strcmp(cptr->name,ULVLCMD))
+ continue;
+
+ /* If the command's user level is to be lowered, then the
+ * current monitor userlevel must be at least as high as the
+ * command's current user level...
+ */
+ if ((newlevel < lvlptr[idx]) && (getUsrLvl() < lvlptr[idx])) {
+ if (verbose)
+ printf("User-level access denied: %s\n",cmdandlevel);
+ return(1);
+ }
+ lvlptr[idx] = newlevel;
+ if (!doall)
+ return(0);
+ }
+ }
+ cptr = cmdlist;
+ lvlptr = cmdUlvl;
+ pass++;
+ }
+
+ if (doall)
+ return(0);
+
+showerr:
+ if (verbose)
+ printf("Input error: %s\n",cmdlvl);
+ return(-1);
+}
+
+#endif
diff --git a/main/common/coff.h b/main/common/coff.h
new file mode 100644
index 0000000..f324e73
--- /dev/null
+++ b/main/common/coff.h
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * coff.h:
+ *
+ * Header file used for the COFF file format of TFS.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _COFF_H_
+#define _COFF_H_
+
+/* File header... */
+struct filehdr {
+ unsigned short f_magic; /* magic number */
+ unsigned short f_nscns; /* number of sections */
+ long f_timdat; /* time & date stamp */
+ long f_symptr; /* file pointer to symtab */
+ long f_nsyms; /* number of symtab entries */
+ unsigned short f_opthdr; /* sizeof(optional hdr) */
+ unsigned short f_flags; /* flags */
+};
+
+#define FILHDR struct filehdr
+#define FILHSZ sizeof(FILHDR)
+#define F_EXEC 0000002
+
+/* Optional header... */
+struct aouthdr {
+ short magic;
+ short vstamp; /* version stamp */
+ long tsize; /* text size in bytes, padded to FW
+ bdry */
+ long dsize; /* initialized data " " */
+ long bsize; /* uninitialized data " " */
+ long entry; /* entry pt. */
+ long text_start; /* base of text used for this file */
+ long data_start; /* base of data used for this file */
+};
+
+#define AOUTHDR struct aouthdr
+#define AOUTHSZ sizeof(AOUTHDR)
+
+struct scnhdr {
+ char s_name[8]; /* section name */
+ long s_paddr; /* physical address */
+ long s_vaddr; /* virtual address */
+ long s_size; /* section size */
+ long s_scnptr; /* file ptr to raw data for section */
+ long s_relptr; /* file ptr to relocation */
+ long s_lnnoptr; /* file ptr to line numbers */
+ unsigned short s_nreloc; /* number of relocation entries */
+ unsigned short s_nlnno; /* number of line number entries */
+ long s_flags; /* flags */
+};
+
+#define SCNHDR struct scnhdr
+#define SCNHSZ sizeof(SCNHDR)
+
+/*
+ * The low 4 bits of s_flags is used as a section "type"
+ */
+
+#define STYP_REG 0x00 /* "regular" section:
+ allocated, relocated, loaded */
+#define STYP_DSECT 0x01 /* "dummy" section:
+ not allocated, relocated,
+ not loaded */
+#define STYP_NOLOAD 0x02 /* "noload" section:
+ allocated, relocated,
+ not loaded */
+#define STYP_GROUP 0x04 /* "grouped" section:
+ formed of input sections */
+#define STYP_PAD 0x08 /* "padding" section:
+ not allocated, not relocated,
+ loaded */
+#define STYP_COPY 0x10 /* "copy" section:
+ for decision function used
+ by field update; not
+ allocated, not relocated,
+ loaded; reloc & lineno
+ entries processed normally */
+#define STYP_TEXT 0x20 /* section contains text only */
+#define STYP_DATA 0x40 /* section contains data only */
+#define STYP_BSS 0x80 /* section contains bss only */
+#define STYP_INFO 0x0200
+#define STYP_LIT 0x8020
+#define STYP_ABS 0x4000
+#define STYP_BSSREG 0x1200
+#define STYP_ENVIR 0x2200
+
+#define ISLOADABLE(flags) \
+ (flags & (STYP_ABS | STYP_TEXT | STYP_LIT | STYP_DATA))
+#define ISBSS(flags) (flags & (STYP_BSS))
+#define ISTEXT(flags) (flags & (STYP_TEXT))
+#endif
diff --git a/main/common/cstart.c b/main/common/cstart.c
new file mode 100644
index 0000000..260c9b3
--- /dev/null
+++ b/main/common/cstart.c
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cstart.c:
+ * This is the first 'C' code exececuted by the processor after a reset if
+ * the monitor is built to boot and copy itself into RAM.
+ *
+ * This 2-stage monitor is done with two distinct images.
+ * The first image (the real "boot" image) includes this cstart() code
+ * in place of normal start(). The make process generates the umon.c file
+ * included below. This file is essentially a C-array that consists of
+ * the binary image (second image) of a version of the monitor that is
+ * built to run out of RAM. The value of UMON_RAMBASE is the base address
+ * of this image and the value of UMON_START is the entry point into this
+ * image.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "cpu.h"
+
+#ifdef ROM_MONSTACKSIZE
+ulong MonStack[ROM_MONSTACKSIZE/4];
+#endif
+
+/* The umon.c file is simply an array that contains the monitor
+ * image and the necessary information needed to do the copy.
+ */
+#include "umon.c"
+
+char *
+memcpy(char *to,char *from,int count)
+{
+ char *to_copy, *end;
+
+ to_copy = to;
+
+ /* If count is greater than 8, get fancy, else just do byte-copy... */
+ if (count > 8) {
+ /* Attempt to optimize the transfer here... */
+ if (((int)to & 3) && ((int)from & 3)) {
+ /* If from and to pointers are both unaligned to the
+ * same degree then we can do a few char copies to get them
+ * 4-byte aligned and then do a lot of 4-byte aligned copies.
+ */
+ if (((int)to & 3) == ((int)from & 3)) {
+ while((int)to & 3) {
+ *to++ = *from++;
+ count--;
+ }
+ }
+ /* If from and to pointers are both odd, but different, then
+ * we can increment them both by 1 and do a bunch of 2-byte
+ * aligned copies...
+ */
+ else if (((int)to & 1) && ((int)from & 1)) {
+ *to++ = *from++;
+ count--;
+ }
+ }
+
+ /* If both pointers are now 4-byte aligned or 2-byte aligned,
+ * take advantage of that here...
+ */
+ if (!((int)to & 3) && !((int)from & 3)) {
+ end = to + (count & ~3);
+ count = count & 3;
+ while(to < end) {
+ *(ulong *)to = *(ulong *)from;
+ from += 4;
+ to += 4;
+ }
+ }
+ else if (!((int)to & 1) && !((int)from & 1)) {
+ end = to + (count & ~1);
+ count = count & 1;
+ while(to < end) {
+ *(ushort *)to = *(ushort *)from;
+ from += 2;
+ to += 2;
+ }
+ }
+ }
+
+ if (count) {
+ end = to + count;
+ while(to < end)
+ *to++ = *from++;
+ }
+ return(to_copy);
+}
+
+void
+cstart(void)
+{
+ register long *lp1, *lp2, *end2;
+ void (*entry)();
+
+ entry = (void(*)())UMON_START;
+
+ /* Copy image from boot flash to RAM, then verify the copy.
+ * If it worked, then jump into that space; else reset and start
+ * over (not much else can be done!).
+ */
+ memcpy((char *)UMON_RAMBASE,(char *)umon,(int)sizeof(umon));
+
+ /* Verify the copy...
+ */
+ lp1 = (long *)UMON_RAMBASE;
+ lp2 = (long *)umon;
+ end2 = lp2 + (int)sizeof(umon)/sizeof(long);
+ while(lp2 < end2) {
+ if (*lp1 != *lp2) {
+#ifdef CSTART_ERROR_FUNCTION
+ extern void CSTART_ERROR_FUNCTION();
+
+ CSTART_ERROR_FUNCTION(lp1,*lp1,*lp2);
+#endif
+#ifdef INLINE_RESETFUNC
+ INLINE_RESETFUNC();
+#else
+ entry = RESETFUNC();
+#endif
+ break;
+ }
+ lp1++; lp2++;
+ }
+ entry();
+}
diff --git a/main/common/dallasdate.c b/main/common/dallasdate.c
new file mode 100644
index 0000000..31af955
--- /dev/null
+++ b/main/common/dallasdate.c
@@ -0,0 +1,362 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dallasdate.c:
+ *
+ * Code to support the DALLAS DS1743W Timekeeping RAM plus the hooks to
+ * allow TFS to timestamp files. The function tfsTimeEnable() must be
+ * called to setup the connection between TFS and the DS1743W.
+ *
+ * Applicable to DS1743W and DS1746WP. Probably also works with other
+ * Dallas timekeepers, but the above two are the only ones I've tested
+ * it with. This code is assumed to be compiled with the DATEREGBASE
+ * value defined elsewhere. This value is the address at which the code
+ * is to access the 8-byte register map that contains the time/date
+ * information.
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+
+#ifndef DATEREGBASE
+#error DATEREGBASE not defined
+#endif
+
+#define WRITE 0x80 /* part of 'cent' member */
+#define READ 0x40 /* part of 'cent' member */
+#define FT 0x40 /* part of 'wday' member */
+#define OSC_OFF 0x80 /* part of 'sec' member */
+
+/* Masks for various portions of the time/date... */
+#define YEAR10_MASK 0xf0
+#define MONTH10_MASK 0x10
+#define DATE10_MASK 0x30
+#define DAY10_MASK 0x00
+#define HOUR10_MASK 0x30
+#define MINUTE10_MASK 0x70
+#define SECOND10_MASK 0x70
+#define CENTURY10_MASK 0x30
+#define YEAR_MASK 0x0f /* Year is 0-99 */
+#define MONTH_MASK 0x0f /* Month is 1-12 */
+#define DATE_MASK 0x0f /* Date is 1-31 */
+#define DAY_MASK 0x07 /* Day is 1-7 */
+#define HOUR_MASK 0x0f /* Hour is 0-23 */
+#define MINUTE_MASK 0x0f /* Minutes is 0-59 */
+#define SECOND_MASK 0x0f /* Seconds is 0-59 */
+#define CENTURY_MASK 0x0f /* Century is 0-39 */
+
+struct dsdate {
+ uchar cent; /* B7=W, B6=R, B5-4=10cent, B3-0=cent (00-39) */
+ uchar sec; /* B7=OSC; B6-4=10secs; B3-0=sec (0-59) */
+ uchar min; /* B6-4=10mins; B3-0=min (0-59) */
+ uchar hour; /* B4-5=10hour; B3-0=hour (0-23) */
+ uchar wday; /* B6=FT B2-0=day (1-7) */
+ uchar mday; /* B4-5=10date; B3-0=date (1-31) */
+ uchar month; /* B4=10mo; B3-0=month (1-12) */
+ uchar year; /* MS-nibble=10Year; LS-nibble=year (0-99) */
+};
+
+#define DS1743REGS ((struct dsdate *)DATEREGBASE)
+#define DS_century (DS1743REGS->cent)
+#define DS_second (DS1743REGS->sec)
+#define DS_minute (DS1743REGS->min)
+#define DS_hour (DS1743REGS->hour)
+#define DS_wday (DS1743REGS->wday)
+#define DS_mday (DS1743REGS->mday)
+#define DS_month (DS1743REGS->month)
+#define DS_year (DS1743REGS->year)
+
+#define SECONDS_IN_DAY 86400
+
+static char
+DaysInMonth[] = {
+ 31, 28, 31, 30, 31, 30, /* Jan, Feb, Mar, Apr, May, Jun */
+ 31, 31, 30, 31, 30, 31 /* Jul, Aug, Sep, Oct, Nov, Dec */
+};
+
+/* rangecheck():
+ Return 0 if value is outside the range of high and low; else 1.
+*/
+static int
+rangecheck(int value, char *name, int low, int high)
+{
+ if ((value < low) || (value > high)) {
+ printf("%s outside valid range of %d - %d\n",
+ name,low,high);
+ return(0);
+ }
+ return(1);
+}
+
+/* to_dsdatefmt():
+ * Take an incoming integer and convert it to the dallas time date
+ * format using a 10-multiplier for the upper nibble.
+ */
+static unsigned char
+to_dsdatefmt(int value)
+{
+ int tens;
+
+ tens = 0;
+ while (value >= 10) {
+ tens++;
+ value -= 10;
+ }
+ return((tens << 4) | value);
+}
+
+static int
+from_dsdatefmt(unsigned char value, unsigned char mask10)
+{
+ int newvalue;
+
+ newvalue = value & 0x0f;
+ newvalue += 10 * ((value & mask10) >> 4);
+ return(newvalue);
+}
+
+int
+showDate(int center)
+{
+ int (*pfunc)(char *, ...);
+ int day, date, month, year, hour, minute, second, century;
+
+ DS_century |= READ; /* Set READ bit */
+
+ century = from_dsdatefmt(DS_century,CENTURY10_MASK);
+ second = from_dsdatefmt(DS_second,SECOND10_MASK);
+ minute = from_dsdatefmt(DS_minute,MINUTE10_MASK);
+ hour = from_dsdatefmt(DS_hour,HOUR10_MASK);
+ day = from_dsdatefmt(DS_wday,DAY10_MASK);
+ date = from_dsdatefmt(DS_mday,DATE10_MASK);
+ month = from_dsdatefmt(DS_month,MONTH10_MASK);
+ year = (((DS_year & 0xf0) >> 4) * 10) + (DS_year & 0x0f);
+
+ DS_century &= ~READ; /* Clear READ bit */
+
+ if (center)
+ pfunc = cprintf;
+ else
+ pfunc = printf;
+
+ pfunc("%02d/%02d/%02d%02d @ %02d:%02d:%02d\n",
+ month,date,century,year,hour,minute,second);
+
+ return(0);
+}
+
+#if INCLUDE_TFS
+
+static int
+YearIsLeap(int year)
+{
+ if (year % 4) /* if year not divisible by 4... */
+ return(0); /* it's not leap */
+ if (year < 1582) /* all years divisible by 4 were */
+ return(1); /* leap prior to 1582 */
+ if (year % 100) /* if year divisible by 4, */
+ return(1); /* but not by 100, it's leap */
+ if (year % 400) /* if year divisible by 100, */
+ return(0); /* but not by 400, it's not leap */
+ else
+ return(1); /* if divisible by 400, it's leap */
+}
+
+/* GetAtime():
+ * Build a string based on the incoming long value as described in
+ * GetLtime()...
+ * Used by TFS to keep track of file time.
+ */
+static char *
+GetAtime(long tval, char *buf, int bsize)
+{
+ int year; /* Actual year */
+ int doy; /* Day of year */
+ int sid; /* Seconds in day */
+ int leapyear; /* Set if year is leap */
+ int month, hour, minute;
+
+ if ((bsize < 18) || (tval == TIME_UNDEFINED)) {
+ *buf = 0;
+ return(buf);
+ }
+
+ /* Break down the basic bitfields: */
+ year = 2000 + ((tval >> 26) & 0x3f);
+ leapyear = YearIsLeap(year);
+ doy = ((tval >> 17) & 0x1ff);
+ sid = tval & 0x1ffff;
+
+ /* Now build the date from the bit fields: */
+ hour = sid / 3600;
+ sid -= (hour*3600);
+ minute = sid/60;
+ sid -= (minute*60);
+
+ month = 0;
+ while(doy > DaysInMonth[month]) {
+ doy -= DaysInMonth[month];
+ if ((month == 1) && (leapyear))
+ doy--;
+ month++;
+ }
+ sprintf(buf,"%02d/%02d/%02d@%02d:%02d:%02d",
+ month+1,doy,year,hour,minute,sid);
+ return(buf);
+}
+
+/* GetLtime():
+ * Build a long with the following format....
+ *
+ * B31-26 year since 2000 (0-127 yep, this breaks in 2128)
+ * B25-17 day of year (1-365)
+ * B16-0 seconds in day (0-86400)
+ *
+ * Used by TFS to keep track of file time.
+ */
+static long
+GetLtime(void)
+{
+ long tval;
+ int year, month, mday, seconds, doy, leapyear;
+
+ DS_century |= READ; /* Set READ bit */
+
+ year = from_dsdatefmt(DS_year,YEAR10_MASK); /* 00=2000 */
+ month = from_dsdatefmt(DS_month,MONTH10_MASK)-1; /* 0-11 */
+ mday = from_dsdatefmt(DS_mday,DATE10_MASK); /* 1-31 */
+ leapyear = YearIsLeap(year+2000);
+
+ if ((month > 11) || (month < 0) || (mday < 1) || (mday > 31))
+ return(TIME_UNDEFINED);
+
+ /* Determine current day of year... */
+ doy = mday;
+ while(month > 0) {
+ doy += DaysInMonth[month-1];
+ if ((month == 1) && leapyear)
+ doy++;
+ month--;
+ }
+
+ /* Determine current second of day... */
+ seconds = (from_dsdatefmt(DS_hour,HOUR10_MASK) * 3600);
+ seconds += (from_dsdatefmt(DS_minute,MINUTE10_MASK) * 60);
+ seconds += from_dsdatefmt(DS_second,SECOND10_MASK);
+
+ DS_century &= ~READ; /* Clear READ bit */
+
+ tval = (((year & 0x3f) << 26) |
+ ((doy & 0x1ff) << 17) |
+ (seconds & 0x1ffff));
+ return(tval);
+}
+
+/* tfsTimeEnable():
+ * Hook the file timestamping in TFS to the DS1743 device...
+ */
+void
+tfsTimeEnable(void)
+{
+ tfsctrl(TFS_TIMEFUNCS,(long)GetLtime,(long)GetAtime);
+}
+#endif
+
+char *DateHelp[] = {
+ "Display (mm/dd/yyyy@hh:mm:ss) or modify time and date.",
+ "[{day date month year hour min sec}]",
+#if INCLUDE_VERBOSEHELP
+ "Where...",
+ " day: 1-7 (sun=1)",
+ " date: 1-31",
+ " month: 1-12",
+ " year: 0-3899",
+ " hour: 0-23",
+ " min: 0-59",
+ " sec: 0-59",
+ "Note: 'date off' disables the oscillator",
+#endif
+ 0
+};
+
+int
+Date(int argc,char *argv[])
+{
+ int day, date, month, year, hour, minute, second, century, rngchk;
+
+ if (argc == 1) {
+ if (DS_second & OSC_OFF)
+ printf("Warning: oscillator disabled.\n");
+ showDate(0);
+ return(CMD_SUCCESS);
+ }
+ else if ((argc == 2) && !strcmp(argv[1],"off")) {
+ DS_century |= WRITE; /* Disable the oscillator */
+ DS_second = OSC_OFF; /* to save battery life. */
+ DS_century &= ~WRITE;
+ return(CMD_SUCCESS);
+ }
+ else if (argc != 8)
+ return(CMD_PARAM_ERROR);
+
+ day = atoi(argv[1]);
+ date = atoi(argv[2]);
+ month = atoi(argv[3]);
+ year = atoi(argv[4]);
+ hour = atoi(argv[5]);
+ minute = atoi(argv[6]);
+ second = atoi(argv[7]);
+
+ rngchk = 0;
+ rngchk += rangecheck(day,"day",1,7);
+ rngchk += rangecheck(date,"date",1,31);
+ rngchk += rangecheck(month,"month",1,12);
+ rngchk += rangecheck(year,"year",0,3899);
+ rngchk += rangecheck(hour,"hour",0,23);
+ rngchk += rangecheck(minute,"minute",0,59);
+ rngchk += rangecheck(second,"second",0,59);
+
+ if (rngchk != 7)
+ return(CMD_PARAM_ERROR);
+
+ DS_century = WRITE; /* Set WRITE bit */
+ DS_second = to_dsdatefmt(second) & ~OSC_OFF;
+ DS_minute = to_dsdatefmt(minute);
+ DS_hour = to_dsdatefmt(hour);
+ DS_wday = day;
+ DS_mday = to_dsdatefmt(date);
+ DS_month = to_dsdatefmt(month);
+ century = year / 100;
+ year = year % 100;
+ DS_year = to_dsdatefmt(year);
+ DS_century = (to_dsdatefmt(century)&(CENTURY_MASK|CENTURY10_MASK))|WRITE;
+
+ DS_century &= ~WRITE; /* Clear WRITE bit */
+ return(CMD_SUCCESS);
+}
+
+
diff --git a/main/common/date.c b/main/common/date.c
new file mode 100644
index 0000000..f7d56b0
--- /dev/null
+++ b/main/common/date.c
@@ -0,0 +1,160 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * date.c:
+ *
+ * A command front-end and utilities for time-of-day-clock hardware.
+ * Some of this is taken from the older file dallasdate.c which *should*
+ * be moved to the dev directory (if not already there).
+ * This code expects a few HW-specific functions to be available...
+ *
+ * getTimeAndDate(struct todinfo *);
+ * setTimeAndDate(struct todinfo *);
+ *
+ * If setTimeAndDate() is passed '0', then it is this code's attempt
+ * to disable the TOD oscillator (to reduce battery drain).
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "cli.h"
+#include "date.h"
+
+/* rangecheck():
+ Return 0 if value is outside the range of high and low; else 1.
+*/
+static int
+rangecheck(int value, char *name, int low, int high)
+{
+ if ((value < low) || (value > high)) {
+ printf("%s outside valid range of %d - %d\n",
+ name,low,high);
+ return(0);
+ }
+ return(1);
+}
+
+int
+showDate(int center)
+{
+ int (*pfunc)(char *, ...);
+ struct todinfo now;
+
+ getTimeAndDate(&now);
+
+ if (center)
+ pfunc = cprintf;
+ else
+ pfunc = printf;
+
+ pfunc("%02d/%02d/%04d @ %02d:%02d:%02d\n",
+ now.month,now.date,now.year,
+ now.hour,now.minute,now.second);
+
+ return(0);
+}
+
+char *DateHelp[] = {
+ "Display (mm/dd/yyyy@hh:mm:ss) or modify time and date.",
+ "[{day date month year hour min sec}]",
+#if INCLUDE_VERBOSEHELP
+ "Where...",
+ " day: 1-7 (sun=1)",
+ " date: 1-31",
+ " month: 1-12",
+ " year: full number (i.e. 2006)",
+ " hour: 0-23",
+ " min: 0-59",
+ " sec: 0-59",
+ "Note: 'date off' disables the oscillator (if HW supports this)",
+#endif
+ 0
+};
+
+int
+DateCmd(int argc,char *argv[])
+{
+ int rngchk;
+ struct todinfo now;
+
+ if (argc == 1) {
+ showDate(0);
+ return(CMD_SUCCESS);
+ }
+ else if ((argc == 2) && !strcmp(argv[1],"off")) {
+ if (setTimeAndDate(0) < 0) {
+ printf("Clock can't be disabled\n");
+ return(CMD_FAILURE);
+ }
+ return(CMD_SUCCESS);
+ }
+ else if (argc != 8)
+ return(CMD_PARAM_ERROR);
+
+ now.day = (char)atoi(argv[1]);
+ now.date = (char)atoi(argv[2]);
+ now.month = (char)atoi(argv[3]);
+ now.year = atoi(argv[4]);
+ now.hour = (char)atoi(argv[5]);
+ now.minute = (char)atoi(argv[6]);
+ now.second = (char)atoi(argv[7]);
+
+ rngchk = 0;
+ rngchk += rangecheck(now.day,"day",1,7);
+ rngchk += rangecheck(now.date,"date",1,31);
+ rngchk += rangecheck(now.month,"month",1,12);
+ rngchk += rangecheck(now.year,"year",0,9999);
+ rngchk += rangecheck(now.hour,"hour",0,23);
+ rngchk += rangecheck(now.minute,"minute",0,59);
+ rngchk += rangecheck(now.second,"second",0,59);
+
+ if (rngchk != 7)
+ return(CMD_PARAM_ERROR);
+
+ setTimeAndDate(&now);
+ return(CMD_SUCCESS);
+}
+
+int
+timeofday(int cmd, void *arg)
+{
+ int rc;
+ struct todinfo *now;
+
+ rc = 0;
+ now = (struct todinfo *)arg;
+
+ switch(cmd) {
+ case TOD_ON:
+ case TOD_OFF:
+ break;
+ case TOD_SET:
+ rc = setTimeAndDate(now);
+ break;
+ case TOD_GET:
+ rc = getTimeAndDate(now);
+ break;
+ }
+ return(rc);
+}
diff --git a/main/common/date.h b/main/common/date.h
new file mode 100644
index 0000000..1f39ee0
--- /dev/null
+++ b/main/common/date.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * date.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+struct todinfo {
+ char day; /* 1-7 (sun = 1) */
+ char date; /* 1-31 */
+ char month; /* 1-12 */
+ char hour; /* 0-23 */
+ char minute; /* 0-59 */
+ char second; /* 0-59 */
+ short year; /* full number (i.e. 2006) */
+};
+
+extern int showDate(int center);
+extern int timeofday(int cmd, void *arg);
+extern int setTimeAndDate(struct todinfo *now);
+extern int getTimeAndDate(struct todinfo *now);
+
+/* #defines used by the uMon API mon_timeofday()...
+ */
+#define TOD_ON 1
+#define TOD_OFF 2
+#define TOD_SET 3
+#define TOD_GET 4
diff --git a/main/common/devices.c b/main/common/devices.c
new file mode 100644
index 0000000..134c21c
--- /dev/null
+++ b/main/common/devices.c
@@ -0,0 +1,149 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * devices.c:
+ *
+ * This code provides the monitor with the ability to treat the peripherals
+ * as an entry in a device table so that each device can be accessed through
+ * read, write, ioctl, init, open and close.
+ * The device table header file is defined as part of the target-specific
+ * code and contains all of the target-specific device entries.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "devtbl.h"
+#include "devices.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+/* devtbldump():
+ * Dump the contents of the device table.
+ */
+void
+devtbldump()
+{
+ int i;
+
+ /* Dump the device table and add an asterisk next to the console device. */
+ for(i=0;i<DEVTOT;i++) {
+ printf("Dev %d: %s%s\n",i,devtbl[i].name,
+ ConsoleDevice == i ? " (console)" : "");
+ }
+}
+
+/* isbaddev():
+ * Return the result of a basic range check of the device number.
+ */
+int
+isbaddev(int dev)
+{
+ if ((dev < 0) || (dev >= DEVTOT)) {
+ printf("Invalid device: %d\n",dev);
+ return(1);
+ }
+ return(0);
+}
+
+/* Upper half device driver interfaces: */
+
+int
+init(int dev,ulong arg)
+{
+ if (isbaddev(dev) || !devtbl[dev].init)
+ return(-1);
+ return (devtbl[dev].init(arg));
+}
+
+int
+open(int dev,ulong arg1,ulong arg2)
+{
+ if (isbaddev(dev) || !devtbl[dev].open)
+ return(-1);
+ return (devtbl[dev].open(arg1,arg2));
+}
+
+int
+close(int dev)
+{
+ if (isbaddev(dev) || !devtbl[dev].close)
+ return(-1);
+ return (devtbl[dev].close(dev));
+}
+
+int
+ioctl(int dev,int func,ulong data1,ulong data2)
+{
+ if (isbaddev(dev) || !devtbl[dev].ctrl)
+ return(-1);
+ return (devtbl[dev].ctrl(func,data1,data2));
+}
+
+int
+read(int dev,char *buf,int cnt)
+{
+ if (isbaddev(dev) || !devtbl[dev].read)
+ return(-1);
+ return (devtbl[dev].read(buf,cnt));
+}
+
+int
+write(int dev,char *buf,int cnt)
+{
+ if (isbaddev(dev) || !devtbl[dev].read)
+ return(-1);
+ return (devtbl[dev].write(buf,cnt));
+}
+
+/* devInit():
+ * Step through the device table and execute each devices' initialization
+ * function (if any). If any device initialization fails, print out an
+ * error message and immediately branch to the montor's command loop.
+ * Since it is through this point that the monitor's UARTs are first
+ * initialized, we pass in a baudrate that is then handed to each of the
+ * device initialization routines (although it is only used by serial
+ * devices).
+ */
+int
+devInit(int baud)
+{
+ int fd;
+
+ if (baud == 0)
+ baud = ConsoleBaudRate;
+
+ /* Keep track of the last baud rate, so that it can be used if the
+ * incoming baudrate is NULL.
+ */
+ ConsoleBaudRate = baud;
+
+ fd = 0;
+ for(fd=0;fd<DEVTOT;fd++)
+ {
+ /* If device table does not have an init function, skip over it. */
+ if (!devtbl[fd].init)
+ continue;
+ if (devtbl[fd].init((ulong)baud) != 0) {
+ printf("devInit() <%s> FAILED\n",devtbl[fd].name);
+ CommandLoop();
+ }
+ }
+ return(0);
+}
diff --git a/main/common/devices.h b/main/common/devices.h
new file mode 100644
index 0000000..62f7e8f
--- /dev/null
+++ b/main/common/devices.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * devices.h
+ *
+ * device structure:
+ * This structure defines the basic information needed for device
+ * control. The table of devices is initialized at compile time
+ * with each device assigned an integer device descriptor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _DEVICES_H_
+#define _DEVICES_H_
+
+struct device {
+ int (*init)(unsigned long);
+ int (*ctrl)(int,unsigned long,unsigned long);
+ int (*open)(unsigned long,unsigned long);
+ int (*close)(int);
+ int (*read)(char *,int);
+ int (*write)(char *,int);
+ char *name;
+};
+
+extern struct device devtbl[];
+
+/* Generic driver functions: */
+extern int open(int, unsigned long, unsigned long);
+extern int close(int);
+extern int read(int, char *, int);
+extern int write(int, char *, int);
+extern int init(int, unsigned long);
+extern int ioctl(int, int, unsigned long, unsigned long);
+extern int devInit(int);
+extern int isbaddev(int);
+extern void devtbldump(void);
+
+/* Common ioctl definitions: */
+#define INIT 1
+#define GOTACHAR 2
+#define SETBAUD 3
+
+#define nodriver 0
+
+extern int ConsoleDevice;
+#endif
diff --git a/main/common/dhcp_00.c b/main/common/dhcp_00.c
new file mode 100644
index 0000000..8a9d7ca
--- /dev/null
+++ b/main/common/dhcp_00.c
@@ -0,0 +1,259 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dhcp_00.c:
+ *
+ * This file contains the functions that are called from dhcpboot.c if the
+ * the default DHCP interaction is to be done by the monitor. Whenever a
+ * new dhcp_XX.c file is created, this file should be used as the template.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "endian.h"
+#include "stddefs.h"
+
+#if INCLUDE_DHCPBOOT
+
+/* ValidDHCPOffer():
+ * Target issued the DISCOVER, the incoming packet is the server's
+ * OFFER reply. If the DHCPOFFRFLTR shell variable is not present, then
+ * return 1 indicating acceptance of the offer. If the DHCPOFFRFLTR variable
+ * exists, then use its content to determine if the offer should be accepted...
+ *
+ * Shell variable syntax:
+ *
+ * DHCP_FIELD_IDENTIFIER,EXPECTED_STRING
+ *
+ * where DHCP_FIELD_IDENTIFIER can be...
+ * BFN bootfile name
+ * SHN server-host name
+ * VSO### vendor-specific option number (options encapsulated within
+ * the Vendor-Specific Information (#43) option)
+ * SSO### site-specific option number (range 128-254)
+ *
+ * For example:
+ * 1...
+ * if DHCPOFFRFLTR contains "BFN,abcfile"
+ * then the offer will only be accepted if the bootfile specified by the
+ * dhcp server contains the string "abcfile".
+ * 2...
+ * if DHCPOFFRFLTR contains "SHN,a_host_name"
+ * then the offer will only be accepted if the server-hostname specified
+ * by the dhcp server contains the string "a_host_name".
+ * 3...
+ * if DHCPOFFRFLTR contains "VSO18,some_String"
+ * then the offer will only be accepted if the server returns vendor-
+ * specific option # 18 and it contains the string "some_String".
+ *
+ * Note that "containing the string" means that the string specified in
+ * the DHCPOFFRFLTR shell variable can be the entire string or a sub-string
+ * within the server's response.
+ */
+int
+ValidDHCPOffer(struct dhcphdr *dhdr)
+{
+ char *var;
+ int offeraccepted, badsyntax;
+
+ /* If no DHCPOFFRFLTR var, accept the offer... */
+ var = getenv("DHCPOFFRFLTR");
+ if (!var)
+ return(1);
+
+ /* Start off by assuming acceptance... */
+ badsyntax = 0;
+ offeraccepted = 1;
+
+ /* Now process the DHCPOFFRFLTR variable and incoming dhcp data,
+ * and clear the offeraccepted (or set badsyntax) flag if necessary...
+ */
+
+ if (!strncmp(var,"BFN,",4)) {
+ if (!strstr((char *)dhdr->bootfile,var+4))
+ offeraccepted = 0;
+ }
+ else if (!strncmp(var,"SHN,",4)) {
+ if (!strstr((char *)dhdr->server_hostname,var+4))
+ offeraccepted = 0;
+ }
+ else if ((!strncmp(var,"SSO",3)) || (!strncmp(var,"VSO",3))) {
+ int optno;
+ ulong cookie;
+ char *comma, *optval, *vso;
+
+ optno = atoi(var+3);
+ comma = strchr(var,',');
+ memcpy((char *)&cookie,(char *)&dhdr->magic_cookie,4);
+ if (cookie != ecl(STANDARD_MAGIC_COOKIE))
+ offeraccepted = 0;
+ else if (!comma)
+ badsyntax = 1;
+ else if (var[0] == 'S') {
+ if ((optno < 128) || (optno > 254))
+ badsyntax = 1;
+ else {
+ optval = (char *)DhcpGetOption(optno,(unsigned char *)(dhdr+1));
+ if (!optval)
+ offeraccepted = 0;
+ else {
+ if (!strstr(optval+2,comma+1))
+ offeraccepted = 0;
+ }
+ }
+ }
+ else if (var[0] == 'V') {
+ if ((optno < 0) || (optno > 254))
+ badsyntax = 1;
+ else {
+ vso = (char *)DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,
+ (uchar *)dhdr+1);
+ if (!vso)
+ offeraccepted = 0;
+ else {
+ optval = (char *)DhcpGetOption(optno,(unsigned char *)vso+2);
+ if (!optval)
+ offeraccepted = 0;
+ else {
+ if (!strstr(optval+2,comma+1))
+ offeraccepted = 0;
+ }
+ }
+ }
+ }
+ }
+ else {
+ badsyntax = 1;
+ }
+ if (badsyntax) {
+ printf("Bad DHCPOFFRFLTR syntax.\n");
+ offeraccepted = 0;
+ }
+ return(offeraccepted);
+}
+
+/* DhcpVendorSpecific():
+ * Process any vendor specific data from the incoming header.
+ */
+void
+DhcpVendorSpecific(struct dhcphdr *dhdr)
+{
+ return; /* Obviously, the default is no processing. */
+}
+
+/* printDhcpVSopt():
+ * Input is the option, the option length and the pointer to the options.
+ * Print the option.
+ */
+int
+printDhcpVSopt(int vsopt, int vsoptlen, char *options)
+{
+ return(0);
+}
+
+/* buildDhcpHdr():
+ * Called by dhcpboot.c to allow application-specific header stuff to
+ * be added to header. Return 0 if generic stuff in dhcpboot.c is to be
+ * used; else return 1 and the calling code will assume this function is
+ * dealing with it (see dhcpboot.c for basic idea).
+ */
+int
+buildDhcpHdr(struct dhcphdr *dhdr)
+{
+ return(0);
+}
+
+/* DhcpBootpLoadVSA():
+ * Called by DhcpBootpDone to store an ascii-coded-hex copy of the
+ * vendor-specific-area (BOOTP) or options (DHCP) in the shell variable
+ * DHCPVSA.
+ */
+void
+DhcpBootpLoadVSA(uchar *vsabin, int vsize)
+{
+ int i;
+ uchar *cp, *vsaacx;
+
+ /* If after the transaction has completed, the RLYAGNT is */
+ /* set, but GIPADD is not set, copy RLYAGNT to GIPADD... */
+ if (!getenv("GIPADD") && getenv("RLYAGNT"))
+ setenv("GIPADD",getenv("RLYAGNT"));
+
+ /* Since the VSA (bootp) or options list (DHCP) can be large,
+ * This code looks for the presence of the DHCPVSA shell variable
+ * as an indication as to whether or not this data should be stored
+ * in the DHCPVSA variable...
+ * If the variable is present, then this code will load the DHCPVSA
+ * shell variable; else it just returns here.
+ * Note that it doesn't matter what the content of DHCPVSA is, as
+ * long as it is present, so just loading it with "TRUE" in monrc
+ * will be sufficient to tell this logic to load the variable with
+ * the data.
+ */
+ if (!getenv("DHCPVSA"))
+ return;
+
+ /* If allocation succeeds, then copy BOOTP VendorSpecificArea to the */
+ /* DHCPVSA shell variable. Copy it as ascii-coded hex */
+ vsaacx = (uchar *)malloc((vsize*2)+4);
+ if (vsaacx) {
+ cp = vsaacx;
+ for(i=0;i<vsize;i++,cp+=2)
+ sprintf((char *)cp,"%02x", vsabin[i]);
+ *cp = 0;
+ setenv("DHCPVSA", (char *)vsaacx);
+ free((char *)vsaacx);
+ }
+ else
+ printf("DHCPVSA space allocation failed\n");
+}
+
+
+/* DhcpBootpDone():
+ * Called at the end of the Bootp or Dhcp transaction.
+ * Input...
+ * bootp: 1 if BOOTP; else DHCP.
+ * dhdr: pointer to dhcp or bootp header.
+ * vsize: size of vendor specific area (for bootp this is fixed at 64,
+ * but for dhcp it is variable).
+ */
+void
+DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize)
+{
+ if (bootp) {
+ struct bootphdr *bhdr;
+
+ bhdr = (struct bootphdr *)dhdr;
+ DhcpBootpLoadVSA(bhdr->vsa,vsize);
+ }
+ else {
+ DhcpBootpLoadVSA((uchar *)&dhdr->magic_cookie,vsize);
+ }
+ return;
+}
+
+#endif
diff --git a/main/common/dhcp_01.c b/main/common/dhcp_01.c
new file mode 100644
index 0000000..afd7fa0
--- /dev/null
+++ b/main/common/dhcp_01.c
@@ -0,0 +1,246 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dhcp_01.c:
+ * This is the PPA-specific code used for Videotron Market trial.
+ * It was built from the dhcp_00.c DHCP-extension template file.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+/* Vendor specific option definitions: */
+#define VS_PROXYIP 1
+#define VS_PHONENUM 2
+#define VS_CODER 3
+#define VS_PPADHCPSRVR 4
+#define VS_MINNETDELAY 5
+#define VS_MAXNETDELAY 6
+#define VS_APPINFO 7
+#define VS_CODERCTL 8
+#define VS_NAMEVAL 99
+
+#define PPADHCPSRVR_STR "PPADHCPSRVR"
+
+/* ValidDHCPOffer():
+ * Target issued the DISCOVER, the incoming packet is the server's
+ * OFFER reply. If the offer contains the vendor specific
+ * VS_PPADHCPSRVR option and the string within that
+ * option is correct, then accept the offer; by issuing a request.
+ */
+ValidDHCPOffer(struct dhcphdr *dhdr)
+{
+ uchar *op, *op1;
+
+ op = op1 = 0;
+ op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1);
+ if (op1) {
+ op = DhcpGetOption(VS_PPADHCPSRVR,op1+2);
+ }
+ if (op) {
+ if (!strncmp(op+2,PPADHCPSRVR_STR,sizeof(PPADHCPSRVR_STR)-1)) {
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/* buildDhcpHdr():
+ * Called by dhcpboot.c to allow application-specific header stuff to
+ * be added to header. Return 0 if generic stuff in dhcpboot.c is to be
+ * used; else return 1 and the calling code will assume this function is
+ * dealing with it (see dhcpboot.c for basic idea).
+ */
+int
+buildDhcpHdr(struct dhcphdr *dhcpdata)
+{
+ return(0);
+}
+
+/* DhcpBootpDone():
+ * Called at the end of the Bootp or Dhcp transaction.
+ * Input...
+ * bootp: 1 if BOOTP; else DHCP.
+ * dhdr: pointer to dhcp or bootp header.
+ * vsize: size of vendor specific area (for bootp this is fixed at 64,
+ * but for dhcp it is variable).
+ */
+void
+DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize)
+{
+ return;
+}
+
+void
+SetPPAOption(type,op1,varname)
+int type;
+uchar *op1;
+char *varname;
+{
+ uchar *op, tmp;
+
+ op = DhcpGetOption(type,op1+2);
+ if (op) {
+ tmp = op[*(op+1)+2];
+ op[*(op+1)+2] = 0;
+ DhcpSetEnv(varname,op+2);
+ op[*(op+1)+2] = tmp;
+ }
+}
+
+/* DhcpVendorSpecific():
+ * Process vendor specific stuff within the incoming dhcp header.
+ */
+DhcpVendorSpecific(struct dhcphdr *dhdr)
+{
+ ulong ip;
+ uchar *op, *op1, buf[16], tmp;
+
+ op = op1 = 0;
+ op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1);
+ if (op1) {
+ /* Get PROXY_IP and BPROXY_IP (optionally): */
+ op = DhcpGetOption(VS_PROXYIP,op1+2);
+ if (op) {
+ memcpy(&ip,op+2,4);
+ DhcpSetEnv("PROXY_IP",IpToString(ip,buf));
+ if (*(op+1) == 8) {
+ memcpy(&ip,op+6,4);
+ DhcpSetEnv("BPROXY_IP",IpToString(ip,buf));
+ }
+ }
+
+ /* Get PPA phone numbers (1 or 2). */
+ op = DhcpGetOption(VS_PHONENUM,op1+2);
+ if (op) {
+ char *space;
+ tmp = op[*(op+1)+2];
+ op[*(op+1)+2] = 0;
+ space = strchr(op+2,' ');
+ if (space) {
+ *space = 0;
+ DhcpSetEnv("LINE0_NUMBER",op+2);
+ DhcpSetEnv("LINE1_NUMBER",space+1);
+ *space = ' ';
+ }
+ else
+ DhcpSetEnv("LINE0_NUMBER",op+2);
+ op[*(op+1)+2] = tmp;
+ }
+
+ /* Set Coder type: */
+ SetPPAOption(VS_CODER,op1,"CODER");
+
+ /* Set Coder control: */
+ SetPPAOption(VS_CODERCTL,op1,"CODERCTL");
+
+ /* Set minimum network delay setting: */
+ SetPPAOption(VS_MINNETDELAY,op1,"MIN_NET_DELAY");
+
+ /* Set maximum network delay setting: */
+ SetPPAOption(VS_MAXNETDELAY,op1,"MAX_NET_DELAY");
+
+ /* Set appinfo: */
+ SetPPAOption(VS_APPINFO,op1,"APPINFO");
+ }
+
+ /* Check for VS_NAMEVAL here...
+ * If the Vendor-Specific-Information is present, and within that
+ * information there is a sub-option of VS_NAMEVAL,
+ * then consider the content of that sub-option to be one or more
+ * strings (separated by a comma) of the format "VARNAME=VALUE".
+ * This is used to allow the DHCP server to configure shell variables
+ * into the environment prior to the monitor turning over control to
+ * the application.
+ * Two examples of VS_NAMEVAL strings:
+ * First, just one name-value combination...
+ * VARNAME=VALUE
+ * Second, a multiple name-value combination...
+ * VARNAME=VALUE,VAR1=ABC,IP=1.2.3.4
+ */
+
+ op = op1 = 0;
+ op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1);
+ if (op1)
+ op = DhcpGetOption(VS_NAMEVAL,op1+2);
+ if (op) {
+ int len;
+ uchar *end, tmp;
+ uchar *name, *value, *eqsign, *comma, *base;
+
+ op++;
+ len = (int)*op++;
+ base = op;
+ tmp = base[len];
+ base[len] = 0;
+ end = base + len;
+ while (op < end) {
+ eqsign = (uchar *)strchr(op,'=');
+ if (!eqsign)
+ break;
+ name = op;
+ *eqsign = 0;
+ value = eqsign+1;
+ comma = (uchar *)strchr(value,',');
+ if (comma) {
+ *comma = 0;
+ op = comma+1;
+ }
+ else
+ op = end;
+ DhcpSetEnv(name,value);
+ *eqsign = '=';
+ *comma = ',';
+ }
+ base[len] = tmp;
+ }
+}
+
+int
+printDhcpVSopt(int vsopt, int vsoptlen, char *options)
+{
+ switch(vsopt) {
+ case VS_PROXYIP:
+ for(i=0;i<vsoptlen;i++)
+ printf("%d ",(unsigned int)*options++);
+ break;
+ case VS_CODER:
+ case VS_NAMEVAL:
+ case VS_MINNETDELAY:
+ case VS_MAXNETDELAY:
+ case VS_PPADHCPSRVR:
+ case VS_PHONENUM:
+ case VS_APPINFO:
+ for(i=0;i<vsoptlen;i++)
+ printf("%c",*options++);
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
diff --git a/main/common/dhcp_02.c b/main/common/dhcp_02.c
new file mode 100644
index 0000000..1fb0cdc
--- /dev/null
+++ b/main/common/dhcp_02.c
@@ -0,0 +1,89 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dhcp_02.c:
+ *
+ * This is the PPA-specific code used for Time-Warner Market.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+/* ValidDHCPOffer():
+ * Target issued the DISCOVER, the incoming packet is the server's
+ * OFFER reply. If the offer contains the string PPADHCPSRVR in the
+ * bootfile string, then accept the offer (return 1); else reject it.
+ */
+ValidDHCPOffer(struct dhcphdr *dhdr)
+{
+ if (strcmp(dhdr->bootfile,"PPADHCPSRVR"))
+ return(0);
+ return(1);
+}
+
+/* buildDhcpHdr():
+ * Called by dhcpboot.c to allow application-specific header stuff to
+ * be added to header. Return 0 if generic stuff in dhcpboot.c is to be
+ * used; else return 1 and the calling code will assume this function is
+ * dealing with it (see dhcpboot.c for basic idea).
+ */
+int
+buildDhcpHdr(struct dhcphdr *dhcpdata)
+{
+ return(0);
+}
+
+/* DhcpBootpDone():
+ * Called at the end of the Bootp or Dhcp transaction.
+ * Input...
+ * bootp: 1 if BOOTP; else DHCP.
+ * dhdr: pointer to dhcp or bootp header.
+ * vsize: size of vendor specific area (for bootp this is fixed at 64,
+ * but for dhcp it is variable).
+ */
+void
+DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize)
+{
+ return;
+}
+
+/* DhcpVendorSpecific():
+ * Process vendor specific stuff within the incoming dhcp header.
+ */
+void
+DhcpVendorSpecific(struct dhcphdr *dhdr)
+{
+}
+
+/* printDhcpVSopt():
+ * Print vendor specific stuff within the incoming dhcp header.
+ */
+int
+printDhcpVSopt(int vsopt, int vsoptlen, char *options)
+{
+ return(0);
+}
diff --git a/main/common/dhcp_03.c b/main/common/dhcp_03.c
new file mode 100644
index 0000000..2f8566c
--- /dev/null
+++ b/main/common/dhcp_03.c
@@ -0,0 +1,101 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dhcp_03.c:
+ *
+ * This is the PPA-specific code used for PATHSTAR. PATHSTAR uses BOOTP
+ * and has their own proprietary string in the vendor-specific-area.
+ * This code loads that string into the BOOTPVSA shell variable.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+/* ValidDHCPOffer():
+ Target issued the DISCOVER, the incoming packet is the server's
+ OFFER reply.
+*/
+ValidDHCPOffer(struct dhcphdr *dhdr)
+{
+ return(1);
+}
+
+/* buildDhcpHdr():
+ Called by dhcpboot.c to allow application-specific header stuff to
+ be added to header. Return 0 if generic stuff in dhcpboot.c is to be
+ used; else return 1 and the calling code will assume this function is
+ dealing with it (see dhcpboot.c for basic idea).
+*/
+int
+buildDhcpHdr(struct dhcphdr *dhcpdata)
+{
+ return(0);
+}
+
+/* DhcpBootpDone():
+ Called at the end of the Bootp or Dhcp transaction.
+ Input...
+ bootp: 1 if BOOTP; else DHCP.
+ dhdr: pointer to dhcp or bootp header.
+ vsize: size of vendor specific area (for bootp this is fixed at 64,
+ but for dhcp it is variable).
+*/
+void
+DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize)
+{
+ if (bootp) {
+ ulong cookie;
+ struct bootphdr *bhdr;
+ char bootpvsa[65], *vp;
+
+ bhdr = (struct bootphdr *)dhdr;
+ memcpy(&cookie,bhdr->vsa,4);
+ if (cookie != STANDARD_MAGIC_COOKIE) {
+ memcpy(bootpvsa,bhdr->vsa,64);
+ bootpvsa[64] = 0;
+ setenv("BOOTPVSA",bootpvsa);
+ }
+ }
+}
+
+/* DhcpVendorSpecific():
+ Process vendor specific stuff within the incoming dhcp header.
+*/
+void
+DhcpVendorSpecific(struct dhcphdr *dhdr)
+{
+}
+
+/* printDhcpVSopt():
+ Print vendor specific stuff within the incoming dhcp header.
+*/
+int
+printDhcpVSopt(int vsopt, int vsoptlen, char *options)
+{
+ return(0);
+}
diff --git a/main/common/dhcpboot.c b/main/common/dhcpboot.c
new file mode 100644
index 0000000..e0ded6a
--- /dev/null
+++ b/main/common/dhcpboot.c
@@ -0,0 +1,1328 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dhcpboot.c:
+ *
+ * This code implements a subset of the DHCP client protocol.
+ * Based on RFC2131 spec, the "automatic allocation" mode, in which DHCP
+ * assigns a permanent IP address to a client, is the only mode supported.
+ *
+ * The idea is that the monitor boots up, and if IPADD is set to DHCP, then
+ * DHCP is used to populate shell variables with a server-supplied IP
+ * address, NetMask and Gateway IP address. Then, when the application
+ * is launched (probably via TFS), it can retrieve the content of those
+ * shell variables for use by the application.
+ *
+ * Sequence of events for this limited implementation of DHCP...
+ * Client issues a DHCP_DISCOVER, server responds with a DHCP_OFFER,
+ * client issues a DHCP_REQUEST and server responds with a DHCP_ACK.
+ * DISCOVER: request by the client to broadcast the fact that it is looking
+ * for a DHCP server.
+ * OFFER: reply from the server when it receives a DISCOVER request from
+ * a client. The offer may contain all the information that the DHCP
+ * client needs to bootup, but this is dependent on the configuration of
+ * the server.
+ * REQUEST: request by the client for the server (now known because an OFFER
+ * was received) to send it the information it needs.
+ * ACK: reply from the server with the information requested.
+ *
+ * NOTE: this file contains a generic DHCP client supporting "automatic
+ * allocation mode" (infinite lease time). There are several different
+ * application-specific enhancements that can be added and hopefully
+ * they have been isolated through the use of the dhcp_00.c file.
+ * I've attempted to isolate as much of the non-generic code to
+ * the file dhcp_XX.c (where dhcp_00.c is the default code). If non-default
+ * code is necessary, then limit the changes to a new dhcp_XX.c file. This
+ * will allow the code in this file to stay generic; hence, the user of this
+ * code will be able to accept monitor upgrades without the need to touch
+ * this file. The makefile must link in some additional dhcp_XX.c file
+ * (default is dhcp_00.c). Bottom line... there should be no need to modify
+ * this file for application-specific stuff; if there is, please let me know.
+ *
+ * NOTE1: the shell variable IPADD can also be set to DHCPV or DHCPv to
+ * enable different levels of verbosity during DHCP transactions... 'V'
+ * is full DHCP verbosity and 'v' only prints the DhcpSetEnv() calls.
+ *
+ * NOTE2: this file supports DHCP and BOOTP. Most of the function names
+ * refer to DHCP even though their functionality is shared by both DHCP
+ * and BOOTP. This is because I wrote this originally for DHCP, then added
+ * the hooks for BOOTP... Bottom line: don't let the names confuse you!
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "endian.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "timer.h"
+
+int DHCPStartup(short), BOOTPStartup(short);
+int DhcpSetEnv(char *,char *);
+int SendDHCPDiscover(int,short);
+void dhcpDumpVsa(void), printDhcpOptions(uchar *);
+
+unsigned short DHCPState;
+
+#if INCLUDE_DHCPBOOT
+
+static struct elapsed_tmr dhcpTmr;
+static int DHCPCommandIssued;
+static ulong DHCPTransactionId;
+
+/* Variables used for DHCP Class ID specification: */
+static char *DHCPClassId;
+static int DHCPClassIdSize;
+
+/* Variables used for DHCP Client ID specification: */
+static char DHCPClientId[32];
+static int DHCPClientIdSize, DHCPClientIdType;
+
+/* Variables used for setting up a DHCP Parameter Request List: */
+static uchar DHCPRequestList[32];
+static int DHCPRqstListSize;
+
+/* Variable to keep track of elapsed seconds since DHCP started: */
+static short DHCPElapsedSecs;
+
+char *DhcpHelp[] = {
+ "Issue a DHCP discover",
+ "-[brvV] [vsa]",
+#if INCLUDE_VERBOSEHELP
+ "Options...",
+ " -b use bootp",
+ " -r retry",
+ " -v|V verbosity",
+#endif
+ 0,
+};
+
+int
+Dhcp(int argc,char *argv[])
+{
+ int opt, bootp;
+
+ bootp = 0;
+ DHCPCommandIssued = 1;
+ while ((opt=getopt(argc,argv,"brvV")) != -1) {
+ switch(opt) {
+ case 'b':
+ bootp = 1;
+ break;
+ case 'r':
+ DHCPCommandIssued = 0;
+ break;
+#if INCLUDE_ETHERVERBOSE
+ case 'v':
+ EtherVerbose = SHOW_DHCP;
+ break;
+ case 'V':
+ EtherVerbose = DHCP_VERBOSE;
+ break;
+#endif
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc == optind+1) {
+ if (!strcmp(argv[optind],"vsa")) {
+ dhcpDumpVsa();
+ return(CMD_SUCCESS);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (argc != optind)
+ return(CMD_PARAM_ERROR);
+
+ startElapsedTimer(&dhcpTmr,RetransmitDelay(DELAY_INIT_DHCP)*1000);
+
+ if (bootp) {
+ DHCPState = BOOTPSTATE_INITIALIZE;
+ if (DHCPCommandIssued)
+ BOOTPStartup(0);
+ }
+ else {
+ DHCPState = DHCPSTATE_INITIALIZE;
+ if (DHCPCommandIssued)
+ DHCPStartup(0);
+ }
+ return(CMD_SUCCESS);
+}
+
+/* dhcpDumpVsa():
+ * Simply dump the content of the VSA shell variable in DHCP format.
+ * The variable content is stored in ascii and must be converted to binary
+ * prior to calling printDhcpOptions().
+ */
+void
+dhcpDumpVsa(void)
+{
+ int i;
+ char tmp[3], *vsa_b, *vsa_a, len;
+
+ vsa_a = getenv("DHCPVSA");
+ if ((!vsa_a) || (!strcmp(vsa_a,"TRUE")))
+ return;
+ len = strlen(vsa_a);
+ vsa_b = malloc(len);
+ if (!vsa_b)
+ return;
+
+ len >>= 1;
+ tmp[2] = 0;
+ for(i=0;i<len;i++) {
+ tmp[0] = *vsa_a++;
+ tmp[1] = *vsa_a++;
+ vsa_b[i] = (char)strtol(tmp,0,16);
+ }
+ /* First 4 bytes of DHCPVSA is the cookie, so skip over that. */
+ printDhcpOptions((unsigned char *)vsa_b+4);
+ free(vsa_b);
+}
+
+void
+dhcpDisable()
+{
+ DHCPState = DHCPSTATE_NOTUSED;
+}
+
+/* DHCPStartup():
+ * This function is called at the point in which the ethernet interface is
+ * started if, and only if, the IPADD shell variable is set to DHCP.
+ * In older version of DHCP, the default was to use "LUCENT.PPA.1.1" as
+ * the default vcid. Now it is only used if specified in the shell variable
+ * DHCPCLASSID. The same strategy applies to DHCPCLIENTID.
+*/
+int
+DHCPStartup(short seconds)
+{
+ char *id, *colon, *rlist;
+
+#if !INCLUDE_TFTP
+ printf("WARNING: DHCP can't load bootfile, TFTP not built into monitor.\n");
+#endif
+
+ /* The format of DHCPCLASSID is simply a string of characters. */
+ id = getenv("DHCPCLASSID");
+ if (id)
+ DHCPClassId = id;
+ else
+ DHCPClassId = "";
+ DHCPClassIdSize = strlen(DHCPClassId);
+
+ /* The format of DHCPCLIENTID is "TYPE:ClientID" where 'TYPE is a
+ * decimal number ranging from 1-255 used as the "type" portion of
+ * the option, and ClientID is a string of ascii-coded hex pairs
+ * that are converted to binary and used as the client identifier.
+ */
+ id = getenv("DHCPCLIENTID");
+ if (id) {
+ colon = strchr(id,':');
+ if ((colon) && (!(strlen(colon+1) & 1))) {
+ DHCPClientIdType = atoi(id);
+ colon++;
+ for(DHCPClientIdSize=0;*colon;DHCPClientIdSize++) {
+ uchar tmp;
+
+ tmp = colon[2];
+ colon[2] = 0;
+ DHCPClientId[DHCPClientIdSize] = (uchar)strtol(colon,0,16);
+ colon[2] = tmp;
+ colon+=2;
+ }
+ }
+ }
+ else
+ DHCPClientIdSize = 0;
+
+ /* The format of DHCPRQSTLIST is #:#:#:#:# where each '#' is a decimal
+ * number representing a parameter to be requested via the Parameter
+ * Request List option...
+ */
+ rlist = getenv("DHCPRQSTLIST");
+ if (rlist) {
+ DHCPRqstListSize = 0;
+ colon = rlist;
+ while(*colon) {
+ if (*colon++ == ':')
+ DHCPRqstListSize++;
+ }
+ if (DHCPRqstListSize > sizeof(DHCPRequestList)) {
+ printf("DHCPRQSTLIST too big.\n");
+ DHCPRqstListSize = 0;
+ }
+ else {
+ char *rqst;
+
+ DHCPRqstListSize = 0;
+ rqst = rlist;
+ while(1) {
+ DHCPRequestList[DHCPRqstListSize++] = strtol(rqst,&colon,0);
+ if (*colon != ':')
+ break;
+ rqst = colon+1;
+ }
+ DHCPRequestList[DHCPRqstListSize] = 0;
+ }
+ }
+ else
+ DHCPRqstListSize = 0;
+
+ return(SendDHCPDiscover(0,seconds));
+}
+
+int
+BOOTPStartup(short seconds)
+{
+ return(SendDHCPDiscover(1,seconds));
+}
+
+uchar *
+dhcpLoadShellVarOpts(uchar *options)
+{
+ if (DHCPClassIdSize) {
+ *options++ = DHCPOPT_CLASSID;
+ *options++ = DHCPClassIdSize;
+ memcpy((char *)options, (char *)DHCPClassId, DHCPClassIdSize);
+ options += DHCPClassIdSize;
+ }
+ if (DHCPClientIdSize) {
+ *options++ = DHCPOPT_CLIENTID;
+ *options++ = DHCPClientIdSize+1;
+ *options++ = DHCPClientIdType;
+ memcpy((char *)options, (char *)DHCPClientId, DHCPClientIdSize);
+ options += DHCPClientIdSize;
+ }
+ if (DHCPRqstListSize) {
+ *options++ = DHCPOPT_PARMRQSTLIST;
+ *options++ = DHCPRqstListSize;
+ memcpy((char *)options, (char *)DHCPRequestList, DHCPRqstListSize);
+ options += DHCPRqstListSize;
+ }
+ return(options);
+}
+
+/* SendDHCPDiscover()
+ * The DHCPDISCOVER is issued as an ethernet broadcast. IF the bootp
+ * flag is non-zero then just do a bootp request (a subset of the
+ * DHCPDISCOVER stuff).
+ */
+int
+SendDHCPDiscover(int bootp,short seconds)
+{
+ struct dhcphdr *dhcpdata;
+ struct bootphdr *bootpdata;
+ struct ether_header *te;
+ struct ip *ti;
+ struct Udphdr *tu;
+ ushort uh_ulen;
+ int optlen;
+ char *dhcpflags;
+ ulong cookie;
+ uchar *dhcpOptions, *dhcpOptionsBase;
+
+ /* Retrieve an ethernet buffer from the driver and populate the
+ * ethernet level of packet:
+ */
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6);
+ memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6);
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it appropriately: */
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+ ti->ip_id = 0;
+ ti->ip_off = ecs(0x4000); /* No fragmentation allowed */
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memset((char *)&ti->ip_src.s_addr,0,4);
+ memset((char *)&ti->ip_dst.s_addr,0xff,4);
+
+ /* Now udp... */
+ tu = (struct Udphdr *) (ti + 1);
+ tu->uh_sport = ecs(DhcpClientPort);
+ tu->uh_dport = ecs(DhcpServerPort);
+
+ /* First the stuff that is the same for BOOTP or DHCP... */
+ bootpdata = (struct bootphdr *)(tu+1);
+ dhcpdata = (struct dhcphdr *)(tu+1);
+ dhcpdata->op = DHCPBOOTP_REQUEST;
+ dhcpdata->htype = 1;
+ dhcpdata->hlen = 6;
+ dhcpdata->hops = 0;
+ dhcpdata->seconds = ecs(seconds);
+ memset((char *)dhcpdata->bootfile,0,sizeof(dhcpdata->bootfile));
+ memset((char *)dhcpdata->server_hostname,0,sizeof(dhcpdata->server_hostname));
+
+ /* For the first DHCPDISCOVER issued, establish a transaction id based
+ * on a crc32 of the mac address. For each DHCPDISCOVER after that,
+ * just increment.
+ */
+ if (!DHCPTransactionId)
+ DHCPTransactionId = crc32(BinEnetAddr,6);
+ else
+ DHCPTransactionId++;
+
+ memcpy((char *)&dhcpdata->transaction_id,(char *)&DHCPTransactionId,4);
+ memset((char *)&dhcpdata->client_ip,0,4);
+ memset((char *)&dhcpdata->your_ip,0,4);
+ memset((char *)&dhcpdata->server_ip,0,4);
+ memset((char *)&dhcpdata->router_ip,0,4);
+ memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6);
+ dhcpflags = getenv("DHCPFLAGS");
+ if (dhcpflags) /* 0x8000 is the only bit used currently. */
+ dhcpdata->flags = (ushort)strtoul(dhcpflags,0,0);
+ else
+ dhcpdata->flags = 0;
+
+ self_ecs(dhcpdata->flags);
+
+ /* Finally, the DHCP or BOOTP specific stuff...
+ * Based on RFC1534 (Interoperation Between DHCP and BOOTP), any message
+ * received by a DHCP server that contains a 'DHCP_MESSAGETYPE' option
+ * is assumed to have been sent by a DHCP client. A message without the
+ * DHCP_MESSAGETYPE option is assumed to have been sent by a BOOTP
+ * client.
+ */
+ uh_ulen = optlen = 0;
+ if (bootp) {
+ memset((char *)bootpdata->vsa,0,sizeof(bootpdata->vsa));
+ uh_ulen = sizeof(struct Udphdr) + sizeof(struct bootphdr);
+ tu->uh_ulen = ecs(uh_ulen);
+ }
+ else {
+ if (!buildDhcpHdr(dhcpdata)) {
+ /* The cookie should only be loaded at the start of the
+ * vendor specific area if vendor-specific options are present.
+ */
+ cookie = ecl(STANDARD_MAGIC_COOKIE);
+ memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4);
+ dhcpOptionsBase = (uchar *)(dhcpdata+1);
+ dhcpOptions = dhcpOptionsBase;
+ *dhcpOptions++ = DHCPOPT_MESSAGETYPE;
+ *dhcpOptions++ = 1;
+ *dhcpOptions++ = DHCPDISCOVER;
+ dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);
+ *dhcpOptions++ = 0xff;
+
+ /* Calculate ip and udp lengths after all DHCP options are loaded
+ * so that the size is easily computed based on the value of the
+ * dhcpOptions pointer. Apparently, the minimum size of the
+ * options space is 64 bytes, we determined this simply because
+ * the DHCP server we are using complains if the size is smaller.
+ * Also, NULL out the space that is added to get a minimum option
+ * size of 64 bytes,
+ */
+ optlen = dhcpOptions - dhcpOptionsBase;
+ if (optlen < 64) {
+ memset((char *)dhcpOptions,0,64-optlen);
+ optlen = 64;
+ }
+ uh_ulen = sizeof(struct Udphdr)+sizeof(struct dhcphdr)+optlen;
+ tu->uh_ulen = ecs(uh_ulen);
+ }
+ }
+ ti->ip_len = ecs((sizeof(struct ip) + uh_ulen));
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ if (bootp) {
+ DHCPState = BOOTPSTATE_REQUEST;
+ sendBuffer(BOOTPSIZE);
+ }
+ else {
+ DHCPState = DHCPSTATE_SELECT;
+ sendBuffer(DHCPSIZE+optlen);
+ }
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ printf(" %s startup (%d elapsed secs)\n",
+ bootp ? "BOOTP" : "DHCP",seconds);
+#endif
+ return(0);
+}
+
+/* SendDHCPRequest()
+ * The DHCP request is broadcast back with the "server identifier" option
+ * set to indicate which server has been selected (in case more than one
+ * has offered).
+ */
+int
+SendDHCPRequest(struct dhcphdr *dhdr)
+{
+ uchar *op;
+ struct dhcphdr *dhcpdata;
+ struct ether_header *te;
+ struct ip *ti;
+ struct Udphdr *tu;
+ int optlen;
+ uchar *dhcpOptions, *dhcpOptionsBase;
+ ushort uh_ulen;
+ ulong cookie;
+
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6);
+ memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6);
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+ ti->ip_id = 0;
+ ti->ip_off = ecs(IP_DONTFRAG); /* No fragmentation allowed */
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memset((char *)&ti->ip_src.s_addr,0,4);
+ memset((char *)&ti->ip_dst.s_addr,0xff,4);
+
+ tu = (struct Udphdr *) (ti + 1);
+ tu->uh_sport = ecs(DhcpClientPort);
+ tu->uh_dport = ecs(DhcpServerPort);
+
+ dhcpdata = (struct dhcphdr *)(tu+1);
+ dhcpdata->op = DHCPBOOTP_REQUEST;
+ dhcpdata->htype = 1;
+ dhcpdata->hlen = 6;
+ dhcpdata->hops = 0;
+ dhcpdata->seconds = ecs(DHCPElapsedSecs);
+ /* Use the same xid for the request as was used for the discover...
+ * (rfc2131 section 4.4.1)
+ */
+ memcpy((char *)&dhcpdata->transaction_id,(char *)&dhdr->transaction_id,4);
+
+ dhcpdata->flags = dhdr->flags;
+ memset((char *)&dhcpdata->client_ip,0,4);
+ memcpy((char *)&dhcpdata->your_ip,(char *)&dhdr->your_ip,4);
+ memset((char *)&dhcpdata->server_ip,0,4);
+ memset((char *)&dhcpdata->router_ip,0,4);
+ cookie = ecl(STANDARD_MAGIC_COOKIE);
+ memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4);
+ memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6);
+
+ dhcpOptionsBase = (uchar *)(dhcpdata+1);
+ dhcpOptions = dhcpOptionsBase;
+ *dhcpOptions++ = DHCPOPT_MESSAGETYPE;
+ *dhcpOptions++ = 1;
+ *dhcpOptions++ = DHCPREQUEST;
+
+ *dhcpOptions++ = DHCPOPT_SERVERID; /* Server id ID */
+ *dhcpOptions++ = 4;
+ op = DhcpGetOption(DHCPOPT_SERVERID,(uchar *)(dhdr+1));
+ if (op)
+ memcpy((char *)dhcpOptions, (char *)op+2,4);
+ else
+ memset((char *)dhcpOptions, (char)0,4);
+ dhcpOptions+=4;
+
+ *dhcpOptions++ = DHCPOPT_REQUESTEDIP; /* Requested IP */
+ *dhcpOptions++ = 4;
+ memcpy((char *)dhcpOptions,(char *)&dhdr->your_ip,4);
+ dhcpOptions += 4;
+ dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);
+ *dhcpOptions++ = 0xff;
+
+ /* See note in SendDHCPDiscover() regarding the computation of the
+ * ip and udp lengths.
+ */
+ optlen = dhcpOptions - dhcpOptionsBase;
+ if (optlen < 64)
+ optlen = 64;
+ uh_ulen = sizeof(struct Udphdr) + sizeof(struct dhcphdr) + optlen;
+ tu->uh_ulen = ecs(uh_ulen);
+ ti->ip_len = ecs((sizeof(struct ip) + uh_ulen));
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ DHCPState = DHCPSTATE_REQUEST;
+ sendBuffer(DHCPSIZE+optlen);
+ return(0);
+}
+
+/* randomDhcpStartupDelay():
+ * Randomize the startup for DHCP/BOOTP (see RFC2131 Sec 4.4.1)...
+ * Return a value between 1 and 10 based on the last 4 bits of the
+ * board's MAC address.
+ * The presence of the DHCPSTARTUPDELAY shell variable overrides
+ * this random value.
+ */
+int
+randomDhcpStartupDelay(void)
+{
+ char *env;
+ int randomsec;
+
+ env = getenv("DHCPSTARTUPDELAY");
+ if (env) {
+ randomsec = (int)strtol(env,0,0);
+ }
+ else {
+ randomsec = (BinEnetAddr[5] & 0xf);
+ if (randomsec > 10)
+ randomsec -= 7;
+ else if (randomsec == 0)
+ randomsec = 10;
+ }
+ return(randomsec);
+}
+
+/* dhcpStateCheck():
+ * Called by pollethernet() to monitor the progress of DHCPState.
+ * The retry rate is "almost" what is specified in the RFC...
+ * Refer to the RetransmitDelay() function for details.
+ *
+ * Regarding timing...
+ * The DHCP startup may be running without an accurate measure of elapsed
+ * time. The value of LoopsPerMillisecond is used as an approximation of
+ * the number of times this function must be called for one second to
+ * pass (dependent on network traffic, etc...). RetransmitDelay() is
+ * called to retrieve the number of seconds that must elapse prior to
+ * retransmitting the last DHCP message. The static variables in this
+ * function are used to keep track of that timeout.
+ */
+void
+dhcpStateCheck(void)
+{
+ int delaysecs;
+
+ /* If the DHCP command has been issued, it is assumed that the script
+ * is handling retries...
+ */
+ if (DHCPCommandIssued)
+ return;
+
+ /* Return, restart or fall through; depending on DHCPState... */
+ switch(DHCPState) {
+ case DHCPSTATE_NOTUSED:
+ case BOOTPSTATE_COMPLETE:
+ case DHCPSTATE_BOUND:
+ return;
+ case DHCPSTATE_RESTART:
+ DHCPStartup(0);
+ return;
+ case BOOTPSTATE_RESTART:
+ BOOTPStartup(0);
+ return;
+ case DHCPSTATE_INITIALIZE:
+ case BOOTPSTATE_INITIALIZE:
+ delaysecs = randomDhcpStartupDelay();
+ startElapsedTimer(&dhcpTmr,delaysecs * 1000);
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs);
+#endif
+ if (DHCPState & BOOTP_MODE)
+ DHCPState = BOOTPSTATE_INITDELAY;
+ else
+ DHCPState = DHCPSTATE_INITDELAY;
+ return;
+ case DHCPSTATE_INITDELAY:
+ case BOOTPSTATE_INITDELAY:
+ if (msecElapsed(&dhcpTmr) || (gotachar())) {
+ DHCPElapsedSecs = 0;
+ startElapsedTimer(&dhcpTmr,
+ RetransmitDelay(DELAY_INIT_DHCP)*1000);
+ if (DHCPState & BOOTP_MODE)
+ BOOTPStartup(0);
+ else
+ DHCPStartup(0);
+ }
+ return;
+ default:
+ break;
+ }
+
+ if (msecElapsed(&dhcpTmr)) {
+ int lastdelay;
+
+ lastdelay = RetransmitDelay(DELAY_RETURN);
+ delaysecs = RetransmitDelay(DELAY_INCREMENT);
+
+ if (delaysecs != RETRANSMISSION_TIMEOUT) {
+ DHCPElapsedSecs += delaysecs;
+ startElapsedTimer(&dhcpTmr,delaysecs*1000);
+
+ if (DHCPState & BOOTP_MODE)
+ BOOTPStartup(DHCPElapsedSecs);
+ else
+ DHCPStartup(DHCPElapsedSecs);
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ printf(" DHCP/BOOTP retry (%d secs)\n",lastdelay);
+#endif
+ }
+ else {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ printf(" DHCP/BOOTP giving up\n");
+#endif
+ }
+ }
+}
+
+/* xidCheck():
+ * Common function used for DHCP and BOOTP to verify incoming transaction
+ * id...
+ */
+int
+xidCheck(char *id,int bootp)
+{
+ if (memcmp(id,(char *)&DHCPTransactionId,4)) {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP) {
+ printf("%s ignored: unexpected transaction id.\n",
+ bootp ? "BOOTP":"DHCP");
+ }
+#endif
+ return(-1);
+ }
+ return(0);
+}
+
+int
+loadBootFile(int bootp)
+{
+#if INCLUDE_TFTP
+ ulong addr;
+ char bfile[TFSNAMESIZE+TFSINFOSIZE+32];
+ char *tfsfile, *bootfile, *tftpsrvr, *flags, *info;
+
+ /* If the DHCPDONTBOOT variable is present, then don't put
+ * the file in TFS and don't run it. Just complete the TFTP
+ * transfer, and allow the user to deal with the downloaded
+ * data using APPRAMBASE and TFTPGET shell variables (probably
+ * through some boot script).
+ */
+ if (getenv("DHCPDONTBOOT"))
+ tfsfile = (char *)0;
+ else
+ tfsfile = bfile;
+
+ /* If both bootfile and server-ip are specified, then boot it.
+ * The name of the file must contain information that tells the monitor
+ * what type of file it is, so the first 'comma' extension is used as
+ * the flag field (if it is a valid flag set) and the second 'comma'
+ * extension is used as the info field.
+ */
+ bootfile = getenv("BOOTFILE");
+ tftpsrvr = getenv("BOOTSRVR");
+
+ if (bootfile && tftpsrvr) {
+ int tftpworked;
+
+ addr = getAppRamStart();
+ info = "";
+ flags = "e";
+ strncpy(bfile,bootfile,sizeof(bfile));
+
+ if (tfsfile) {
+ char *icomma, *fcomma;
+
+ fcomma = strchr(bfile,',');
+ if (fcomma) {
+ icomma = strchr(fcomma+1,',');
+ if (icomma) {
+ *icomma = 0;
+ info = icomma+1;
+ }
+ *fcomma = 0;
+ if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != 0)
+ flags = fcomma+1;
+ }
+ }
+
+ /* Since we are about to transition to TFTP, match TFTP's
+ * verbosity to the verbosity currently set for DHCP...
+ */
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ EtherVerbose |= SHOW_TFTP_STATE;
+#endif
+
+ /* If the TFTP transfer succeeds, attempt to run the boot file;
+ * if the TFTP transfer fails, then re-initialize the tftp state
+ * and set the DHCP state such that dhcpStateCheck() will
+ * cause the handshake to start over again...
+ */
+ tftpworked = tftpGet(addr,tftpsrvr,"octet",bfile,tfsfile,flags,info);
+ if (tftpworked) {
+#if INCLUDE_ETHERVERBOSE
+ EtherVerbose = 0;
+#endif
+ if (tfsfile) {
+ int err;
+ char *argv[2];
+
+ argv[0] = bfile;
+ argv[1] = 0;
+ err = tfsrun(argv,0);
+ if (err != TFS_OKAY)
+ printf("DHCP-invoked tfsrun(%s) failed: %s\n",
+ bfile,tfserrmsg(err));
+ }
+ }
+ else {
+ tftpInit();
+ RetransmitDelay(DELAY_INIT_TFTP);
+#if INCLUDE_ETHERVERBOSE
+ EtherVerbose &= ~SHOW_TFTP_STATE;
+#endif
+ if (bootp)
+ DHCPState = BOOTPSTATE_RESTART;
+ else
+ DHCPState = DHCPSTATE_RESTART;
+ }
+ }
+#if INCLUDE_ETHERVERBOSE
+ else
+ EtherVerbose &= ~(SHOW_DHCP|DHCP_VERBOSE);
+#endif
+#endif
+ return(0);
+}
+
+/* processBOOTP():
+ * A subset of processDHCP().
+ * We get here from processDHCP, because it detects that the current
+ * value of DHCPState is BOOTPSTATE_REQUEST.
+ */
+int
+processBOOTP(struct ether_header *ehdr,ushort size)
+{
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ struct bootphdr *bhdr;
+ ulong ip, temp_ip, cookie;
+ uchar buf[16], *op;
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_HEX)
+ printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII);
+#endif
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
+ bhdr = (struct bootphdr *)(uhdr+1);
+
+ /* Verify incoming transaction id matches the previous outgoing value: */
+ if (xidCheck((char *)&bhdr->transaction_id,1) < 0)
+ return(-1);
+
+ /* If bootfile is nonzero, store it into BOOTFILE shell var: */
+ if (bhdr->bootfile[0])
+ DhcpSetEnv("BOOTFILE", (char *)bhdr->bootfile);
+
+ /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */
+ memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4);
+ if (temp_ip)
+ DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf));
+
+ /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */
+ memcpy((char *)&temp_ip,(char *)&bhdr->router_ip,4);
+ if (temp_ip)
+ DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf));
+
+ /* Assign IP address loaded in "your_ip" to the IPADD shell var: */
+ memcpy((char *)BinIpAddr,(char *)&bhdr->your_ip,4);
+ memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4);
+ DhcpSetEnv("IPADD",(char *)IpToString(temp_ip,(char *)buf));
+
+ /* If STANDARD_MAGIC_COOKIE exists, then process options... */
+ memcpy((char *)&cookie,(char *)bhdr->vsa,4);
+ if (cookie == ecl(STANDARD_MAGIC_COOKIE)) {
+ /* Assign subnet mask option to NETMASK shell var (if found): */
+ op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]);
+ if (op) {
+ memcpy((char *)&ip,(char *)op+2,4);
+ DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf));
+ }
+ /* Assign first router option to GIPADD shell var (if found): */
+ /* (the router option can have multiple entries, and they are */
+ /* supposed to be in order of preference, so use the first one) */
+ op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]);
+ if (op) {
+ memcpy((char *)&ip, (char *)op+2,4);
+ DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf));
+ }
+ }
+
+ DhcpBootpDone(1,(struct dhcphdr *)bhdr,
+ size - ((int)((int)&bhdr->vsa - (int)ehdr)));
+
+ DHCPState = BOOTPSTATE_COMPLETE;
+
+ /* Call loadBootFile() which will then kick off a tftp client
+ * transfer if both BOOTFILE and BOOTSRVR shell variables are
+ * loaded; otherwise, we are done.
+ */
+ loadBootFile(1);
+
+ return(0);
+}
+
+int
+processDHCP(struct ether_header *ehdr,ushort size)
+{
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ struct dhcphdr *dhdr;
+ uchar buf[16], *op, msgtype;
+ ulong ip, temp_ip, leasetime;
+
+ if (DHCPState == BOOTPSTATE_REQUEST)
+ return(processBOOTP(ehdr,size));
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_HEX)
+ printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII);
+#endif
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
+ dhdr = (struct dhcphdr *)(uhdr+1);
+
+ /* Verify incoming transaction id matches the previous outgoing value: */
+ if (xidCheck((char *)&dhdr->transaction_id,0) < 0)
+ return(-1);
+
+ op = DhcpGetOption(DHCPOPT_MESSAGETYPE,(uchar *)(dhdr+1));
+ if (op)
+ msgtype = *(op+2);
+ else
+ msgtype = DHCPUNKNOWN;
+
+ if ((DHCPState == DHCPSTATE_SELECT) && (msgtype == DHCPOFFER)) {
+ /* Target issued the DISCOVER, the incoming packet is the server's
+ * OFFER reply. The function "ValidDHCPOffer() will return
+ * non-zero if the request is to be sent.
+ */
+ if (ValidDHCPOffer(dhdr))
+ SendDHCPRequest(dhdr);
+#if INCLUDE_ETHERVERBOSE
+ else if (EtherVerbose & SHOW_DHCP) {
+ char ip[4];
+ memcpy(ip,(char *)&ihdr->ip_src,4);
+ printf(" DHCP offer from %d.%d.%d.%d ignored\n",
+ ip[0],ip[1],ip[2],ip[3]);
+ }
+#endif
+ }
+ else if ((DHCPState == DHCPSTATE_REQUEST) && (msgtype == DHCPACK)) {
+ ulong cookie;
+ uchar ipsrc[4];
+
+ /* Target issued the REQUEST, the incoming packet is the server's
+ * ACK reply. We're done so load the environment now.
+ */
+ memcpy((char *)ipsrc,(char *)&ihdr->ip_src,4);
+ shell_sprintf("DHCPOFFERFROM","%d.%d.%d.%d",
+ ipsrc[0],ipsrc[1],ipsrc[2],ipsrc[3]);
+
+ /* If bootfile is nonzero, store it into BOOTFILE shell var: */
+ if (dhdr->bootfile[0])
+ DhcpSetEnv("BOOTFILE",(char *)dhdr->bootfile);
+
+ /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */
+ memcpy((char *)&temp_ip,(char *)&dhdr->server_ip,4);
+ if (temp_ip)
+ DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf));
+
+ /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */
+ memcpy((char *)&temp_ip,(char *)&dhdr->router_ip,4);
+ if (temp_ip)
+ DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf));
+
+ /* Assign IP address loaded in "your_ip" to the IPADD shell var: */
+ memcpy((char *)BinIpAddr,(char *)&dhdr->your_ip,4);
+ memcpy((char *)&temp_ip,(char *)&dhdr->your_ip,4);
+ DhcpSetEnv("IPADD",IpToString(temp_ip,(char *)buf));
+
+ op = DhcpGetOption(DHCPOPT_ROOTPATH,(uchar *)(dhdr+1));
+ if (op)
+ DhcpSetEnv("ROOTPATH",(char *)op+2);
+
+ /* If STANDARD_MAGIC_COOKIE exists, process options... */
+ memcpy((char *)&cookie,(char *)&dhdr->magic_cookie,4);
+ if (cookie == ecl(STANDARD_MAGIC_COOKIE)) {
+ /* Assign subnet mask to NETMASK shell var (if found): */
+ op = DhcpGetOption(DHCPOPT_SUBNETMASK,(uchar *)(dhdr+1));
+ if (op) {
+ memcpy((char *)&ip,(char *)op+2,4);
+ DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf));
+ }
+
+ /* Assign Hostname to HOSTNAME shell var (if found): */
+ op = DhcpGetOption(DHCPOPT_HOSTNAME,(uchar *)(dhdr+1));
+ if (op) {
+ char tmpnam[64];
+ int optlen = *(op+1);
+
+ if (optlen < sizeof(tmpnam)-1) {
+ memset(tmpnam,0,sizeof(tmpnam));
+ memcpy(tmpnam,(char *)(op+2),optlen);
+ DhcpSetEnv("HOSTNAME",tmpnam);
+ }
+ }
+
+ /* Assign gateway IP to GIPADD shell var (if found):
+ * (the router option can have multiple entries, and they are
+ * supposed to be in order of preference, so use the first one).
+ */
+ op = DhcpGetOption(DHCPOPT_ROUTER,(uchar *)(dhdr+1));
+ if (op) {
+ memcpy((char *)&ip,(char *)op+2,4);
+ DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf));
+ }
+ /* Process DHCPOPT_LEASETIME option as follows...
+ * If not set, assume infinite and clear DHCPLEASETIME shellvar.
+ * If set, then look for the presence of the DHCPLEASETIME shell
+ * variable and use it as a minimum. If the incoming value is
+ * >= what is in the shell variable, accept it and load the shell
+ * variable with this value. If incoming lease time is less than
+ * what is stored in DHCPLEASETIME, ignore the request.
+ * If DHCPLEASETIME is not set, then just load the incoming lease
+ * into the DHCPLEASETIME shell variable and accept the offer.
+ */
+ op = DhcpGetOption(DHCPOPT_LEASETIME,(uchar *)(dhdr+1));
+ if (op) {
+ memcpy((char *)&leasetime,(char *)op+2,4);
+ leasetime = ecl(leasetime);
+ if (getenv("DHCPLEASETIME")) {
+ ulong minleasetime;
+ minleasetime = strtol(getenv("DHCPLEASETIME"),0,0);
+ if (leasetime < minleasetime) {
+ printf("DHCP: incoming lease time 0x%lx too small.\n",
+ leasetime);
+ return(-1);
+ }
+ }
+ sprintf((char *)buf,"0x%lx",leasetime);
+ setenv("DHCPLEASETIME",(char *)buf);
+ }
+ else
+ setenv("DHCPLEASETIME",(char *)0);
+ }
+
+ /* Check for vendor specific stuff... */
+ DhcpVendorSpecific(dhdr);
+
+ DhcpBootpDone(0,dhdr,
+ size - ((int)((int)&dhdr->magic_cookie - (int)ehdr)));
+
+ DHCPState = DHCPSTATE_BOUND;
+
+ /* Call loadBootFile() which will then kick off a tftp client
+ * transfer if both BOOTFILE and BOOTSRVR shell variables are
+ * loaded; otherwise, we are done.
+ */
+ loadBootFile(0);
+ }
+ return(0);
+}
+
+char *
+DHCPop(int op)
+{
+ switch(op) {
+ case DHCPBOOTP_REQUEST:
+ return("REQUEST");
+ case DHCPBOOTP_REPLY:
+ return("REPLY");
+ default:
+ return("???");
+ }
+}
+
+char *
+DHCPmsgtype(int msg)
+{
+ char *type;
+
+ switch(msg) {
+ case DHCPDISCOVER:
+ type = "DISCOVER";
+ break;
+ case DHCPOFFER:
+ type = "OFFER";
+ break;
+ case DHCPREQUEST:
+ type = "REQUEST";
+ break;
+ case DHCPDECLINE:
+ type = "DECLINE";
+ break;
+ case DHCPACK:
+ type = "ACK";
+ break;
+ case DHCPNACK:
+ type = "NACK";
+ break;
+ case DHCPRELEASE:
+ type = "RELEASE";
+ break;
+ case DHCPINFORM:
+ type = "INFORM";
+ break;
+ case DHCPFORCERENEW:
+ type = "FORCERENEW";
+ break;
+ case DHCPLEASEQUERY:
+ type = "LEASEQUERY";
+ break;
+ case DHCPLEASEUNASSIGNED:
+ type = "LEASEUNASSIGNED";
+ break;
+ case DHCPLEASEUNKNOWN:
+ type = "LEASEUNKNOWN";
+ break;
+ case DHCPLEASEACTIVE:
+ type = "LEASEACTIVE";
+ break;
+ default:
+ type = "???";
+ break;
+ }
+ return(type);
+}
+
+/* printDhcpOptions():
+ * Verbosely display the DHCP options pointed to by the incoming
+ * options pointer.
+ */
+void
+printDhcpOptions(uchar *options)
+{
+ int i, safety, opt, optlen;
+
+ safety = 0;
+ while(*options != 0xff) {
+ if (safety++ > 10000) {
+ printf("Aborting, overflow likely\n");
+ break;
+ }
+ opt = (int)*options++;
+ if (opt == 0) /* padding */
+ continue;
+ printf(" option %3d: ",opt);
+ optlen = (int)*options++;
+ if (opt==DHCPOPT_MESSAGETYPE) {
+ printf("DHCP_%s",DHCPmsgtype(*options++));
+ }
+ else if ((opt < DHCPOPT_HOSTNAME) ||
+ (opt == DHCPOPT_BROADCASTADDRESS) ||
+ (opt == DHCPOPT_REQUESTEDIP) ||
+ (opt == DHCPOPT_SERVERID) ||
+ (opt == DHCPOPT_NISSERVER)) {
+ for(i=0;i<optlen;i++)
+ printf("%d ",*options++);
+ }
+ else if ((opt == DHCPOPT_NISDOMAINNAME) || (opt == DHCPOPT_CLASSID)) {
+ for(i=0;i<optlen;i++)
+ printf("%c",*options++);
+ }
+ else if (opt == DHCPOPT_CLIENTID) {
+ printf("%d 0x",(int)*options++);
+ for(i=1;i<optlen;i++)
+ printf("%02x",*options++);
+ }
+ else {
+ printf("0x");
+ for(i=0;i<optlen;i++)
+ printf("%02x",*options++);
+ }
+ printf("\n");
+ }
+}
+
+/* printDhcp():
+ * Try to format the DHCP stuff...
+ */
+void
+printDhcp(struct Udphdr *p)
+{
+ struct dhcphdr *d;
+ uchar *client_ip, *your_ip, *server_ip, *router_ip;
+ ulong cookie, xid;
+
+ d = (struct dhcphdr *)(p+1);
+
+ client_ip = (uchar *)&(d->client_ip);
+ your_ip = (uchar *)&(d->your_ip);
+ server_ip = (uchar *)&(d->server_ip);
+ router_ip = (uchar *)&(d->router_ip);
+ memcpy((char *)&xid,(char *)&d->transaction_id,4);
+ /* xid = ecl(xid) */
+
+ printf(" DHCP: sport dport ulen sum\n");
+ printf(" %4d %4d %4d %4d\n",
+ ecs(p->uh_sport), ecs(p->uh_dport), ecs(p->uh_ulen),ecs(p->uh_sum));
+ printf(" op = %s, htype = %d, hlen = %d, hops = %d\n",
+ DHCPop(d->op),d->htype,d->hlen,d->hops);
+ printf(" seconds = %d, flags = 0x%x, xid= 0x%lx\n",
+ ecs(d->seconds),ecs(d->flags),xid);
+ printf(" client_macaddr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ d->client_macaddr[0], d->client_macaddr[1],
+ d->client_macaddr[2], d->client_macaddr[3],
+ d->client_macaddr[4], d->client_macaddr[5]);
+ printf(" client_ip = %d.%d.%d.%d\n",
+ client_ip[0],client_ip[1],client_ip[2],client_ip[3]);
+ printf(" your_ip = %d.%d.%d.%d\n",
+ your_ip[0],your_ip[1],your_ip[2],your_ip[3]);
+ printf(" server_ip = %d.%d.%d.%d\n",
+ server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
+ printf(" router_ip = %d.%d.%d.%d\n",
+ router_ip[0],router_ip[1],router_ip[2],router_ip[3]);
+ if (d->bootfile[0])
+ printf(" bootfile: %s\n", d->bootfile);
+ if (d->server_hostname[0])
+ printf(" server_hostname: %s\n", d->server_hostname);
+
+ /* If STANDARD_MAGIC_COOKIE doesn't exist, then don't process options... */
+ memcpy((char *)&cookie,(char *)&d->magic_cookie,4);
+ if (cookie != ecl(STANDARD_MAGIC_COOKIE))
+ return;
+
+ printDhcpOptions((uchar *)(d+1));
+}
+
+/* DhcpGetOption():
+ * Based on the incoming option pointer and a specified option value,
+ * search through the options list for the value and return a pointer
+ * to that option.
+ */
+uchar *
+DhcpGetOption(unsigned char optval,unsigned char *options)
+{
+ int safety;
+
+ safety = 0;
+ while(*options != 0xff) {
+ if (safety++ > 1000)
+ break;
+ if (*options == 0) { /* Skip over padding. */
+ options++;
+ continue;
+ }
+ if (*options == optval)
+ return(options);
+ options += ((*(options+1)) + 2);
+ }
+ return((uchar *)0);
+}
+
+int
+DhcpSetEnv(char *name,char *value)
+{
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_DHCP)
+ printf(" Dhcp/Bootp SetEnv: %s = %s\n",name,value);
+#endif
+ return(setenv(name,value));
+}
+
+int
+DhcpIPCheck(char *ipadd)
+{
+ char verbose;
+
+ if (!memcmp(ipadd,"DHCP",4)) {
+ verbose = ipadd[4];
+ DHCPState = DHCPSTATE_INITIALIZE;
+ }
+ else if (!memcmp(ipadd,"BOOTP",5)) {
+ verbose = ipadd[5];
+ DHCPState = BOOTPSTATE_INITIALIZE;
+ }
+ else {
+ if (IpToBin(ipadd,BinIpAddr) < 0) {
+ verbose = 0;
+ DHCPState = BOOTPSTATE_INITIALIZE;
+ }
+ else {
+ DHCPState = DHCPSTATE_NOTUSED;
+ return(0);
+ }
+ }
+
+ BinIpAddr[0] = 0;
+ BinIpAddr[1] = 0;
+ BinIpAddr[2] = 0;
+ BinIpAddr[3] = 0;
+#if INCLUDE_ETHERVERBOSE
+ if (verbose == 'V')
+ EtherVerbose = DHCP_VERBOSE;
+ else if (verbose == 'v')
+ EtherVerbose = SHOW_DHCP;
+#endif
+ return(0);
+}
+
+char *
+dhcpStringState(int state)
+{
+ switch(state) {
+ case DHCPSTATE_INITIALIZE:
+ return("DHCP_INITIALIZE");
+ case DHCPSTATE_SELECT:
+ return("DHCP_SELECT");
+ case DHCPSTATE_REQUEST:
+ return("DHCP_REQUEST");
+ case DHCPSTATE_BOUND:
+ return("DHCP_BOUND");
+ case DHCPSTATE_RENEW:
+ return("DHCP_RENEW");
+ case DHCPSTATE_REBIND:
+ return("DHCP_REBIND");
+ case DHCPSTATE_NOTUSED:
+ return("DHCP_NOTUSED");
+ case DHCPSTATE_RESTART:
+ return("DHCP_RESTART");
+ case BOOTPSTATE_INITIALIZE:
+ return("BOOTP_INITIALIZE");
+ case BOOTPSTATE_REQUEST:
+ return("BOOTP_REQUEST");
+ case BOOTPSTATE_RESTART:
+ return("BOOTP_RESTART");
+ case BOOTPSTATE_COMPLETE:
+ return("BOOTP_COMPLETE");
+ default:
+ return("???");
+ }
+}
+
+void
+ShowDhcpStats()
+{
+ printf("Current DHCP State: %s\n",dhcpStringState(DHCPState));
+}
+
+#endif
diff --git a/main/common/dns.c b/main/common/dns.c
new file mode 100755
index 0000000..8947289
--- /dev/null
+++ b/main/common/dns.c
@@ -0,0 +1,760 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * dns.c:
+ *
+ * This file implements a basic DNS client and some form of a multicast-DNS
+ * reponder. The functionality provides the basic ability to retrieve an IP
+ * address from a domain name.
+ * Refer to RFC 1035 section 4.1 for the packet format.
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_DNS
+#include "endian.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "ether.h"
+#include "cli.h"
+#include "timer.h"
+
+const char mDNSIp[] = { 224, 0, 0, 251 };
+const char mDNSMac[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb };
+
+char * dnsErrStr(int errno);
+
+short DnsPort;
+static unsigned short dnsId;
+static unsigned long dnsIP;
+static char dnsErrno, dnsWaiting, dnsCacheInitialized;
+static struct dnscache hostnames[MAX_CACHED_HOSTNAMES];
+
+/* ip_to_bin...
+ * Essentially identical to IpToBin() in ethernet.c, but without
+ * the error message.
+ */
+int
+ip_to_bin(char *ascii,uchar *binary)
+{
+ int i, digit;
+ char *acpy;
+
+ acpy = ascii;
+ for(i=0;i<4;i++) {
+ digit = (int)strtol(acpy,&acpy,10);
+ if (((i != 3) && (*acpy++ != '.')) ||
+ ((i == 3) && (*acpy != 0)) ||
+ (digit < 0) || (digit > 255)) {
+ return(-1);
+ }
+ binary[i] = (uchar)digit;
+ }
+ return(0);
+}
+
+
+/* getHostAddr():
+ * This function is a simplified version of gethostbyname().
+ * Given a domain name, this function will first query a
+ * locally maintained cache then, if not found there, it will
+ * issue a DNS query to retrieve the hosts IP address.
+ */
+unsigned long
+getHostAddr(char *hostname)
+{
+ short port;
+ struct ip *ipp;
+ struct Udphdr *udpp;
+ struct dnshdr *dnsp;
+ struct elapsed_tmr tmr;
+ struct ether_header *enetp;
+ uchar binenet[8], *enetaddr;
+ unsigned long srvrip, binip;
+ char *pp, *np, *srvrname, *dot;
+ int i, namelen, pktsize, ip_len;
+
+ /* First check to see if the incoming host name is simply a
+ * decimal-dot-formatted IP address. If it is, then just
+ * convert it to a 32-bit long and return here...
+ */
+ if (ip_to_bin(hostname,(uchar *)&binip) == 0)
+ return(binip);
+
+ if (!dnsCacheInitialized)
+ dnsCacheInit();
+
+ dnsErrno = DNSERR_NULL;
+
+ /* First try to find the hostname in our local cache...
+ */
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++) {
+ if (strcmp(hostnames[i].name,hostname) == 0)
+ return(hostnames[i].addr);
+ }
+
+ /* If not in the cache, we query the network. First look
+ * for a DNSSRVR defined in the environment. If found, use
+ * it; else, use IP broadcast.
+ */
+
+ /* See if this is a mDNS request...
+ */
+ if (strstr(hostname,".local")) {
+ DnsPort = port = DNSMCAST_PORT;
+ srvrip = htonl(DNSMCAST_IP);
+ memcpy((char *)binenet,(char *)mDNSMac,sizeof(mDNSMac));
+ enetaddr = binenet;
+ }
+ else {
+ port = IPPORT_DNS;
+ DnsPort = port+1;
+ srvrname = getenv("DNSSRVR");
+ if (srvrname == (char *)0)
+ srvrip = 0xffffffff;
+ else {
+ if (IpToBin(srvrname,(uchar *)&srvrip) < 0)
+ return(0);
+ }
+
+ /* Get the ethernet address for the IP:
+ */
+ enetaddr = ArpEther((uchar *)&srvrip,binenet,0);
+ if (!enetaddr) {
+ printf("ARP failed for 0x%x\n",srvrip);
+ return(0);
+ }
+ }
+
+ /* Retrieve an ethernet buffer from the driver and populate the
+ * ethernet level of packet:
+ */
+ enetp = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6);
+ memcpy((char *)&enetp->ether_dhost,(char *)binenet,6);
+ enetp->ether_type = htons(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it
+ * appropriately:
+ */
+ ipp = (struct ip *) (enetp + 1);
+ ipp->ip_vhl = IP_HDR_VER_LEN;
+ ipp->ip_tos = 0;
+ ipp->ip_id = ipId();
+ ipp->ip_off = 0;
+ ipp->ip_ttl = UDP_TTL;
+ ipp->ip_p = IP_UDP;
+ memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4);
+ memcpy((char *)&ipp->ip_dst.s_addr,(char *)&srvrip,4);
+
+ /* Now UDP...
+ */
+ udpp = (struct Udphdr *) (ipp + 1);
+ udpp->uh_sport = htons(DnsPort);
+ udpp->uh_dport = htons(port);
+
+ /* Finally, the DNS data ...
+ */
+ dnsp = (struct dnshdr *)(udpp+1);
+
+ /* Build the message. This query supports a single internet
+ * host-address question.
+ *
+ * Fixed header...
+ */
+ dnsId = ipId();
+ dnsp->id = htons(dnsId); /* Unique id */
+ dnsp->param = 0; /* Parameter field */
+ dnsp->num_questions = htons(1); /* # of questions */
+ dnsp->num_answers = 0; /* # of answers */
+ dnsp->num_authority = 0; /* # of authority */
+ dnsp->num_additional = 0; /* # of additional */
+
+ /* The formatted name list..
+ * Each name is preceded by a single-byte length, so for our
+ * query, the list is "LNNNLNNNLNNN0", where...
+ * 'L' is the single-byte length of the name.
+ * 'NN..N' is variable-lenght domain.
+ * '0' is the length of the next name in the list; hence,
+ * indicating the end of the list.
+ *
+ * For each '.' (dot) in the hostname, there is a
+ * LNNN pair.
+ */
+ pp = (char *)dnsp->question;
+ np = (char *)hostname;
+ namelen = strlen(hostname);
+ do {
+ dot = strchr(np,'.');
+ if (dot) {
+ *pp++ = dot-np;
+ memcpy(pp,np,dot-np);
+ pp += (dot-np);
+ np = dot + 1;
+ }
+ else {
+ *pp++ = strlen(np);
+ strcpy(pp,np);
+ }
+ } while(dot);
+
+
+ /* Since the size of the name can be arbitrary (not aligned),
+ * we must populate the TYPE and CLASS fields one byte at
+ * a time...
+ */
+ pp += (strlen(np) + 1);
+ *pp++ = 0;
+ *pp++ = 1; /* type = 'A' (host address) */
+ *pp++ = 0;
+ *pp = 1; /* class = 'IN' (the internet) */
+
+ /* Send the DNS query:
+ * Total message size is...
+ * FIXED_HDR_SIZE + NAME_SIZE + TYPE_SIZE + CLASS_SIZE + (NAMELEN_SIZE*2)
+ * where...
+ * FIXED_HDR_SIZE = 12
+ * NAME_SIZE = strlen(hostname) = namelen
+ * TYPE_SIZE = sizeof(short) = 2
+ * CLASS_SIZE = sizeof(short) = 2
+ * NAMELEN_SIZE = sizeof(char) = 1
+ *
+ * There are 2 name lengths. The first one is the size of the host
+ * name we are querying for and the second one is zero (indicating no
+ * more names in the list).
+ * So, the total length of the packet is <namelen + 18>.
+ */
+
+ pktsize = namelen+18;
+ ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + pktsize;
+ ipp->ip_len = htons(ip_len);
+ udpp->uh_ulen = htons((ushort)(ip_len - sizeof(struct ip)));
+
+ ipChksum(ipp); /* Compute csum of ip hdr */
+ udpChksum(ipp); /* Compute UDP checksum */
+
+// printf("Sending DNS rqst id=%04x (%d %d)\n",dnsId,pktsize,ip_len);
+
+ dnsWaiting = 1;
+ sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + pktsize);
+
+ /* Wait for 3 seconds for a response...
+ */
+ startElapsedTimer(&tmr,3000);
+ while(!msecElapsed(&tmr)) {
+ if (dnsErrno != DNSERR_NULL)
+ break;
+ pollethernet();
+ }
+ if (dnsErrno == DNSERR_COMPLETE) {
+ dnsCacheAdd(hostname,dnsIP);
+ shell_sprintf("DNSIP","%d.%d.%d.%d",
+ IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP));
+ return(dnsIP);
+ }
+ else {
+ if (dnsErrno == DNSERR_NULL)
+ printf("DNS attempt timeout\n");
+ else
+ printf("DNSErr: %s\n",dnsErrStr((int)dnsErrno));
+ setenv("DNSIP",0);
+ }
+ return(0);
+}
+
+/* Note two different processDNS/processMCASTDNS functions...
+ * processDNS() provides the necessary code to deal with responses
+ * that we should expect to get as a result of issuing a dns request.
+ * processMCASTDNS() provides the necessary code to deal with requests
+ * from other machines querying for our hostname/ip info.
+ */
+
+/* processDNS():
+ * This function provides the recieving half of the DNS query above.
+ */
+int
+processDNS(struct ether_header *ehdr,ushort size)
+{
+ int i;
+ char *pp;
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ struct dnshdr *dhdr;
+ unsigned short rtype, qtot, atot;
+
+ if (dnsWaiting == 0)
+ return(0);
+
+ dnsWaiting = 0;
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
+ dhdr = (struct dnshdr *)(uhdr + 1);
+
+// printf("DNS: (%d)\n",size);
+// printf(" dnsid: %04x\n",htons(dhdr->id));
+// printf(" param: %04x\n",htons(dhdr->param));
+// printf(" quest: %04x\n",htons(dhdr->num_questions));
+// printf(" answe: %04x\n",htons(dhdr->num_answers));
+// printf(" autho: %04x\n",htons(dhdr->num_authority));
+// printf(" addit: %04x\n",htons(dhdr->num_additional));
+// printMem(dhdr->question, size - UDPSIZE - IPSIZE - ETHERSIZE - 12,1);
+
+ /* Verify the DNS response...
+ */
+ if ((htons(dhdr->param) & 0x8000) == 0) { /* response? */
+ dnsErrno = DNSERR_NOTARESPONSE;
+ return(0);
+ }
+ if (htons(dhdr->id) != dnsId) { /* correct id? */
+ dnsErrno = DNSERR_BADRESPID;
+ return(0);
+ }
+ if ((rtype = (htons(dhdr->param) & 0xf)) != 0) { /* response normal? */
+ switch(rtype) {
+ case 1:
+ dnsErrno = DNSERR_FORMATERR;
+ break;
+ case 2:
+ dnsErrno = DNSERR_SRVRFAILURE;
+ break;
+ case 3:
+ dnsErrno = DNSERR_NAMENOEXIST;
+ break;
+ default:
+ dnsErrno = DNSERR_BADRESPTYPE;
+ break;
+ }
+ return(0);
+ }
+ qtot = htons(dhdr->num_questions);
+ if ((atot = htons(dhdr->num_answers)) < 1) { /* answer count >= 1? */
+ dnsErrno = DNSERR_BADANSWRCOUNT;
+ return(0);
+ }
+
+ /* At this point we can assume that the received packet format
+ * is ok. Now we need to parse the packet for the "answer" to
+ * our query...
+ */
+
+ /* Set 'pp' to point to the start of the question list.
+ * There should only be one question in the response.
+ */
+ pp = (char *)&dhdr->question;
+
+ /* Skip over the questions:
+ */
+ for(i=0;i<qtot;i++) {
+ while(*pp) /* while 'L' is nonzero */
+ pp += (*pp + 1);
+ pp += 5; /* Account for last 'L' plus TYPE/CLASS */
+ }
+
+ /* The 'pp' pointer is now pointing a list of resource records that
+ * correspond to the answer list. It is from this list that we
+ * must retrieve the information we are looking for...
+ */
+
+ for(i=0;i<atot;i++) {
+ unsigned short type, len;
+
+ /* The first portion of the record is the resource domain name
+ * and it may be literal string (a 1-octet count followed by
+ * characters that make up the name) or a pointer to a literal
+ * string.
+ */
+ if ((*pp & 0xc0) == 0xc0) { /* compressed? (section 4.1.4 RFC1035) */
+ pp += 2;
+ }
+ else {
+ while(*pp) /* while 'L' is nonzero */
+ pp += (*pp + 1);
+ pp += 1;
+ }
+ memcpy((char *)&type,pp,2);
+ type = htons(type);
+ pp += 8;
+ memcpy((char *)&len,pp,2);
+ len = htons(len);
+ if ((type == TYPE_A) && (len == 4)) {
+ pp += 2;
+ memcpy((char *)&dnsIP,pp,4);
+ dnsIP = htonl(dnsIP);
+ }
+ else
+ pp += (len+2);
+ }
+ dnsErrno = DNSERR_COMPLETE;
+ return(0);
+}
+
+/* processMCASTDNS():
+ * If we're here, then we've received a request over the Multi-cast
+ * DNS address for some host name. If the hostname in this request
+ * matches this board's hostname, then return this board's IP address.
+ * If the shell variable HOSTNAME isn't set, then just return immediately.
+ */
+int
+processMCASTDNS(struct ether_header *ehdr,ushort size)
+{
+ int l1, ql = 0;
+ struct ip *ihdr;
+ char *pp, *myname;
+ struct Udphdr *uhdr;
+ struct dnshdr *dhdr;
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)(ihdr + 1);
+ dhdr = (struct dnshdr *)(uhdr + 1);
+
+ // If this message is DNS response, branch to processDNS()...
+ if ((htons(dhdr->param) & 0x8000) == 0x8000) {
+ processDNS(ehdr,size);
+ return(0);
+ }
+
+ if ((myname = getenv("HOSTNAME")) == 0)
+ return(0);
+
+ // If this isn't a normal query type, return...
+ if ((htons(dhdr->param) & 0xf) != 0)
+ return(0);
+
+ // If there isn't exactly 1 question, return...
+ if (htons(dhdr->num_questions) != 1)
+ return(0);
+
+ /* At this point we can assume that the received packet format
+ * is ok. Now we need to parse the packet for the "question"...
+ */
+
+ /* Set 'pp' to point to the start of the question list.
+ */
+ pp = (char *)dhdr->question;
+ l1 = *pp;
+ while(*pp) {
+ ql += *pp;
+ ql++;
+ pp += (*pp + 1);
+ }
+
+ /* If the name in the question matches our hostname, then send a
+ * reply...
+ *
+ * Referring to top of pg 20 of the document
+ * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt...
+ *
+ * Multicast DNS responses MUST be sent to UDP port 5353 on the
+ * 224.0.0.251 multicast address.
+ */
+ if ((l1 == strlen(myname)) &&
+ (memcmp(myname,(char *)&dhdr->question[1],l1) == 0)) {
+ struct ip *ti, *ri;
+ struct Udphdr *tu, *ru;
+ struct ether_header *te;
+ struct dnshdr *td;
+ short type, class;
+ long ttl;
+ struct elapsed_tmr tmr;
+
+ te = EtherCopy(ehdr);
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (ehdr + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_id = ri->ip_id;
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)mDNSIp,
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = htons(DNSMCAST_PORT);
+
+ td = (struct dnshdr *)(tu+1);
+
+ /* Flags: */
+ td->id = dhdr->id;
+ td->param = htons(0x8400);
+ td->num_questions = 0;
+ td->num_answers = htons(1);
+ td->num_authority = 0;
+ td->num_additional = 0;
+
+ /* Answers: */
+ pp = (char *)td->question;
+ memcpy(pp,(char *)dhdr->question,ql+1);
+ pp += (ql+1);
+
+ type = htons(TYPE_A);
+ memcpy(pp,(char *)&type,2);
+ pp += 2;
+
+ class = htons(CLASS_IN);
+ memcpy(pp,(char *)&class,2);
+ pp += 2;
+
+ ttl = htonl(900);
+ memcpy(pp,(char *)&ttl,4);
+ pp += 4;
+
+ *pp++ = 0; /* 2-byte length of address */
+ *pp++ = 4;
+ memcpy(pp,(char *)BinIpAddr,4);
+
+ tu->uh_ulen = ecs((UDPSIZE + 27 + ql));
+ ti->ip_len = ecs((UDPSIZE + 27 + ql + sizeof(struct ip)));
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ /* Delay for some random time between 20-120msec...
+ */
+ startElapsedTimer(&tmr,20 + (BinEnetAddr[5] & 0x3f));
+ while(!msecElapsed(&tmr));
+
+ sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + 27 + ql);
+ }
+ return(0);
+}
+
+/* DNS Cache utilities:
+ */
+void
+dnsCacheInit(void)
+{
+ int i;
+
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++) {
+ hostnames[i].idx = 0;
+ hostnames[i].addr = 0;
+ hostnames[i].name[0] = 0;
+ }
+ dnsCacheInitialized = 1;
+}
+
+int
+dnsCacheDump(void)
+{
+ int i, tot;
+ struct dnscache *hnp;
+
+ tot = 0;
+ hnp = hostnames;
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) {
+ if (hnp->addr) {
+ printf("%3d %30s: %d.%d.%d.%d\n",hnp->idx,hnp->name, IP1(hnp->addr),
+ IP2(hnp->addr), IP3(hnp->addr), IP4(hnp->addr));
+ tot++;
+ }
+ }
+ return(tot);
+}
+
+int
+dnsCacheAdd(char *name, unsigned long inaddr)
+{
+ int i, li, lowest;
+ struct dnscache *hnp;
+ static int idx = 0;
+
+ if (!dnsCacheInitialized)
+ dnsCacheInit();
+
+ /* Validate incoming name size:
+ */
+ if ((strlen(name) >= MAX_HOSTNAME_SIZE) || (inaddr == 0))
+ return(-1);
+
+ lowest = 0x70000000;
+
+ /* First look for an empty slot...
+ */
+ hnp = hostnames;
+ li = MAX_CACHED_HOSTNAMES;
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) {
+ if (hnp->addr == 0) {
+ strcpy(hnp->name,name);
+ hnp->addr = inaddr;
+ hnp->idx = idx++;
+ return(1);
+ }
+ else {
+ if (hnp->idx < lowest) {
+ lowest = hnp->idx;
+ li = i;
+ }
+ }
+ }
+
+ if (i == MAX_CACHED_HOSTNAMES)
+ return(-1);
+
+ /* If all slots are filled, use the slot that had the
+ * the lowest idx value (this would be the oldest entry)...
+ */
+ hnp = &hostnames[li];
+ strcpy(hnp->name,name);
+ hnp->addr = inaddr;
+ hnp->idx = idx++;
+ return(1);
+}
+
+int
+dnsCacheDelAddr(unsigned long addr)
+{
+ int i;
+
+ if (!dnsCacheInitialized) {
+ dnsCacheInit();
+ return(0);
+ }
+
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++) {
+ if (hostnames[i].addr == addr) {
+ hostnames[i].name[0] = 0;
+ hostnames[i].addr = 0;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+int
+dnsCacheDelName(char *name)
+{
+ int i;
+
+ if (!dnsCacheInitialized) {
+ dnsCacheInit();
+ return(0);
+ }
+
+ for(i=0;i<MAX_CACHED_HOSTNAMES;i++) {
+ if (strcmp(hostnames[i].name,name) == 0) {
+ hostnames[i].name[0] = 0;
+ hostnames[i].addr = 0;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+struct dnserr dnsErrTbl[] = {
+ { DNSERR_NOSRVR, "no dns server" },
+ { DNSERR_SOCKETFAIL, "socket fail" },
+ { DNSERR_FORMATERR, "format error" },
+ { DNSERR_SRVRFAILURE, "server error" },
+ { DNSERR_NAMENOEXIST, "no name exists" },
+ { DNSERR_BADRESPTYPE, "bad dns server response" },
+ { DNSERR_BADQSTNCOUNT, "bad question count" },
+ { DNSERR_BADANSWRCOUNT, "bad answer count" },
+ { DNSERR_NOTARESPONSE, "replay not a dns response" },
+ { DNSERR_BADRESPID, "bad dns response id" },
+
+ /* Must be last entry in table: */
+ { DNSERR_NULL, "no error" }
+};
+
+char *
+dnsErrStr(int errno)
+{
+ struct dnserr *dep;
+
+ dep = dnsErrTbl;
+ while(dep->errno != DNSERR_NULL) {
+ if (dep->errno == errno)
+ return(dep->errstr);
+ dep++;
+ }
+ return("invalid dns errno");
+}
+
+char *DnsHelp[] = {
+ "DNS Client",
+ "{hostname} | {cmd args}",
+ " Valid cmd values:",
+ " add {name} {ip}",
+ " cache {dump | init}",
+ " mdns {on | off}",
+ " del {name}",
+ 0,
+};
+
+int
+DnsCmd(int argc, char *argv[])
+{
+ unsigned long addr;
+
+ if (argc == 2) {
+ if ((addr = getHostAddr(argv[1])) != 0) {
+ printf("%s: %d.%d.%d.%d\n",argv[1],
+ IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP));
+ }
+ }
+ else if (argc == 3) {
+ if (strcmp(argv[1],"cache") == 0) {
+ if (strcmp(argv[2],"dump") == 0)
+ dnsCacheDump();
+ else if (strcmp(argv[2],"init") == 0)
+ dnsCacheInit();
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (strcmp(argv[1],"mdns") == 0) {
+ extern void enableMulticastReception(void);
+ extern void disableMulticastReception(void);
+
+ if (strcmp(argv[2],"on") == 0)
+ enableMulticastReception();
+ else if (strcmp(argv[2],"off") == 0)
+ disableMulticastReception();
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (strcmp(argv[1],"del") == 0) {
+ dnsCacheDelName(argv[2]);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (argc == 4) {
+ if (strcmp(argv[1],"add") == 0) {
+ if (IpToBin(argv[3],(uchar *)&addr) < 0)
+ return(CMD_FAILURE);
+ dnsCacheAdd(argv[2],addr);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+
+#endif
diff --git a/main/common/docmd.c b/main/common/docmd.c
new file mode 100644
index 0000000..49a2190
--- /dev/null
+++ b/main/common/docmd.c
@@ -0,0 +1,940 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * docmd:
+ * This code supports the command line interface (CLI) portion of the
+ * monitor. It is a table-driven CLI that uses the table in cmdtbl.c.
+ * A limited amount of "shell-like" capabilities are supported...
+ * shell variables, symbol-table lookup, command history,
+ * command line editiing, command output redirection, etc...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "ether.h"
+#include "cli.h"
+#include "term.h"
+#include <ctype.h>
+
+const char *__ctype_ptr;
+const char *__ctype_ptr__;
+
+/* appCmdlist:
+ * This is a pointer to a list of commands that can be added to the
+ * monitor's list by the application using addcommand().
+ */
+struct monCommand *appCmdlist;
+char *appcmdUlvl;
+
+extern struct monCommand cmdlist[];
+extern char cmdUlvl[];
+
+void
+showusage(struct monCommand *cmdptr)
+{
+ char *usage;
+
+ usage = cmdptr->helptxt[1];
+ printf("Usage: %s %s\n",
+ cmdptr->name,*usage ? usage : "(no args/opts)");
+}
+
+void
+paramerr(struct monCommand *cmdptr)
+{
+ printf("Command parameter error...\n");
+ showusage(cmdptr);
+}
+
+int
+addcommand(struct monCommand *cmdlist, char *cmdlvl)
+{
+ appCmdlist = cmdlist;
+#if INCLUDE_USRLVL
+ appcmdUlvl = cmdlvl;
+#endif
+ return(0);
+}
+
+#if INCLUDE_SHELLVARS
+
+char *
+shellsym_chk(char type, char *string,int *size,char *buf,int bufsize)
+{
+ char *p1, *p2, varname[CMDLINESIZE], *val;
+
+ p1 = string;
+ p2 = varname;
+ /* If incoming check is for a symbol, we apply a somewhat more
+ * flexible syntax check for the symbol name...
+ */
+ if (type == '%') {
+ while(*p1 && (*p1 != '}') && (*p1 != ' ') && (*p1 != '\t'))
+ *p2++ = *p1++;
+ }
+ else {
+ while(1) {
+ if (((*p1 >= '0') && (*p1 <= '9')) ||
+ ((*p1 >= 'a') && (*p1 <= 'z')) ||
+ ((*p1 >= 'A') && (*p1 <= 'Z')) ||
+ (*p1 == '_')) {
+ *p2++ = *p1++;
+ }
+ else
+ break;
+ }
+ }
+ *p2 = '\0';
+
+ if (type == '%')
+ val = getsym(varname,buf,bufsize);
+ else
+ val = getenv(varname);
+
+ if ((val) && (size))
+ *size = strlen(varname);
+
+ return(val);
+}
+
+/* braceimbalance():
+ * Return non-zero (the index into the src string at the point of the
+ * imbalance) if the incoming string does not have a balanced set
+ * of braces; else return 0.
+ */
+static int
+braceimbalance(char *src, int *idx, int *ndp)
+{
+ int bnest;
+ char *base;
+
+ bnest = 0;
+ base = src;
+ while((*src) && (bnest >= 0)) {
+ if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) {
+ bnest++;
+ src++;
+ }
+ else if (*src == '}') {
+ if (bnest)
+ bnest--;
+ }
+ else if (*src == '{') {
+ *ndp += 1; /* Indicate that there is a brace with no '$' prefix */
+ }
+ else if (*src == '\\') {
+ if ((*(src+1) == '$') || (*(src+1) == '%') ||
+ (*(src+1) == '\\') ||
+ (*(src+1) == '{') || (*(src+1) == '}')) {
+ src++;
+ }
+ }
+ src++;
+ }
+
+ /* If there is a '{}' mismatch, bnest will be non-zero... */
+ *idx = src - base - 1;
+ return(bnest);
+}
+
+/* processprefixes():
+ * Process the '$' for shell variables and '%' for symbols.
+ * Look for the last '$' (or '%') in the incoming string and attempt to
+ * make a shell variable (or symbol) substitution. Return 0 if no '$'
+ * (or '%') is found. Note that '$' and '%' are processed interchangeably
+ * to support symbols and shell variables in the same way.
+ */
+static int
+processprefixes(char *src)
+{
+ int namesize, srclen;
+ char *varname, *value;
+ char buf[CMDLINESIZE], buf1[CMDLINESIZE];
+
+
+ srclen = strlen(src);
+
+ while(*src) {
+ if (((*src == '$') || (*src == '%')) && (*(src-1) != '\\')) {
+ varname = src+1;
+ value = shellsym_chk(*src,varname,&namesize,buf1,sizeof(buf1));
+ if (value) {
+ if (((srclen - namesize) + strlen(value)) >= CMDLINESIZE) {
+ printf("Cmd line expansion overflow\n");
+ return(-1);
+ }
+ if ((*value == '$') &&
+ (strncmp(value+1,varname,strlen(value+1)) == 0))
+ return(0);
+ strcpy(buf,varname+namesize);
+ sprintf(varname-1,"%s%s",value,buf);
+ return(1);
+ }
+ }
+ src++;
+ }
+ return(0);
+}
+
+/* processbraces():
+ * Look into the incoming string for the deepest set of braces and
+ * substitute that with the value stored in the corresponding shell
+ * variable. Return 1 if a set of braces was processed; else 0 indicating
+ * that all braces have been processed. Return -1 if there is some kind
+ * of processing error (buffer overflow).
+ */
+static int
+processbraces(char *src)
+{
+ int namesize, srclen, result, opentot;
+ char *cp1, *cp2, *varname, *value, type;
+ char buf[CMDLINESIZE], buf1[CMDLINESIZE], buf2[CMDLINESIZE];
+
+ type = 0;
+ opentot = 0;
+ varname = src;
+ srclen = strlen(src);
+
+ while(*src) {
+ if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) {
+ opentot++;
+ type = *src;
+ varname = src+2;
+ src++;
+ }
+ else if ((*src == '}') && (opentot)) {
+ cp1 = varname;
+ cp2 = buf1;
+ while(cp1 < src)
+ *cp2++ = *cp1++;
+ *cp2 = 0;
+ while((result = processprefixes(buf1)) == 1);
+ if (result == -1)
+ return(-1);
+
+ strcpy(buf,src);
+ sprintf(varname,"%s%s",buf1,buf);
+ value = shellsym_chk(type,varname,&namesize,buf2,sizeof(buf2));
+ /* If the shellvar or symbol exists, replace it; else remove it. */
+ if (value) {
+ if (((srclen-(namesize+3))+strlen(value)+1) > CMDLINESIZE) {
+ printf("Cmd line expansion overflow\n");
+ return(-1);
+ }
+ strcpy(buf1,varname+namesize+1);
+ sprintf(varname-2,"%s%s",value,buf1);
+ }
+ else {
+ strcpy(varname-2,src+1);
+ }
+ return(1);
+ }
+ else if (*src == '\\') {
+ if ((*(src+1) == '$') || (*(src+1) == '%') ||
+ (*(src+1) == '\\') ||
+ (*(src+1) == '{') || (*(src+1) == '}')) {
+ src++;
+ }
+ }
+ else if ((isspace(*src)) && (opentot)) {
+ printf("Cmd line expansion error\n");
+ return(-1);
+ }
+ src++;
+ }
+ return(0);
+}
+
+/* expandshellvars():
+ * Passed a string that is to be expanded with all shell variables converted.
+ * This function supports variables of type $VARNAME and ${VARNAME}.
+ * It also allows variables to be embedded within variables. For example...
+ * ${VAR${NAME}} will be a 2-pass expansion in which ${NAME} is evaluated
+ * and then ${VARXXX} (where XXX is whatever was in variable NAME) is
+ * processed.
+ */
+static int
+expandshellvars(char *newstring)
+{
+ char *cp;
+ int result, cno, ndp;
+
+ /* Verify that there is a balanced set of braces in the incoming
+ * string...
+ */
+ ndp = 0;
+ if (braceimbalance(newstring,&cno,&ndp)) {
+ printf("Brace imbalance @ %d%s.\n",
+ cno,ndp ? " ({ missing $ or %)" : "");
+ return(-1);
+ }
+
+ /* Process the variable names within braces... */
+ while((result = processbraces(newstring)) == 1);
+ if (result == -1)
+ return(-1);
+
+ /* Process dollar signs (left-most first)... */
+ while((result = processprefixes(newstring)) == 1);
+ if (result == -1)
+ return(-1);
+
+ /* Cleanup any remaining "\{", "\}" or "\$" strings... */
+ cp = newstring+1;
+ while(*cp) {
+ if (*cp == '{' || *cp == '}' || *cp == '$' || *cp == '%') {
+ if (*(cp-1) == '\\') {
+ strcpy(cp-1,cp);
+ cp -= 2;
+ }
+ }
+ cp++;
+ }
+ return(0);
+}
+#else
+static int
+expandshellvars(char *newstring)
+{
+ return(0);
+}
+#endif
+
+
+/* tokenize():
+ * Take the incoming string and create an argv[] array from that. The
+ * incoming string is assumed to be writeable. The argv[] array is simple
+ * a set of pointers into that string, where the whitespace delimited
+ * character sets are each NULL terminated.
+ */
+int
+tokenize(char *string,char *argv[])
+{
+ int argc, done;
+
+ /* Null out the incoming argv array. */
+ for(argc=0;argc<ARGCNT;argc++)
+ argv[argc] = (char *)0;
+
+ argc = 0;
+ while(1) {
+ while ((*string == ' ') || (*string == '\t'))
+ string++;
+ if (*string == 0)
+ break;
+ argv[argc] = string;
+ while ((*string != ' ') && (*string != '\t')) {
+ if ((*string == '\\') && (*(string+1) == '"')) {
+ strcpy(string,string+1);
+ }
+ else if (*string == '"') {
+ strcpy(string,string+1);
+ while(*string != '"') {
+ if ((*string == '\\') && (*(string+1) == '"'))
+ strcpy(string,string+1);
+ if (*string == 0)
+ return(-1);
+ string++;
+ }
+ strcpy(string,string+1);
+ continue;
+ }
+ if (*string == 0)
+ break;
+ string++;
+ }
+ if (*string == 0)
+ done = 1;
+ else {
+ done = 0;
+ *string++ = 0;
+ }
+ argc++;
+ if (done)
+ break;
+ if (argc >= ARGCNT) {
+ argc = -1;
+ break;
+ }
+ }
+ return(argc);
+}
+
+/* showhelp():
+ * Called by Help() when it is time to print out some verbosity level of
+ * a command's help text.
+ * if...
+ * verbose == 2, then print all the help text;
+ * verbose == 1, then print the command name and abstract;
+ * verbose == 0, then print only the command name;
+ */
+int
+showhelp(struct monCommand *list,int index,int verbose)
+{
+ char **hp;
+ struct monCommand *cptr = &list[index];
+
+#if INCLUDE_USRLVL
+ char *lvltbl = 0;
+
+ /* Get command list in sync with user-level table:
+ */
+ if (list == cmdlist)
+ lvltbl = cmdUlvl;
+ else if (list == appCmdlist)
+ lvltbl = appcmdUlvl;
+ else
+ return(-1);
+
+ /* Verify user level:
+ */
+ if ((lvltbl[index] > getUsrLvl()))
+ return(0);
+#endif
+
+ if (verbose == 2) {
+ printf("%s\n", cptr->helptxt[0]);
+ showusage(cptr);
+
+ hp = &cptr->helptxt[2];
+ while(*hp)
+ printf("%s\n",*hp++);
+
+#if INCLUDE_USRLVL
+ printf("\nRequired user level: %d\n",lvltbl[index]);
+#endif
+ }
+ else if (verbose == 1) {
+#if INCLUDE_USRLVL
+ printf(" %-12s %d %s\n", cptr->name, lvltbl[index],cptr->helptxt[0]);
+#else
+ printf(" %-12s %s\n", cptr->name, cptr->helptxt[0]);
+#endif
+ }
+ else {
+ printf("%-12s",cptr->name);
+ }
+ return(1);
+}
+
+/* Command list headers can be defined in config.h or just
+ * omitted...
+ */
+#ifndef APP_CMDLIST_HEADER
+#define APP_CMDLIST_HEADER "\nApplication-Installed Command Set:"
+#endif
+
+#ifndef MON_CMDLIST_HEADER
+#define MON_CMDLIST_HEADER "\nMicro-Monitor Command Set:"
+#endif
+
+/* Help():
+ * This command displays each commands help text.
+ * The help text is assumed to be formatted as an array of strings
+ * where...
+ * the first string is the command description;
+ * the second string is command usage;
+ * and all remaining strings up to the NULL are just printable text.
+ */
+char *HelpHelp[] = {
+ "Display command set",
+ "-[di] [commandname]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -d list commands and descriptions",
+ " -i configuration info",
+#endif
+ 0,
+};
+
+int
+Help(int argc,char *argv[])
+{
+ char *cp;
+ char *args[2];
+ struct monCommand *cptr, *acptr;
+ int j, i, foundit, opt, descriptions, info;
+
+ descriptions = info = 0;
+ while((opt=getopt(argc,argv,"di")) != -1) {
+ switch(opt) {
+ case 'd':
+ descriptions = 1;
+ break;
+ case 'i':
+ info = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (info) {
+ monHeader(0);
+ stkusage();
+ printf("Moncomptr: 0x%08lx\n",(long)&moncomptr);
+#if INCLUDE_ETHERNET
+ printf("Etheradd_ptr: 0x%08lx\n",(long)etheraddr);
+#endif
+#if INCLUDE_TFS
+#ifdef TFS_ALTDEVTBL_BASE
+ if (alt_tfsdevtbl != (struct tfsdev *)0xffffffff)
+ printf("AltTFSdevtbl: 0x%08lx\n",(long)alt_tfsdevtbl);
+#endif
+#endif
+#if INCLUDE_TERM
+ {
+ int row, col;
+ if (term_getsize(&row,&col) != -1)
+ printf("ROW/COL: %d/%d\n",row,col);
+ }
+#endif
+
+ return(CMD_SUCCESS);
+ }
+
+ cptr = cmdlist;
+ if (argc == optind) {
+ foundit = 1;
+ if (descriptions) {
+ if (appCmdlist) {
+ printf("%s\n",APP_CMDLIST_HEADER);
+ acptr = appCmdlist;
+ for(i=0;acptr->name;acptr++,i++)
+ showhelp(appCmdlist,i,1);
+ }
+ printf("%s\n",MON_CMDLIST_HEADER);
+ while(cptr->name) {
+ showhelp(cmdlist,cptr-cmdlist,1);
+ cptr++;
+ }
+ putchar('\n');
+ }
+ else {
+ i = 0;
+ if (appCmdlist) {
+ acptr = appCmdlist;
+ printf("%s\n",APP_CMDLIST_HEADER);
+ for(j=0;acptr->name;acptr++,j++) {
+ if (showhelp(appCmdlist,j,0)) {
+ if ((++i%6) == 0)
+ putchar('\n');
+ }
+ }
+ putchar('\n');
+ i = 0;
+ }
+ printf("%s\n",MON_CMDLIST_HEADER);
+ while(cptr->name) {
+ if (showhelp(cmdlist,cptr-cmdlist,0)) {
+ if ((++i%6) == 0)
+ putchar('\n');
+ }
+ cptr++;
+ }
+ putchar('\n');
+ }
+ }
+ else {
+ foundit = 0;
+ cp = argv[1];
+ if (appCmdlist) {
+ acptr = appCmdlist;
+ for(i=0;acptr->name;acptr++,i++) {
+ if (strcmp(acptr->name,cp) == 0) {
+ foundit = showhelp(appCmdlist,i,2);
+ break;
+ }
+ }
+ }
+ if (!foundit) {
+ if (*cp == '_')
+ cp++;
+ while(cptr->name) {
+ if (strcmp(cptr->name,cp) == 0) {
+ foundit = showhelp(cmdlist,cptr-cmdlist,2);
+ break;
+ }
+ cptr++;
+ }
+ }
+ }
+
+ if (!foundit) {
+ TFILE *tfp;
+
+ /* If the command is not found in the command table, then see if
+ * it is an executable in TFS. If it is, run it with a single
+ * argument "help"...
+ */
+ tfp = tfsstat(argv[1]);
+ if (tfp && (TFS_ISEXEC(tfp))) {
+ args[0] = argv[1];
+ args[1] = argv[0];
+ tfsrun(args,0);
+ }
+ else {
+ printf("\"%s\" not found\n",argv[1]);
+ return(CMD_FAILURE);
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
+#if INCLUDE_SHELLVARS
+/* getPathEntry():
+ * Copy the next path entry pointed to by 'path' into 'entry'.
+ */
+char *
+getPathEntry(char *path, char *entry, int entrysize)
+{
+ int i;
+ char *base = entry;
+
+ entrysize--;
+
+ while(*path == ':')
+ path++;
+
+ for(i=0;(i < entrysize) && (*path != ':') && (*path != 0); i++)
+ *entry++ = *path++;
+
+ if (entry == base)
+ return(0);
+
+ *entry++ = 0;
+ return(path);
+}
+
+/* findPath():
+ * If PATH is set, then step through each colon-delimited entry looking
+ * for a valid executable.
+ */
+int
+findPath(char *name,char *fpath,int pathsize)
+{
+ int elen;
+ TFILE *tfp;
+ char *path;
+ char entry[TFSNAMESIZE+1];
+
+ if ((tfp = tfsstat(name)))
+ strcpy(fpath,name);
+
+ if ((path = getenv("PATH"))) {
+ if ((*path == ':') && tfp)
+ return(1);
+ while((path = getPathEntry(path,entry,sizeof(entry)))) {
+ elen = strlen(entry);
+ if ((elen + strlen(name)) < (pathsize-1)) {
+ if (entry[elen-1] != '/')
+ strcat(entry,"/");
+ strcat(entry,name);
+ if (tfsstat(entry)) {
+ strcpy(fpath,entry);
+ return(1);
+ }
+ }
+ }
+ }
+ if (tfp)
+ return(1);
+ return(0);
+}
+#else
+int
+findPath(char *name, char *fpath, int pathsize)
+{
+ if (tfsstat(name)) {
+ strcpy(fpath,name);
+ return(1);
+ }
+ return(0);
+}
+#endif
+
+/* fsCmdAlias():
+ * Just allow "cat" to be used instead of "tfs cat" (for exammple)...
+ */
+char *
+fsCmdAlias(char *cmdcpy, char *cmd, int cpysize)
+{
+#if INCLUDE_TFS
+ if ((strlen(cmd) + 16) >= cpysize) {
+ strcpy(cmdcpy,cmd);
+ }
+ else if ((strncmp(cmd,"cat ",4) == 0) ||
+ (strncmp(cmd,"ls",2) == 0) ||
+ (strncmp(cmd,"rm ",3) == 0) ||
+ (strncmp(cmd,"cp ",3) == 0) ||
+ (strncmp(cmd,"ld ",3) == 0)) {
+ sprintf(cmdcpy,"tfs %s", cmd);
+ }
+ else
+ strcpy(cmdcpy,cmd);
+#else
+ strcpy(cmdcpy,cmd);
+#endif
+ return(cmdcpy);
+}
+
+/* _docommand():
+ * Called by docommand() (below) to process what it thinks is a
+ * single command.
+ *
+ * Assume the incoming string is a null terminated character string
+ * that is made up of whitespace delimited tokens that will be parsed
+ * into command line arguments. The first argument is the command name
+ * and all following arguments (if any) are specific to that command.
+ * If verbose is non-zero, print the list of arguments after tokenization.
+ */
+int
+_docommand(char *cmdline,int verbose)
+{
+ int ret, argc, i, err;
+ struct monCommand *cmdptr, *cmdptrbase;
+ char *argv[ARGCNT], cmdcpy[CMDLINESIZE], path[TFSNAMESIZE+1];
+#if INCLUDE_USRLVL
+ char *ulvlptr = 0;
+#endif
+
+ cmdline = fsCmdAlias(cmdcpy,cmdline,CMDLINESIZE);
+
+ /* Redirection check is done prior to shell variable expansion, so
+ * the code within RedirectionCheck() itself must deal with the '$'
+ * after the redirection arrow...
+ */
+ if (RedirectionCheck(cmdline) == -1)
+ return(CMD_LINE_ERROR);
+
+ /* If there are any instances if a dollar or percent sign within the
+ * command line, then expand any shell variables (or symbols) that may
+ * be present.
+ */
+ if (strpbrk(cmdline,"$%")) {
+ if (expandshellvars(cmdline) < 0)
+ return(CMD_LINE_ERROR);
+ }
+
+ /* Build argc/argv structure based on incoming command line.
+ */
+ argc = tokenize(cmdline,argv);
+ if (argc == 0)
+ return(CMD_SUCCESS); /* Empty line is ok */
+ if (argc < 0) {
+ printf("Command line error\n");
+ return(CMD_LINE_ERROR);
+ }
+
+ /* If verbosity is enabled, print the processed command line.
+ */
+ if (verbose) {
+ for(i=0;i<argc;i++)
+ printf("%s ",argv[i]);
+ printf("\n");
+ }
+
+ /* Initialize static data used by getopt().
+ */
+ getoptinit();
+
+ /* At this point all CLI processing has been done. We've tokenized
+ * and converted shell variables where necessary. Now its time to
+ * scan through the command table(s) looking for a match between
+ * the first token of the incoming command string and a command name
+ * in the table(s).
+ * The monitor allows the application to insert a set of commands
+ * that will be in addition to the commands that are in the monitor's
+ * command list, this is done with the API function mon_addcommand()
+ * which ultimately calls the function addcommand() in this file.
+ * That function is handed a pointer to two tables: a command structure
+ * table and a user level table.
+ * If the application-supplied command table is present, then we scan
+ * through it first. This is done so that when we scan the monitor-owned
+ * command table, we can strip off a leading underscore to support the
+ * ability to have a command in each table (applcation-supplied and
+ * monitor built-ins) with the same name.
+ */
+ if (appCmdlist) {
+ cmdptrbase = appCmdlist;
+#if INCLUDE_USRLVL
+ ulvlptr = appcmdUlvl;
+#endif
+ }
+ else {
+ cmdptrbase = cmdlist;
+#if INCLUDE_USRLVL
+ ulvlptr = cmdUlvl;
+#endif
+ }
+
+ while(1) {
+ /* If we are processing the monitor-owned command table, then
+ * we want to eliminate the leading underscore of argv[0] (if
+ * there is one).
+ */
+ if ((cmdptrbase == cmdlist) && (argv[0][0] == '_'))
+ strcpy(argv[0],&argv[0][1]);
+
+ for(cmdptr = cmdptrbase; cmdptr->name; cmdptr++) {
+ if (strcmp(argv[0],cmdptr->name) == 0)
+ break;
+ }
+ if (cmdptr->name) {
+#if INCLUDE_USRLVL
+ /* If command exists, but we are not at the required user
+ * level, then just pretend there was no command match...
+ */
+ if (ulvlptr[cmdptr-cmdptrbase] > getUsrLvl())
+ break;
+#endif
+ /* Do not run this command if monrc is active and the
+ * NOMONRC flag bit is set for this command...
+ */
+ if ((cmdptr->flags & CMDFLAG_NOMONRC) && tfsRunningMonrc()) {
+ printf("%s: illegal within monrc.\n",cmdptr->name);
+ return(CMD_MONRC_DENIED);
+ }
+
+ /* Execute the command's function...
+ */
+ ret = cmdptr->func(argc,argv);
+
+ /* If command returns parameter error, then print the second
+ * string in that commands help text as the usage text. If
+ * the second string is a null pointer, then print a generic
+ * "no arguments" string as the usage message.
+ */
+ if (ret == CMD_PARAM_ERROR)
+ paramerr(cmdptr);
+
+ RedirectionCmdDone();
+ return(ret);
+ }
+ if (cmdptrbase == cmdlist)
+ break;
+
+ cmdptrbase = cmdlist;
+#if INCLUDE_USRLVL
+ ulvlptr = cmdUlvl;
+#endif
+ }
+
+ /* If we get here, then the first token does not match on any of
+ * the command names in ether of the command tables. As a last
+ * resort, we look to see if the first token matches an executable
+ * file name in TFS.
+ */
+ ret = CMD_NOT_FOUND;
+
+ if (findPath(argv[0],path,sizeof(path))) {
+ argv[0] = path;
+ err = tfsrun(argv,0);
+ if (err == TFS_OKAY)
+ ret = CMD_SUCCESS;
+ else
+ printf("%s: %s\n",path,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+ else {
+ printf("Command not found: %s\n",argv[0]);
+ }
+ RedirectionCmdDone();
+ return(ret);
+}
+
+/* docommand():
+ * This is a relatively new (Jan 2006) front end to _docommand().
+ * It deals with three things (two of which are new uMon command line
+ * capabilities):
+ *
+ * 1. Terminates the line at the sight of a poundsign (moved from
+ * original docommand() function).
+ * 2. Looks for the left arros ('<') at the end of the line and if
+ * found, it is used to indicate that the line should be repeated
+ * until interrupted.
+ * 3. Allow multiple, semicolon-delimited commands to be put on a
+ * single command line.
+ */
+int
+docommand(char *line, int verbose)
+{
+ int ret, loop, len;
+ char *lp, *base, *backslash, cmdcpy[CMDLINESIZE];
+
+ loop = 0;
+ len = strlen(line);
+ if (len >= CMDLINESIZE)
+ return(CMD_LINE_ERROR);
+
+ lp = line + len - 1;
+ if (*lp == '<') {
+ loop = 1;
+ *lp = 0;
+ }
+
+repeat:
+ backslash = 0;
+ lp = base = cmdcpy;
+ strcpy(lp,line);
+
+ while (*lp) {
+ if (*lp == ';') {
+ if (backslash) {
+ strcpy(backslash,lp);
+ backslash = 0;
+ continue;
+ }
+ *lp = 0;
+ ret = _docommand(base,verbose);
+ *lp++ = ';';
+ base = lp;
+ if (ret != CMD_SUCCESS)
+ return(ret);
+ continue;
+ }
+ if (*lp == '#') {
+ if (backslash) {
+ strcpy(backslash,lp);
+ backslash = 0;
+ continue;
+ }
+ *lp = 0;
+ loop = 0;
+ break;
+ }
+ if (*lp == '\\') {
+ backslash = lp;
+ lp++;
+ continue;
+ }
+ backslash = 0;
+ lp++;
+ }
+ ret = _docommand(base,verbose);
+
+ if ((loop) && !gotachar())
+ goto repeat;
+
+ return(ret);
+}
diff --git a/main/common/edit.c b/main/common/edit.c
new file mode 100644
index 0000000..3fb8b54
--- /dev/null
+++ b/main/common/edit.c
@@ -0,0 +1,722 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * edit.c:
+ *
+ * A simple buffer editor. It allows a user to pull a TFS file into RAM,
+ * make some "ed-like" modifications to the ASCII data and then write
+ * that data back to TFS.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_EDIT
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include <ctype.h>
+#include "cli.h"
+
+extern char *file_line_edit(char *);
+static int rmCR(char *,int);
+static int gotoline(char *,char *,char **,char *,int);
+static int searchfor(char *,char *,char **,char *);
+static int whatlineisthis(char *,char *);
+static int getrange(char *,int *,int *,char *,char *,char *);
+static void lnprbuf(char *,char *,char *);
+static void prbuf(char *,char *);
+static void prlno(int,int);
+static void deletelines(char *,int,char *,char **,char **);
+static char *prline(char *,char *);
+static char *skipwhite(char *);
+
+#define BREAK 1
+#define CONTINUE 2
+#define FALLTHROUGH 3
+#define INSERT 4
+#define COMMAND 5
+#define ESCAPE 0x1b
+
+#define ILCMAX 8
+
+void
+efree(int size, char *buffer)
+{
+ if (size != 0)
+ free(buffer);
+}
+
+/* Help text while in the editor: */
+char *edithelp[] = {
+ "Editor commands:",
+ "d{LRNG} delete line",
+#if INCLUDE_LINEEDIT
+ "e# edit line # (uses 'ksh/vi-like' command line editing)",
+#endif
+ "i enter insert mode (use '.' to exit insert mode)",
+ "a enter append mode (use '.' to exit append mode)",
+ "j# join line '#' with line '#+1'",
+ "P[LRNG] print buffer with line numbers",
+ "p print buffer",
+ "q[fname] quit edit, write file",
+ "s[srchstr] goto line containing search string",
+ "x exit edit, do not write file",
+ "# goto line # (use '$' to go to last line)",
+ ".+/-# goto line relative to current position",
+ "",
+ "Where...",
+ "# represents a decimal number;",
+ "LRNG represents a line number or inclusive line range (# or #-#);",
+ 0,
+};
+
+/* Help text outside the editor: */
+
+char *EditHelp[] = {
+ "Edit file or buffer",
+ "-[b:c:f:i:m:rs:t] [filename]",
+#if INCLUDE_VERBOSEHELP
+ " -b {adr} specify buffer base address",
+ " -c {cmd} in-line command",
+ " -f {flgs} file flags (see tfs)",
+ " -i {info} file info (see tfs)",
+ " -m {size} specify allocation size for buffer",
+ " -r do not automatically remove carriage returns from file",
+ " -s {size} size of buffer",
+ " -t convert tabs to spaces",
+#endif
+ 0,
+};
+
+int
+Edit(int argc,char *argv[])
+{
+ int i, opt, tfd, quit, mode, bsize;
+ char ln[CMDLINESIZE], *lp, *cp, *cp1, *filename, *flags, *info;
+ char *buffer, *bp; /* Buffer and pointer into buffer. */
+ char *eob; /* Current EOF pointer (max distance between */
+ /* bp and buffer). */
+ char *inlinecmd[ILCMAX]; /* If non-NULL, it points to a list of */
+ /* commands to be executed prior to going */
+ /* into interactive mode. */
+ int ilcidx; /* Index into in-line command table. */
+ int len; /* Length of the incoming line. */
+ int size; /* Size of buffer specified on command line. */
+ int cmdtot; /* Running total of incoming lines. */
+ int delcnt; /* Used by :d when a range is specified. */
+ int noCR; /* Set by -r option to remove Carriage Returns */
+ TFILE tstruct, *tfp;
+
+ tfp = (TFILE *)0;
+ size = bsize = 0;
+ flags = filename = (char*)0;
+ buffer = (char *)getAppRamStart();
+ info = (char *)0;
+ noCR = 1;
+ ilcidx = 0;
+ for(i=0;i<8;i++)
+ inlinecmd[i] = (char *)0;
+
+ while ((opt = getopt(argc, argv, "b:c:f:i:m:rs:")) != -1) {
+ switch (opt) {
+ case 'b':
+ buffer = (char *)strtol(optarg,(char **)0,0);
+ break;
+ case 'c':
+ if (ilcidx < ILCMAX-1)
+ inlinecmd[ilcidx++] = optarg;
+ break;
+ case 'f':
+ flags = optarg;
+ break;
+ case 'i':
+ info = optarg;
+ break;
+ case 'm':
+ bsize = strtol(optarg,0,0);
+ break;
+ case 'r':
+ noCR = 0;
+ break;
+ case 's':
+ size = (int)strtol(optarg,(char **)0,0);
+ break;
+ default:
+ return (CMD_PARAM_ERROR);
+ }
+ }
+
+ if (bsize != 0) {
+ buffer = malloc(bsize);
+ if (!buffer)
+ return(CMD_FAILURE);
+ }
+
+ if (argc == optind+1) {
+ filename = argv[optind];
+ if (tfsfstat(filename,&tstruct) != -1) {
+ tfp = &tstruct;
+ size = TFS_SIZE(tfp);
+ if ((bsize > 0) && (size > bsize)) {
+ printf("Allocation too small\n");
+ efree(bsize,buffer);
+ return(CMD_FAILURE);
+ }
+ tfd = tfsopen(filename,TFS_RDONLY,0);
+ if (tfd < 0) {
+ printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,tfd,0));
+ efree(bsize,buffer);
+ return(CMD_FAILURE);
+ }
+ else {
+ tfsread(tfd,buffer,size);
+ tfsclose(tfd,0);
+ }
+ }
+ }
+
+ if ((noCR) && (size != 0)) {
+ if ((buffer[size-1] != 0x0d) && (buffer[size-1] != 0x0a)) {
+ printf("EOF linefeed inserted.\n");
+ buffer[size++] = 0x0a;
+ buffer[size] = 0;
+ }
+ size -= rmCR(buffer,size);
+ }
+
+ bp = buffer;
+ eob = buffer + size;
+
+ if (!ilcidx)
+ printf("Edit buffer = 0x%lx.\nType '?' for help\n",(ulong)buffer);
+
+ quit = 0;
+ cmdtot = 0;
+ mode = COMMAND;
+ while(!quit) {
+ lp = ln;
+ if (ilcidx > cmdtot)
+ strcpy(ln,inlinecmd[cmdtot]);
+ else if (ilcidx) { /* If ILC command set doesn't terminate */
+ /* the edit session, force it here. */
+ efree(bsize,buffer);
+ return(CMD_SUCCESS);
+ }
+ else
+ getline(ln,CMDLINESIZE,0);
+ cmdtot++;
+ if (mode == INSERT) {
+ if (!strcmp(lp,"."))
+ mode = COMMAND;
+ else {
+ len = strlen(lp) + 1;
+ cp1 = eob + len;
+ cp = eob;
+ while(cp > bp) *--cp1 = *--cp;
+ while(*lp) *bp++ = *lp++;
+ *bp++ = '\n';
+ eob += len;
+ }
+ continue;
+ }
+ if (!strcmp(ln,"x")) { /* Exit editor now. */
+ efree(bsize,buffer);
+ return(CMD_SUCCESS);
+ }
+ else if (!strcmp(ln,"?")) { /* Display help info. */
+ char **eh;
+
+ eh = edithelp;
+ while(*eh)
+ printf("%s\n",*eh++);
+ }
+ else if (!strcmp(ln,"p")) /* Print buffer. */
+ prbuf(buffer,eob);
+ else if (!strcmp(ln,"P")) /* Print buffer with lines. */
+ lnprbuf(buffer,bp,eob);
+ else if (!strcmp(ln,"i")) /* Enter insert mode. */
+ mode = INSERT;
+ else if (!strcmp(ln,"a")) { /* Enter insert mode at */
+ mode = INSERT; /* next line */
+ gotoline(".+1",buffer,&bp,eob,0);
+ }
+ else if (!strcmp(ln,"$")) { /* Goto last line. */
+ gotoline(ln,buffer,&bp,eob,0);
+ gotoline(".-1",buffer,&bp,eob,1);
+ }
+ else if (isdigit(ln[0]) || (ln[0]=='.')) /* Goto line. */
+ gotoline(ln,buffer,&bp,eob,1);
+ else if (ln[0] == 's') { /* Go to line containing string. */
+ char *str;
+ str = skipwhite(&ln[1]);
+ if (!*str)
+ gotoline(".+1",buffer,&bp,eob,0);
+ searchfor(str,buffer,&bp,eob);
+ }
+#if INCLUDE_LINEEDIT
+ else if (ln[0] == 'e') {
+ char *copy, *eoc, *cp2, crlf[2];
+ int oldlnsize, newlnsize, toendsize;
+
+ if (gotoline(&ln[1],buffer,&bp,eob,0) == -1)
+ continue;
+ copy = malloc(CMDLINESIZE);
+ if (!copy)
+ continue;
+ eoc = copy + CMDLINESIZE - 3;
+ cp = bp;
+ cp1 = copy;
+ oldlnsize = 0;
+ while ((*cp != 0x0a) && (*cp != 0x0d) && (cp1 != eoc)) {
+ if (*cp == '\t') /* Tabs are replaced with spaces to */
+ *cp = ' '; /* eliminate whitespace confusion in */
+ putchar(*cp); /* the line editor. */
+ *cp1++ = *cp++;
+ oldlnsize++;
+ }
+ crlf[0] = *cp;
+ if (*cp != *(cp+1)) {
+ crlf[1] = *(cp+1);
+ if (*(cp+1) == 0x0a || *(cp+1) == 0x0d)
+ oldlnsize++;
+ }
+ else {
+ crlf[1] = 0;
+ }
+ oldlnsize++;
+ *cp1++ = ESCAPE;
+ *cp1 = 0;
+ if (file_line_edit(copy) != (char *)0) {
+ newlnsize = strlen(copy);
+ toendsize = eob - (bp+oldlnsize);
+ copy[newlnsize++] = crlf[0];
+ if (crlf[1] == 0x0d || crlf[1] == 0x0a)
+ copy[newlnsize++] = crlf[1];
+ copy[newlnsize] = 0;
+ if (oldlnsize == newlnsize) {
+ memcpy(bp,copy,newlnsize);
+ }
+ else if (oldlnsize > newlnsize) {
+ strcpy(bp,copy);
+ memcpy(bp+newlnsize,cp+1,toendsize);
+ }
+ else {
+ cp1 = eob-1;
+ cp2 = (char *)(eob+(newlnsize-oldlnsize)-1);
+ for(i=0;i<toendsize;i++)
+ *cp2-- = *cp1--;
+ memcpy(bp,copy,newlnsize);
+ }
+ eob -= oldlnsize;
+ eob += newlnsize;
+ }
+ free(copy);
+ }
+#endif
+ else if (ln[0] == 'P') {
+ int range, first, last, currentline;
+
+ range = getrange(&ln[1],&first,&last,buffer,bp,eob);
+ if (range > 0) {
+ char *bpcpy;
+
+ bpcpy = bp;
+ gotoline(".",buffer,&bpcpy,eob,0);
+ currentline = whatlineisthis(buffer,bpcpy);
+ if (gotoline(&ln[1],buffer,&bpcpy,eob,0) == -1)
+ continue;
+ for(i=first;i<=last;i++) {
+ prlno(i,currentline);
+ bpcpy = prline(bpcpy,eob);
+ }
+ }
+ }
+ else if (ln[0] == 'j') { /* Join line specified with next line */
+ char *tmpeob;
+
+ if (gotoline(&ln[1],buffer,&bp,eob,0) == -1)
+ continue;
+ tmpeob=eob-1;
+ while(bp < tmpeob) {
+ if (*bp == '\n') {
+ memcpy(bp,bp+1,eob-bp);
+ eob--;
+ break;
+ }
+ bp++;
+ }
+ }
+ else if (ln[0] == 'd') { /* Delete line (or range of lines) */
+ delcnt = getrange(&ln[1],0,0,buffer,bp,eob);
+ deletelines(&ln[1],delcnt,buffer,&bp,&eob);
+ }
+ else if (ln[0] == 'q') { /* Quit edit, if filename is present */
+ lp = &ln[1]; /* use it. */
+ lp = skipwhite(lp);
+ if (*lp)
+ filename = lp;
+ quit = 1;
+ }
+ else {
+ printf("huh?\n");
+ }
+ }
+
+ if (filename) {
+ int err;
+ char buf[16];
+
+ if (tfp) {
+ int link;
+
+ /* If filename and TFS_NAME(tfp) differ, then we are editing
+ * a file through a symbolic link. If it is a link, then we
+ * use the info/flags/filename from the source file (using the
+ * file pointer and ignoring user input stuff).
+ */
+ link = strcmp(filename,TFS_NAME(tfp));
+
+ if ((!flags) || (link))
+ flags = (char *)tfsctrl(TFS_FBTOA,TFS_FLAGS(tfp),(long)buf);
+ if ((!info) || (link))
+ info = TFS_INFO(tfp);
+ if (link) {
+ printf("Updating source file '%s' thru link '%s'\n",
+ TFS_NAME(tfp),filename);
+ filename = TFS_NAME(tfp);
+ }
+ }
+ if (!flags)
+ flags = (char *)0;
+ if (!info)
+ info = (char *)0;
+ err = tfsadd(filename,info,flags,(unsigned char *)buffer,eob-buffer);
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+ efree(bsize,buffer);
+ return(CMD_SUCCESS);
+}
+
+static void
+lnprbuf(char *buffer,char *bp,char *eob)
+{
+ int lno, currentline;
+
+ if (buffer == eob)
+ return;
+
+ lno = 1;
+ currentline = whatlineisthis(buffer,bp);
+ prlno(lno++,currentline);
+ while(buffer < eob) {
+ putchar(*buffer);
+ if ((*buffer == '\n') && ((buffer + 1) != eob))
+ prlno(lno++,currentline);
+ buffer++;
+ }
+}
+
+static void
+prlno(int lno,int currentline)
+{
+ char *fmt;
+
+ if (lno == currentline)
+ fmt = ">%2d: ";
+ else
+ fmt = "%3d: ";
+ printf(fmt,lno);
+}
+
+static void
+prbuf(char *bp,char *eob)
+{
+ while(bp < eob)
+ putchar(*bp++);
+}
+
+char *
+prline(char *bp,char *eob)
+{
+ while(bp < eob) {
+ putchar(*bp);
+ if (*bp == '\n')
+ break;
+ bp++;
+ }
+ return(bp+1);
+}
+
+/* searchfor():
+ * Step through the buffer starting at 'bp' and search for a memory match
+ * with the incoming string pointed to by 'srch'. If not found, simply
+ * return after the entire buffer has been searched (wrap to start if
+ * necessary). If found, then adjust '*bp' to point to the beginning of
+ * of the line that contains the match.
+ */
+static int
+searchfor(char *srch,char *buffer,char **bp,char *eob)
+{
+ static char *lastsrchstring;
+ char *startedhere, *tbp;
+ int len;
+
+ tbp = *bp;
+ if (tbp < eob)
+ startedhere = *bp;
+ else
+ tbp = startedhere = buffer;
+
+ if (*srch) {
+ len = strlen(srch);
+ if (lastsrchstring)
+ free(lastsrchstring);
+ lastsrchstring = malloc(len+1);
+ if (lastsrchstring)
+ strcpy(lastsrchstring,srch);
+ }
+ else if (lastsrchstring) {
+ len = strlen(lastsrchstring);
+ srch = lastsrchstring;
+ }
+ else
+ return(-1);
+ do {
+ if ((tbp + len) > eob) {
+ tbp = buffer;
+ }
+ else {
+ if (!memcmp(tbp,srch,len)) {
+ while(1) {
+ if (tbp <= buffer) {
+ *bp = buffer;
+ break;
+ }
+ if (*tbp == '\n') {
+ *bp = tbp+1;
+ break;
+ }
+ tbp--;
+ }
+ prline(*bp,eob);
+ return(0);
+ }
+ else
+ tbp++;
+ }
+ } while(tbp != startedhere);
+ printf("'%s' not found\n",srch);
+ return(-1);
+}
+
+static int
+gotoline(char *ln,char *buffer,char **bp,char *eob,int verbose)
+{
+ int lno, i, moveforward;
+ char *tbp, *base;
+
+ base = buffer;
+ moveforward = 1;
+
+ /* If destination line number is '.', assume you're already there.
+ * If the '.' is followed by a '+' or '-' then the following number
+ * is considered an offset from the current line instead of from the
+ * start of the buffer.
+ */
+ if (ln[0] == '.') {
+ base = *bp;
+ if (ln[1] == '+')
+ lno = atoi(&ln[2]) + 1;
+ else if (ln[1] == '-') {
+ lno = atoi(&ln[2]) + 2;
+ moveforward = 0;
+ }
+ else
+ goto end;
+ }
+ else if (ln[0] == '$') {
+ lno = 99999999;
+ }
+ else
+ lno = atoi(ln);
+
+ if (lno < 1) {
+ printf("Invalid line\n");
+ return(-1);
+ }
+
+ if (moveforward) {
+ for(tbp=base,i=1;i<lno&&tbp<eob;tbp++)
+ if (*tbp == '\n') i++;
+ if (tbp == eob) {
+ if (verbose)
+ printf("Pointer set to end of buffer.\n");
+ /* If out of range, set pointer to end of buffer. */
+ *bp = eob;
+ return(-1);
+ }
+ }
+ else {
+ for(tbp=base,i=1;i<lno&&tbp>=buffer;tbp--)
+ if (*tbp == '\n') i++;
+ if (tbp < buffer) {
+ if (verbose)
+ printf("Pointer set to start of buffer.\n");
+ /* If out of range, set pointer to beginning of buffer. */
+ *bp = buffer;
+ return(-1);
+ }
+ tbp+=2;
+ }
+ *bp = tbp;
+
+end:
+ if (verbose) {
+ printf("%3d: ",whatlineisthis(buffer,*bp));
+ prline(*bp,eob);
+ }
+ return(0);
+}
+
+static int
+whatlineisthis(char *buffer,char *bp)
+{
+ int lno;
+ char *cp;
+ cp = buffer;
+
+ lno = 1;
+ while(cp < bp) {
+ if (*cp == '\n')
+ lno++;
+ cp++;
+ }
+ return(lno);
+}
+
+static int
+getrange(char *cp,int *begin,int *end,char *buffer,char *bp,char *eob)
+{
+ char *dash;
+ int b, e, lastline, thisline;
+
+ if (!*cp)
+ return(0);
+
+ lastline = whatlineisthis(buffer,eob) - 1;
+ thisline = whatlineisthis(buffer,bp);
+
+ if (*cp == '.')
+ b = thisline;
+ else
+ b = atoi(cp);
+ dash = strchr(cp,'-');
+ if (dash) {
+ if (*(dash+1) == '$')
+ e = lastline;
+ else if (*(dash+1) == '.')
+ e = thisline;
+ else
+ e = atoi(dash+1);
+ }
+ else
+ e = b;
+
+ if (e > lastline)
+ e = lastline;
+ if (begin)
+ *begin = b;
+ if (end)
+ *end = e;
+ if ((e <= 0) || (b <=0) || (e < b))
+ printf("Bad range\n");
+ return(e - b + 1);
+}
+
+static void
+deletelines(char *lp,int lcnt,char *buffer,char **bp,char **eob)
+{
+ char *cp, *cp1, *t_bp, *t_eob;
+
+ if (lcnt <= 0)
+ return;
+
+ t_bp = *bp;
+ t_eob = *eob;
+
+ if (gotoline(lp,buffer,&t_bp,t_eob,0) == -1)
+ return;
+ cp = cp1 = t_bp;
+ while(lcnt>0) {
+ if (cp >= t_eob) {
+ printf("Pointer set to end of buffer.\n");
+ break;
+ }
+ if (*cp == '\n')
+ lcnt--;
+ cp++;
+ }
+ while(cp != t_eob)
+ *cp1++ = *cp++;
+
+ *eob = cp1;
+ *bp = t_bp;
+}
+
+static char *
+skipwhite(char *cp)
+{
+ while((*cp == ' ') || (*cp == '\t'))
+ cp++;
+ return(cp);
+}
+
+/* rmCR():
+ * Given the source and size of the buffer, remove all instances of 0x0d
+ * (carriage return) from the buffer. Return the number of CRs removed.
+*/
+static int
+rmCR(char *src,int size)
+{
+ int i; /* Index into src array. */
+ int tot; /* Keep track of total # of 0x0d's removed. */
+ int remaining; /* Keep track of how far to go. */
+
+ tot = 0;
+ remaining = size;
+ for (i=0;i<size;i++) {
+ remaining--;
+ if (src[i] == 0x0d) {
+ src[i] = 0; /* Make sure memory is writeable. */
+ if (src[i] != 0)
+ continue;
+ memcpy(&src[i],&src[i+1],remaining);
+ tot++;
+ }
+ }
+ if (tot)
+ printf("Removed %d CRs\n",tot);
+ return(tot);
+}
+
+#endif
diff --git a/main/common/elf.h b/main/common/elf.h
new file mode 100644
index 0000000..f8a69b2
--- /dev/null
+++ b/main/common/elf.h
@@ -0,0 +1,159 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * elf.h:
+ *
+ * Used to support ELF file format in TFS.
+ * The data in this header file is built primarily from information in
+ * the book "Understanding ELF Object Files and Debugging Tools"
+ * All page references in comments refer to that book.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#ifndef _ELF_H_
+#define _ELF_H_
+
+typedef unsigned short Elf32_Half;
+typedef unsigned long Elf32_Word;
+typedef unsigned long Elf32_Addr;
+typedef unsigned long Elf32_Off;
+
+/* Size of ELF identification field. */
+#define EI_NIDENT 16
+
+/* e_type values... */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+
+struct elf_fhdr { /* pg 12 */
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+};
+
+#define ELFFHDR struct elf_fhdr
+
+/* sh_flags values... */
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+
+/* sh_type values... */
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0x8fffffff
+
+struct elf_shdr { /* pg 19 */
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+};
+
+#define ELFSHDR struct elf_shdr
+
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+
+struct elf_phdr { /* pg 42 */
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+};
+
+#define ELFPHDR struct elf_phdr
+
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+#define STB_LOPROC 13
+#define STB_HIPROC 15
+
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+#define STT_LOPROC 13
+#define STT_HIPROC 15
+
+#define SHN_UNDEF 0
+
+struct elf_sym {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+};
+
+#endif
diff --git a/main/common/endian.h b/main/common/endian.h
new file mode 100644
index 0000000..36dede7
--- /dev/null
+++ b/main/common/endian.h
@@ -0,0 +1,68 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * endian.h:
+ *
+ * macros used for endian conversion.
+ * The intent is that the macros have nil effect on Big_Endian systems...
+ *
+ * ecs: endian-convert short
+ * ecl: endian-convert long
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _ENDIAN_H_
+#define _ENDIAN_H_
+
+#ifdef CPU_LE
+#define ecs(a) (((a & 0x00ff) << 8) | ((a & 0xff00) >> 8))
+#define ecl(a) (((a & 0x000000ff) << 24) | ((a & 0x0000ff00) << 8) | \
+ ((a & 0x00ff0000) >> 8) | ((a & 0xff000000) >> 24))
+#define self_ecs(a) (a = ecs(a))
+#define self_ecl(a) (a = ecl(a))
+#define ntohl ecl
+#define ntohs ecs
+#define htonl ecl
+#define htons ecs
+#else
+#ifdef CPU_BE
+#define ecs(a) a
+#define ecl(a) a
+#define self_ecs(a)
+#define self_ecl(a)
+#define ntohl(a) a
+#define ntohs(a) a
+#define htonl(a) a
+#define htons(a) a
+#else
+#error You need to define CPU_BE or CPU_LE in config.h!
+#endif /* else ifdef CPU_BE */
+#endif /* ifdef CPU_LE */
+
+/* just to be safe...
+ */
+#ifdef CPU_LE
+#ifdef CPU_BE
+#error You have both CPU_BE and CPU_LE defined. Pick one!
+#endif
+#endif
+
+#endif
diff --git a/main/common/env.c b/main/common/env.c
new file mode 100755
index 0000000..22a10fc
--- /dev/null
+++ b/main/common/env.c
@@ -0,0 +1,858 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * env.c:
+ * Shell variable functions used to load or retrieve shell variable
+ * information from the shell variable table.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include <stdarg.h>
+#include "config.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "ether.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "version.h"
+#include "boardinfo.h"
+#include "timer.h"
+
+#if INCLUDE_SHELLVARS
+
+char *whatplatform = "@(#)PLATFORM=" PLATFORM_NAME;
+
+#ifdef TARGET_ENV_SETUP
+extern void TARGET_ENV_SETUP(void);
+#endif
+
+#ifndef PROMPT
+#define PROMPT "uMON>"
+#endif
+
+int shell_print(void);
+int envToExec(char *);
+void clearenv(void);
+
+/* Structure used for the shell variables: */
+struct s_shell {
+ char *val; /* Value stored in shell variable */
+ char *name; /* Name of shell variable */
+ int vsize; /* Size of storage allocated for value */
+ struct s_shell *next;
+};
+
+struct s_shell *shell_vars;
+
+/* If no malloc, then use locally defined env_alloc() and env_free()...
+ */
+#if INCLUDE_MALLOC
+
+#define env_alloc malloc
+#define env_free free
+
+#else
+
+#define ENV_ALLOC_TOT 48
+#define ENV_ALLOC_SIZE (sizeof(struct s_shell)+8)
+
+struct env_space {
+ int inuse;
+ char space[ENV_ALLOC_SIZE];
+} envSpace[ENV_ALLOC_TOT];
+
+
+char *
+env_alloc(int size)
+{
+ int i;
+
+ if (size > ENV_ALLOC_SIZE)
+ return(0);
+
+ for(i=0;i<ENV_ALLOC_TOT;i++) {
+ if (envSpace[i].inuse == 0) {
+ envSpace[i].inuse = 1;
+ memset(envSpace[i].space,0,ENV_ALLOC_SIZE);
+ return(envSpace[i].space);
+ }
+ }
+ return(0);
+}
+
+void
+env_free(char *space)
+{
+ int i;
+
+ for(i=0;i<ENV_ALLOC_TOT;i++) {
+ if (envSpace[i].space == space) {
+ envSpace[i].inuse = 0;
+ break;
+ }
+ }
+ return;
+}
+#endif
+
+/*
+ * Set()
+ *
+ * Syntax:
+ * set var clears the variable 'var'
+ * set var value assign "value" to variable 'var'
+ * set -a var value AND 'var' with 'value'
+ * set -o var value OR 'var' with 'value'
+ * set -i var [value] increment 'var' by 'value' (or 1 if no value)
+ * set -d var [value] decrement 'var' by 'value' (or 1 if no value)
+ * set -x result of -i/-d is in hex
+ */
+char *SetHelp[] = {
+ "Shell variable operations",
+#if INCLUDE_EE
+ "-[ab:cdef:iox] [varname[=expression]] [value]",
+#else
+ "-[ab:cdef:iox] [varname] [value]",
+#endif
+#if INCLUDE_VERBOSEHELP
+ " -a AND var with value",
+ " -b set console baudrate",
+ " -c clear the environment",
+ " -d decrease var by value (or 1)",
+ " -e build an environ string",
+#if INCLUDE_TFS
+ " -f{file} create script from environment",
+#endif
+ " -i increase var by value (or 1)",
+ " -o OR var with value",
+ " -x result in hex (NA with expressions, use hex())",
+#endif
+ 0,
+};
+
+#define SET_NOOP 0
+#define SET_INCR 1
+#define SET_DECR 2
+#define SET_OR 3
+#define SET_AND 4
+
+int
+Set(int argc,char *argv[])
+{
+ char *envp, buf[CMDLINESIZE];
+ int opt, decimal, setop, i;
+
+ setop = SET_NOOP;
+ envp = (char *)0;
+ decimal = 1;
+ while((opt=getopt(argc,argv,"ab:cdef:iox")) != -1) {
+ switch(opt) {
+ case 'a': /* logical and */
+ setop = SET_AND;
+ decimal = 0;
+ break;
+ case 'b':
+ ChangeConsoleBaudrate(atoi(optarg));
+ return(CMD_SUCCESS);
+ case 'c': /* clear environment */
+ clearenv();
+ break;
+ case 'd': /* decrement */
+ setop = SET_DECR;
+ break;
+ case 'e':
+ envp = getenvp();
+ break;
+#if INCLUDE_TFS
+ case 'f': /* build script from environment */
+ envToExec(optarg);
+ return(0);
+#endif
+ case 'i': /* increment */
+ setop = SET_INCR;
+ break;
+ case 'o': /* logical or */
+ setop = SET_OR;
+ decimal = 0;
+ break;
+ case 'x':
+ decimal = 0;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (!shell_vars) {
+ printf("No memory allocated for environment.\n");
+ return(CMD_FAILURE);
+ }
+
+ if (setop != SET_NOOP) { /* Do some operation on a shell variable */
+ char *varval;
+ unsigned long value, opval;
+
+ /* For -i & -d, if value is not specified, then assume 1. */
+ if (argc == optind+1) {
+ if ((setop == SET_INCR) || (setop == SET_DECR))
+ opval = 1;
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (argc == optind+2)
+ opval = strtoul(argv[optind+1],0,0);
+ else
+ return(CMD_PARAM_ERROR);
+
+ varval = getenv(argv[optind]);
+ if (!varval) {
+ printf("%s: not found\n", argv[optind]);
+ return(CMD_FAILURE);
+ }
+
+ value = strtoul(varval,(char **)0,0);
+ switch(setop) {
+ case SET_INCR:
+ value += opval;
+ break;
+ case SET_DECR:
+ value -= opval;
+ break;
+ case SET_AND:
+ value &= opval;
+ break;
+ case SET_OR:
+ value |= opval;
+ break;
+ }
+ if (decimal)
+ sprintf(buf,"%ld",value);
+ else
+ sprintf(buf,"0x%lx",value);
+ setenv(argv[optind],buf);
+ }
+ else if (argc == optind) { /* display all variables */
+ shell_print();
+ }
+ else if (argc == (optind+1)) { /* run EE or clear one var or set envp */
+#if INCLUDE_EE
+ switch(setEE(argv[optind])) {
+ case 1:
+ return(CMD_SUCCESS);
+ case -1:
+ return(CMD_FAILURE);
+ }
+#endif
+ if (envp)
+ shell_sprintf(argv[optind],"0x%lx",(ulong)envp);
+ else
+ setenv(argv[optind],0);
+ }
+ else if (argc >= (optind+2)) { /* Set a specific variable */
+ buf[0] = 0;
+ for(i=optind+1;i<argc;i++) {
+ if ((strlen(buf) + strlen(argv[i]) + 2) >= sizeof(buf)) {
+ printf("String too large\n");
+ break;
+ }
+ strcat(buf,argv[i]);
+ if (i != (argc-1))
+ strcat(buf," ");
+ }
+ if (!decimal)
+ shell_sprintf(argv[optind],"0x%lx",atoi(buf));
+ else
+ setenv(argv[optind],buf);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+
+/* Shell variable support routines...
+ * The basic scheme is to malloc in the space needed for the variable
+ * name and the value of that variable. For each variable that
+ * exists there is one s_shell structure that is in the linked list.
+ * As shell variables are removed, their corresonding s_shell structure
+ * is NOT removed, but the data pointed to within the structure is
+ * freed. This keeps the linked list implementation extremely simple
+ * but maintains the versatility gained by using malloc for the
+ * variables instead of some limted set of static arrays.
+ */
+
+
+/* shell_alloc():
+ * First scan through the entire list to see if the requested
+ * shell variable name already exists in the list; if it does,
+ * then just use the same s_shell entry but change the value.
+ * Also, if the new value fits in the same space as the older value,
+ * then just use the same memory space (don't do the free/malloc).
+ * If it doesn't, then scan through the list again. If there
+ * is one that has no variable assigned to it (name = 0), then
+ * use it for the new allocation. If all s_shell structures do
+ * have valid entries, then malloc a new s_shell structure and then
+ * place the new shell variable data in that structure.
+ */
+
+static int
+shell_alloc(char *name,char *value)
+{
+ int namelen, valuelen;
+ struct s_shell *sp;
+
+ sp = shell_vars;
+ namelen = strlen(name);
+ valuelen = strlen(value);
+ while(1) {
+ if (sp->name == (char *)0) {
+ if (sp->next != (struct s_shell *)0) {
+ sp = sp->next;
+ continue;
+ }
+ else
+ break;
+ }
+ if (strcmp(sp->name,name) == 0) {
+ if (sp->vsize < valuelen+1) { /* If new value is smaller */
+ env_free(sp->val); /* than the old value, then */
+ sp->val = env_alloc(valuelen+1);/* don't re-allocate any */
+ if (!sp->val) /* memory, just copy into */
+ return(-1); /* the space used by the */
+ sp->vsize = valuelen+1; /* previous value. */
+ }
+ strcpy(sp->val,value);
+ return(0);
+ }
+ if (sp->next == (struct s_shell *)0)
+ break;
+ sp = sp->next;
+ }
+ sp = shell_vars;
+ while(1) {
+ if (sp->name == (char *)0) {
+ sp->name = env_alloc(namelen+1);
+ if (!sp->name)
+ return(-1);
+ strcpy(sp->name,name);
+ sp->val = env_alloc(valuelen+1);
+ if (!sp->val)
+ return(-1);
+ sp->vsize = valuelen+1;
+ strcpy(sp->val,value);
+ return(0);
+ }
+ if (sp->next != (struct s_shell *)0)
+ sp = sp->next;
+ else {
+ sp->next = (struct s_shell *)env_alloc(sizeof(struct s_shell));
+ if (!sp->next)
+ return(-1);
+ sp = sp->next;
+ sp->name = env_alloc(namelen+1);
+ if (!sp->name)
+ return(-1);
+ strcpy(sp->name,name);
+ sp->val = env_alloc(valuelen+1);
+ if (!sp->val)
+ return(-1);
+ sp->vsize = valuelen+1;
+ strcpy(sp->val,value);
+ sp->next = (struct s_shell *)0;
+ return(0);
+ }
+ }
+}
+
+/* shell_dealloc():
+ * Remove the requested shell variable from the list. Return 0 if
+ * the variable was removed successfully, otherwise return -1.
+ */
+static int
+shell_dealloc(char *name)
+{
+ struct s_shell *sp;
+
+ sp = shell_vars;
+ while(1) {
+ if (sp->name == (char *)0) {
+ if (sp->next == (struct s_shell *)0)
+ return(-1);
+ else {
+ sp = sp->next;
+ continue;
+ }
+ }
+ if (strcmp(name,sp->name) == 0) {
+ env_free(sp->name);
+ env_free(sp->val);
+ sp->name = (char *)0;
+ sp->val = (char *)0;
+ return(0);
+ }
+
+ if (sp->next == (struct s_shell *)0)
+ return(-1);
+ else
+ sp = sp->next;
+ }
+}
+
+/* ConsoleBaudEnvSet():
+ * Called by to load/reload the CONSOLEBAUD shell variable based on
+ * the content of the global variable 'ConsoleBaudRate'.
+ */
+void
+ConsoleBaudEnvSet(void)
+{
+ char buf[16];
+
+ sprintf(buf,"%d",ConsoleBaudRate);
+ setenv("CONSOLEBAUD",buf);
+}
+
+/* ShellVarInit();
+ * Setup the shell_vars pointer appropriately for additional
+ * shell variable assignments that will be made through shell_alloc().
+ */
+int
+ShellVarInit()
+{
+ char buf[16];
+
+#if !INCLUDE_MALLOC
+ memset((char *)&envSpace,0,sizeof(envSpace));
+#endif
+
+ shell_vars = (struct s_shell *)env_alloc(sizeof(struct s_shell));
+ if (!shell_vars) {
+ printf("No memory for environment initialization\n");
+ return(-1);
+ }
+ shell_vars->next = (struct s_shell *)0;
+ shell_vars->name = (char *)0;
+ setenv("PROMPT",PROMPT);
+ sprintf(buf,"0x%lx",APPLICATION_RAMSTART);
+ setenv("APPRAMBASE",buf);
+ sprintf(buf,"0x%lx",BOOTROM_BASE);
+ setenv("BOOTROMBASE",buf);
+ setenv("PLATFORM",PLATFORM_NAME);
+ setenv("MONITORBUILT",monBuilt());
+ shell_sprintf("MONCOMPTR","0x%lx",(ulong)&moncomptr);
+#if INCLUDE_HWTMR
+ shell_sprintf("TARGETTIMER","0x%x",target_timer);
+ shell_sprintf("TICKSPERMSEC","0x%x",TIMER_TICKS_PER_MSEC);
+#endif
+
+ /* Support the ability to have additional target-specific
+ * shell variables initialized at startup...
+ */
+#ifdef TARGET_ENV_SETUP
+ TARGET_ENV_SETUP();
+#endif
+
+ shell_sprintf("VERSION_MAJ","%d",MAJOR_VERSION);
+ shell_sprintf("VERSION_MIN","%d",MINOR_VERSION);
+ shell_sprintf("VERSION_TGT","%d",TARGET_VERSION);
+ return(0);
+}
+
+/* getenv:
+ * Return the pointer to the value entry if the shell variable
+ * name is currently set; otherwise, return a null pointer.
+ */
+char *
+getenv(char *name)
+{
+ register struct s_shell *sp;
+
+ for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) {
+ if (sp->name != (char *)0) {
+ if (strcmp(sp->name,name) == 0)
+ return(sp->val);
+ }
+ }
+ return((char *)0);
+}
+
+/* getenvp:
+ * Build an environment string consisting of all shell variables and
+ * their values concatenated into one string. The format is
+ *
+ * NAME=VALUE LF NAME=VALUE LF NAME=VALUE LF NULL
+ *
+ * with the limit in size being driven only by the space
+ * available on the heap. Note that this uses malloc, and it
+ * the responsibility of the caller to free the pointer when done.
+ */
+char *
+getenvp(void)
+{
+ int size;
+ char *envp, *cp;
+ register struct s_shell *sp;
+
+ size = 0;
+
+ /* Get total size of the current environment vars */
+ for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) {
+ if (sp->name != (char *)0) {
+ size += (strlen(sp->name) + strlen(sp->val) + 2);
+ }
+ }
+ if (size == 0)
+ return((char *)0);
+
+ envp = env_alloc(size+1); /* leave room for final NULL */
+ if (envp == 0)
+ return((char *)0);
+
+ cp = envp;
+ for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) {
+ if (sp->name != (char *)0)
+ cp += sprintf(cp,"%s=%s\n",sp->name,sp->val);
+ }
+ *cp = 0; /* Append NULL after final separator */
+ return(envp);
+}
+
+/* clearenv():
+ * Clear out the entire environment.
+ */
+void
+clearenv(void)
+{
+ struct s_shell *sp;
+
+ for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) {
+ if (sp->name != (char *)0) {
+ env_free(sp->name);
+ env_free(sp->val);
+ sp->name = (char *)0;
+ sp->val = (char *)0;
+ }
+ }
+}
+
+/* setenv:
+ * Interface to shell_dealloc() and shell_alloc().
+ */
+int
+setenv(char *name,char *value)
+{
+ if (!shell_vars)
+ return(-1);
+ if ((value == (char *)0) || (*value == 0))
+ return(shell_dealloc(name));
+ else
+ return(shell_alloc(name,value));
+}
+
+/* shell_print():
+ * Print out all of the current shell variables and their values.
+ */
+int
+shell_print(void)
+{
+ int maxlen, len;
+ char format[8];
+ register struct s_shell *sp;
+
+ /* Before printing the list, pass through the list to determine the
+ * largest variable name. This is used to create a format string
+ * that is then passed to printf() when printing the list of
+ * name/value pairs. It guarantees that regardless of the length
+ * of the name, the format of the printed out put will be consistent
+ * for all variables.
+ */
+ maxlen = 0;
+ sp = shell_vars;
+ while(1) {
+ if (sp->name) {
+ len = strlen(sp->name);
+ if (len > maxlen)
+ maxlen = len;
+ }
+ if (sp->next != (struct s_shell *)0)
+ sp = sp->next;
+ else
+ break;
+ }
+ sprintf(format,"%%%ds = ",maxlen+1);
+
+ /* Now that we know the size of the largest variable, we can
+ * print the list cleanly...
+ */
+ sp = shell_vars;
+ while(1) {
+ if (sp->name != (char *)0) {
+ printf(format, sp->name);
+ puts(sp->val); /* sp->val may overflow printf, so use puts */
+ }
+ if (sp->next != (struct s_shell *)0)
+ sp = sp->next;
+ else
+ break;
+ }
+ return(0);
+}
+
+/* shell_sprintf():
+ * Simple way to turn a printf-like formatted string into a shell variable.
+ */
+int
+shell_sprintf(char *varname, char *fmt, ...)
+{
+ int tot;
+ char buf[CMDLINESIZE];
+ va_list argp;
+
+ va_start(argp,fmt);
+ tot = vsnprintf(buf,CMDLINESIZE-1,fmt,argp);
+ va_end(argp);
+ setenv(varname,buf);
+ return(tot);
+}
+
+
+#if INCLUDE_TFS
+/* validEnvToExecVar():
+ * Return 1 if the variable should be included in the script
+ * generated by envToExec(); else return 0.
+ * Specifically... if the variable is generated internally
+ * then we don't want to include it in the script.
+ */
+int
+validEnvToExecVar(char *varname)
+{
+ char **vp;
+ static char *invalid_varprefixes[] = {
+ "ARG", "TFS_PREFIX_", "TFS_START_",
+ "TFS_END_", "TFS_SPARE_", "TFS_SPARESZ_",
+ "TFS_SCNT_", "TFS_DEVINFO_", "FLASH_BASE_",
+ "FLASH_SCNT_", "FLASH_END_",
+ 0
+ };
+ static char *invalid_varnames[] = {
+ "APPRAMBASE", "BOOTROMBASE", "CMDSTAT",
+ "CONSOLEBAUD", "MALLOC", "MONCOMPTR",
+ "MONITORBUILT", "PLATFORM", "PROMPT",
+ "TFS_DEVTOT", "FLASH_DEVTOT", "PROMPT",
+ "VERSION_MAJ", "VERSION_MIN", "VERSION_TGT",
+ "MONCMD_SRCIP", "MONCMD_SRCPORT",
+#if INCLUDE_HWTMR
+ "TARGETTIMER", "TICKSPERMSEC",
+#endif
+ 0
+ };
+
+ if (varname == 0)
+ return(0);
+
+ if (strncmp(varname,"ARG",3) == 0)
+ return(0);
+
+#if INCLUDE_BOARDINFO
+ if (BoardInfoVar(varname))
+ return(0);
+#endif
+
+ for(vp=invalid_varnames;*vp;vp++) {
+ if (!strcmp(varname,*vp))
+ return(0);
+ }
+ for(vp=invalid_varprefixes;*vp;vp++) {
+ if (!strncmp(varname,*vp,strlen(*vp)))
+ return(0);
+ }
+ return(1);
+}
+
+/* envToExec():
+ Create a file of "set" commands that can be run to recreate the
+ current environment.
+ Changed Oct 2008 to eliminate use of getAppRamStart().
+*/
+int
+envToExec(char *filename)
+{
+ int err, vartot, size, rc;
+ char *buf, *bp, *cp;
+ register struct s_shell *sp;
+
+ sp = shell_vars;
+ vartot = size = rc = 0;
+
+ /* First go through the list to see how much space we need
+ * to allocate...
+ */
+ while(1) {
+ if (validEnvToExecVar(sp->name)) {
+ size += strlen(sp->name) + 6;
+ cp = sp->val;
+ while(*cp) {
+ if (*cp == '$')
+ size++;
+ size++;
+ cp++;
+ }
+ size += 3;
+ vartot++;
+ }
+ if (sp->next != (struct s_shell *)0)
+ sp = sp->next;
+ else
+ break;
+ }
+ if (size == 0)
+ return(0);
+
+ /* Now that we know the space needed (stored in 'size' variable),
+ * allocate it and build the new file in that space, then use tfsadd()
+ * to create the file...
+ */
+ vartot = 0;
+ sp = shell_vars;
+ buf = bp = (char *)env_alloc(size);
+ while(1) {
+ /* Note: if this code changes, then the code above that is used to
+ * allocate the buffer size may also need to change...
+ */
+ if (validEnvToExecVar(sp->name)) {
+ bp += sprintf(bp,"set %s \"",sp->name);
+ cp = sp->val;
+ while(*cp) {
+ if (*cp == '$')
+ *bp++ = '\\';
+ *bp++ = *cp++;
+ }
+ *bp++ = '\"';
+ *bp++ = '\n';
+ *bp = 0;
+ vartot++;
+ }
+ if (sp->next != (struct s_shell *)0)
+ sp = sp->next;
+ else
+ break;
+ }
+ if (vartot > 0) {
+ err = tfsadd(filename,"envsetup","e",(unsigned char *)buf,strlen(buf));
+ if (err != TFS_OKAY) {
+ printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ rc = -1;
+ }
+ }
+ env_free(buf);
+ return(rc);
+}
+#endif
+
+#else
+
+/* The 'set' command is part of the build even if INCLUDE_SHELLVARS
+ * is false. This allows the user to still access teh "set -b ###"
+ * facility for changing the baudrate.
+ */
+char *SetHelp[] = {
+ "Set baud",
+ "-[b:] (no args)",
+#if INCLUDE_VERBOSEHELP
+ " -b set console baudrate",
+#endif
+ 0,
+};
+
+int
+Set(int argc,char *argv[])
+{
+ int opt;
+
+ while((opt=getopt(argc,argv,"b:")) != -1) {
+ switch(opt) {
+ case 'b':
+ ChangeConsoleBaudrate(atoi(optarg));
+ return(CMD_SUCCESS);
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ printf("Shell vars not included in build.\n");
+ return(CMD_FAILURE);
+}
+
+int
+setenv(char *name,char *value)
+{
+ return(-1);
+}
+
+char *
+getenv(char *name)
+{
+ return(0);
+}
+
+int
+shell_sprintf(char *varname, char *fmt, ...)
+{
+ return(0);
+}
+
+void
+ConsoleBaudEnvSet(void)
+{
+}
+
+char *
+getenvp(void)
+{
+ return(0);
+}
+
+#endif
+
+/* ChangeConsoleBaudrate():
+ * Called to attempt to adjust the console baudrate.
+ * Support 2 special cases:
+ * if baud == 0, then just turn off console echo;
+ * if baud == 1, turn it back on.
+ */
+int
+ChangeConsoleBaudrate(int baud)
+{
+ if (baud == 0)
+ console_echo(0);
+ else if (baud == 1)
+ console_echo(1);
+ else {
+ if (ConsoleBaudSet(baud) < 0) {
+ printf("Baud=%d failed\n",baud);
+ return(-1);
+ }
+ ConsoleBaudRate = baud;
+ ConsoleBaudEnvSet();
+ }
+ return(0);
+}
+
diff --git a/main/common/ether.h b/main/common/ether.h
new file mode 100644
index 0000000..8fd470d
--- /dev/null
+++ b/main/common/ether.h
@@ -0,0 +1,714 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * ether.h:
+ *
+ * This file is a single "contains-all" header file to support different
+ * components of ethernet/IP along with the peer and upper layer protocols
+ * like ICMP, UDP, TFTP, DHCP etc...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#ifndef _ETHER_H_
+#define _ETHER_H_
+
+#define __PACKED__ __attribute__ ((packed))
+
+#ifndef INCLUDE_MONCMD
+#define INCLUDE_MONCMD INCLUDE_ETHERNET
+#endif
+
+#ifndef INCLUDE_ETHERVERBOSE
+#define INCLUDE_ETHERVERBOSE INCLUDE_ETHERNET
+#endif
+
+#ifndef INCLUDE_RARPIPASSIGN
+#define INCLUDE_RARPIPASSIGN INCLUDE_ETHERNET
+#endif
+
+/************************************************************************
+ *
+ * Default MAC & IP addresses...
+ *
+ */
+
+#ifndef DEFAULT_ETHERADD
+#define DEFAULT_ETHERADD "00:00:00:00:00:00"
+#endif
+
+#ifndef DEFAULT_IPADD
+#define DEFAULT_IPADD "0.0.0.0"
+#endif
+
+/************************************************************************
+ *
+ * Retransmission delay stuff...
+ *
+ */
+
+#define DELAY_INIT_ARP 1
+#define DELAY_INIT_DHCP 2
+#define DELAY_INIT_TFTP 3
+#define DELAY_INCREMENT 4
+#define DELAY_RETURN 5
+#define DELAY_OR_TIMEOUT_RETURN 6
+#define RETRANSMISSION_TIMEOUT -1
+#define RETRANSMISSION_ACTIVE 1
+
+/************************************************************************
+ *
+ * Ethernet stuff...
+ *
+ */
+
+struct ether_addr {
+ unsigned char ether_addr_octet[6];
+} __PACKED__ ;
+
+struct ether_header {
+ struct ether_addr ether_dhost;
+ struct ether_addr ether_shost;
+ unsigned short ether_type;
+} __PACKED__ ;
+#define ETHERSIZE sizeof(struct ether_header)
+
+#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#define ETHERTYPE_ARP 0x0806 /* Addr resolution protocol */
+#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */
+
+#define ETHER_MINPKT 64
+
+/************************************************************************
+ *
+ * ARP/RARP stuff...
+ *
+ */
+
+#define SIZEOFARPCACHE 8
+
+#define ARPSIZE (sizeof(struct ether_header) + sizeof(struct arphdr))
+
+struct arphdr {
+ unsigned short hardware; /* 1 for ethernet */
+ unsigned short protocol;
+ unsigned char hlen;
+ unsigned char plen;
+ unsigned short operation;
+ unsigned char senderha[6];
+ unsigned char senderia[4];
+ unsigned char targetha[6];
+ unsigned char targetia[4];
+} __PACKED__ ;
+
+/* ARP/RARP operations:. */
+#define ARP_REQUEST 1
+#define ARP_RESPONSE 2
+#define RARP_REQUEST 3
+#define RARP_RESPONSE 4
+
+/************************************************************************
+ *
+ * IP stuff...
+ *
+ */
+
+struct in_addr {
+ unsigned long s_addr;
+} __PACKED__ ;
+
+#define getIP_V(x) ((x)>>4)
+#define getIP_HL(x) ((x)&0xf)
+#define IP_DONTFRAG 0x4000 /* dont fragment flag */
+#define IP_MOREFRAGS 0x2000 /* more fragments flag */
+#define IP_VER 0x4
+#define IP_HDR_LEN (sizeof(struct ip)>>2)
+#define IP_HDR_VER_LEN ((IP_VER<<4)|IP_HDR_LEN)
+#define IP_HLEN(ihdr) ((ihdr->ip_vhl&0x0f)<<2)
+
+struct ip {
+ unsigned char ip_vhl; /* version & header length */
+ unsigned char ip_tos; /* type of service */
+ short ip_len; /* total length */
+ unsigned short ip_id; /* identification */
+ short ip_off; /* fragment offset field */
+ unsigned char ip_ttl; /* time to live */
+ unsigned char ip_p; /* protocol */
+ unsigned short ip_sum; /* checksum */
+ struct in_addr ip_src; /* source address */
+ struct in_addr ip_dst; /* dest address */
+} __PACKED__ ;
+#define IPSIZE sizeof(struct ip)
+
+/* ip protocols */
+#define IP_IP 0
+#define IP_ICMP 1
+#define IP_IGMP 2
+#define IP_GGP 3
+#define IP_TCP 6
+#define IP_PUP 12
+#define IP_UDP 17
+
+#define IP1(a) ((a & 0xff000000) >> 24)
+#define IP2(a) ((a & 0xff0000) >> 16)
+#define IP3(a) ((a & 0xff00) >> 8)
+#define IP4(a) (a & 0xff)
+
+#define IP2LONG(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d)
+
+/************************************************************************
+ *
+ * ICMP stuff...
+ *
+ */
+
+#define ICMP_UNREACHABLESIZE (sizeof(struct ether_header) + \
+ sizeof(struct ip) + sizeof(struct icmp_unreachable_hdr) + datalen)
+#define ICMP_TIMERQSTSIZE (sizeof(struct ether_header) + \
+ sizeof(struct ip) + sizeof(struct icmp_time_hdr))
+#define ICMP_ECHORQSTSIZE (sizeof(struct ether_header) + \
+ sizeof(struct ip) + sizeof(struct icmp_echo_hdr))
+
+#define INVALID_TIMESTAMP 0xffffffff
+#define NONSTANDARD_TIMESTAMP 0x80000000
+
+/* ICMP protocol header.
+ */
+struct icmp_hdr {
+ unsigned char type; /* type of message */
+ unsigned char code; /* type subcode */
+ unsigned short cksum; /* ones complement cksum of struct */
+} __PACKED__ ;
+
+/* ICMP time request.
+ */
+struct icmp_time_hdr {
+ unsigned char type; /* type of message */
+ unsigned char code; /* type subcode */
+ unsigned short cksum; /* ones complement cksum of struct */
+ unsigned short id; /* identifier */
+ unsigned short seq; /* sequence number */
+ unsigned long orig; /* originate timestamp */
+ unsigned long recv; /* receive timestamp */
+ unsigned long xmit; /* transmit timestamp */
+} __PACKED__ ;
+
+/* ICMP echo reply.
+ */
+struct icmp_echo_hdr {
+ unsigned char type; /* type of message */
+ unsigned char code; /* type subcode */
+ unsigned short cksum; /* ones complement cksum of struct */
+ unsigned short id; /* identifier */
+ unsigned short seq; /* sequence number */
+} __PACKED__ ;
+
+struct icmp_unreachable_hdr {
+ unsigned char type; /* type of message */
+ unsigned char code; /* type subcode */
+ unsigned short cksum; /* ones complement cksum of struct */
+ unsigned short unused1; /* Is alway zero */
+ unsigned short unused2; /* Is alway zero */
+} __PACKED__ ;
+
+/* ICMP types
+ */
+#define ICMP_ECHOREPLY 0
+#define ICMP_DESTUNREACHABLE 3
+#define ICMP_SOURCEQUENCH 4
+#define ICMP_REDIRECT 5
+#define ICMP_ECHOREQUEST 8
+#define ICMP_TIMEEXCEEDED 11
+#define ICMP_PARAMPROBLEM 12
+#define ICMP_TIMEREQUEST 13
+#define ICMP_TIMEREPLY 14
+#define ICMP_INFOREQUEST 15
+#define ICMP_INFOREPLY 16
+#define ICMP_ADDRMASKREQUEST 17
+#define ICMP_ADDRMASKREPLY 18
+
+/* A few unreachable codes.
+ */
+#define ICMP_UNREACHABLE_PROTOCOL 2
+#define ICMP_UNREACHABLE_PORT 3
+#define ICMP_DEST_UNREACHABLE_MAX_CODE 12
+
+/************************************************************************
+ *
+ * UDP stuff...
+ *
+ */
+
+/* UDP protocol header.
+ */
+struct Udphdr {
+ unsigned short uh_sport; /* source port */
+ unsigned short uh_dport; /* destination port */
+ unsigned short uh_ulen; /* udp length */
+ unsigned short uh_sum; /* udp checksum */
+} __PACKED__ ;
+#define UDPSIZE sizeof(struct Udphdr)
+
+/* UDP pseudo header.
+ */
+struct UdpPseudohdr {
+ struct in_addr ip_src; /* source address */
+ struct in_addr ip_dst; /* dest address */
+ unsigned char zero; /* fixed to zero */
+ unsigned char proto; /* protocol */
+ unsigned short ulen; /* udp length */
+} __PACKED__ ;
+
+#define UDP_OPEN 2
+#define UDP_DATA 3
+#define UDP_ACK 4
+#define UDP_TTL 0x3c
+
+/************************************************************************
+ *
+ * IGMP stuff...
+ *
+ */
+
+/* IGMP protocol header.
+ */
+struct Igmphdr {
+ unsigned char type; /* IGMP message type */
+ unsigned char mrt; /* Max response time */
+ unsigned short csum; /* Checksum of IGMP header */
+ unsigned long group; /* Multicast group ip */
+} __PACKED__ ;
+
+#define IGMPSIZE sizeof(struct Igmphdr)
+
+#define IGMPTYPE_QUERY 0x11
+#define IGMPTYPE_REPORTV1 0x12
+#define IGMPTYPE_REPORTV2 0x16
+#define IGMPTYPE_JOIN IGMPTYPE_REPORTV2
+#define IGMPTYPE_LEAVE 0x17
+
+#define ALL_HOSTS 0xe0000001 /* 224.0.0.1 */
+#define ALL_MULTICAST_ROUTERS 0xe0000002 /* 224.0.0.2 */
+
+#define IGMP_JOINRQSTSIZE (sizeof(struct ether_header) + \
+ sizeof(struct ip) + sizeof(long) + sizeof(struct Igmphdr))
+
+/************************************************************************
+ *
+ * TFTP stuff...
+ *
+ */
+
+/* TFTP state values:
+ */
+#define TFTPOFF 0
+#define TFTPIDLE 1
+#define TFTPACTIVE 2
+#define TFTPERROR 3
+#define TFTPSENTRRQ 4
+#define TFTPTIMEOUT 5
+#define TFTPHOSTERROR 6
+#define TFTPSENTWRQ 7
+
+/* TFTP opcode superset (see Stevens pg 466)
+ */
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DAT 3
+#define TFTP_ACK 4
+#define TFTP_ERR 5
+#define TFTP_OACK 6 /* RFC2347: Option Acknowledgement opcode. */
+
+/* TFTP is UDP port 69... (see Stevens pg 206)
+ */
+#define IPPORT_TFTP 69
+#define IPPORT_TFTPSRC 8888
+
+#define TFTP_NETASCII_WRQ 1
+#define TFTP_NETASCII_RRQ 2
+#define TFTP_OCTET_WRQ 3
+#define TFTP_OCTET_RRQ 4
+#define TFTP_DATAMAX 512
+#define TFTP_PKTOVERHEAD (ETHERSIZE + IPSIZE + UDPSIZE)
+#define TFTPACKSIZE (TFTP_PKTOVERHEAD + 4)
+
+/************************************************************************
+ *
+ * DHCP stuff...
+ * See RFCs 2131 & 2132 for more details.
+ * Note that the values used for dhcpstate enum are based on the state
+ * diagram in 3rd Edition Comer pg 375. Plus a few more so that I can
+ * used the same enum for DHCP and BOOTP.
+ *
+ */
+
+#define BOOTPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \
+ sizeof(struct Udphdr) + sizeof(struct bootphdr))
+
+#define DHCPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \
+ sizeof(struct Udphdr) + sizeof(struct dhcphdr))
+
+#define IPPORT_DHCP_SERVER 67
+#define IPPORT_DHCP_CLIENT 68
+
+#define DHCPBOOTP_REQUEST 1
+#define DHCPBOOTP_REPLY 2
+
+#define USE_NULL 0
+#define USE_DHCP 1
+#define USE_BOOTP 2
+
+#define DHCP_VERBOSE (SHOW_DHCP|SHOW_INCOMING|SHOW_OUTGOING|SHOW_BROADCAST)
+
+/* DHCP Message types:
+ */
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNACK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+#define DHCPFORCERENEW 9
+#define DHCPLEASEQUERY 10
+#define DHCPLEASEUNASSIGNED 11
+#define DHCPLEASEUNKNOWN 12
+#define DHCPLEASEACTIVE 13
+#define DHCPUNKNOWN 99
+
+/* DHCPState (short) values: (upper bit set = bootp)
+ */
+#define DHCPSTATE_INITIALIZE 0x0001
+#define DHCPSTATE_INITDELAY 0x0002
+#define DHCPSTATE_SELECT 0x0003
+#define DHCPSTATE_REQUEST 0x0004
+#define DHCPSTATE_BOUND 0x0005
+#define DHCPSTATE_RENEW 0x0006
+#define DHCPSTATE_REBIND 0x0007
+#define DHCPSTATE_NOTUSED 0x0008
+#define DHCPSTATE_RESTART 0x0009
+#define BOOTP_MODE 0x8000
+#define BOOTPSTATE_INITIALIZE 0x8001
+#define BOOTPSTATE_INITDELAY 0x8002
+#define BOOTPSTATE_REQUEST 0x8003
+#define BOOTPSTATE_RESTART 0x8004
+#define BOOTPSTATE_COMPLETE 0x8005
+
+/* DHCP Options
+ */
+#define DHCPOPT_SUBNETMASK 1
+#define DHCPOPT_ROUTER 3
+#define DHCPOPT_HOSTNAME 12
+#define DHCPOPT_ROOTPATH 17
+#define DHCPOPT_BROADCASTADDRESS 28
+#define DHCPOPT_VENDORSPECIFICINFO 43
+#define DHCPOPT_REQUESTEDIP 50
+#define DHCPOPT_LEASETIME 51
+#define DHCPOPT_MESSAGETYPE 53
+#define DHCPOPT_SERVERID 54
+#define DHCPOPT_PARMRQSTLIST 55
+#define DHCPOPT_CLASSID 60
+#define DHCPOPT_CLIENTID 61
+#define DHCPOPT_NISDOMAINNAME 64
+#define DHCPOPT_NISSERVER 65
+
+#define STANDARD_MAGIC_COOKIE 0x63825363 /* 99.130.83.99 */
+
+struct dhcphdr {
+ unsigned char op;
+ unsigned char htype;
+ unsigned char hlen;
+ unsigned char hops;
+ unsigned long transaction_id;
+ unsigned short seconds;
+ unsigned short flags;
+ unsigned long client_ip;
+ unsigned long your_ip;
+ unsigned long server_ip;
+ unsigned long router_ip;
+ unsigned char client_macaddr[16];
+ unsigned char server_hostname[64];
+ unsigned char bootfile[128];
+ unsigned long magic_cookie;
+ /* Dhcp options would start here */
+} __PACKED__ ;
+
+struct bootphdr {
+ unsigned char op;
+ unsigned char htype;
+ unsigned char hlen;
+ unsigned char hops;
+ unsigned long transaction_id;
+ unsigned short seconds;
+ unsigned short unused;
+ unsigned long client_ip;
+ unsigned long your_ip;
+ unsigned long server_ip;
+ unsigned long router_ip;
+ unsigned char client_macaddr[16];
+ unsigned char server_hostname[64];
+ unsigned char bootfile[128];
+ unsigned char vsa[64];
+} __PACKED__ ;
+
+unsigned char *DhcpGetOption(unsigned char, unsigned char *);
+
+/************************************************************************
+ *
+ * DNS stuff...
+ *
+ * The area of the dnshdr structure beginning with the question array
+ * is actually a variable sized area for four sections:
+ * question, answer, authority and additional information.
+ * For the monitor's implementation of DNS, it is simplified to need
+ * only the question section because we are only using this to do
+ * a standard DNS query (give a domain name to a server and wait for
+ * a response that has the IP address).
+ * So, for the sake of building a fixed size structure, we allocate a
+ * 64 byte question section and assume that no single domain name request
+ * will exceed that length.
+ * Note: first byte of domain name is the size.
+ *
+ * For MulticastDNS information I used...
+ * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt
+ */
+#define MAX_DOMAIN_NAME_SIZE 63
+
+struct dnshdr {
+ unsigned short id;
+ unsigned short param;
+ unsigned short num_questions;
+ unsigned short num_answers;
+ unsigned short num_authority;
+ unsigned short num_additional;
+ unsigned char question[MAX_DOMAIN_NAME_SIZE+1];
+} __PACKED__ ;
+
+#define IPPORT_DNS 53
+#define TYPE_A 1
+#define TYPE_CNAME 5
+#define CLASS_IN 1
+
+/* DNS Error codes:
+ */
+#define DNSERR_NULL 0
+#define DNSERR_COMPLETE 1
+#define DNSERR_NOSRVR 2
+#define DNSERR_SOCKETFAIL 3
+#define DNSERR_FORMATERR 4
+#define DNSERR_SRVRFAILURE 5
+#define DNSERR_NAMENOEXIST 6
+#define DNSERR_BADRESPTYPE 7
+#define DNSERR_BADQSTNCOUNT 8
+#define DNSERR_BADANSWRCOUNT 9
+#define DNSERR_NOTARESPONSE 10
+#define DNSERR_BADRESPID 11
+
+#define DNSMCAST_IP IP2LONG(224,0,0,251)
+#define DNSMCAST_PORT 5353
+
+/* DNS Buffer sizes:
+ */
+#define MAX_CACHED_HOSTNAMES 32
+#define MAX_HOSTNAME_SIZE 255
+
+#define DNS_RETRY_MAX 5
+#define DNS_PKTBUF_SIZE 512
+
+struct dnserr {
+ int errno;
+ char *errstr;
+};
+
+struct dnscache {
+ int idx;
+ unsigned long addr;
+ char name[MAX_HOSTNAME_SIZE+1];
+};
+
+extern const char mDNSIp[];
+
+/************************************************************************
+ *
+ * TCP stuff...
+ *
+ */
+
+struct tcphdr {
+ unsigned short sport; /* Source port */
+ unsigned short dport; /* Source port */
+ unsigned long seqno; /* Sequence number */
+ unsigned long ackno; /* Acknowledgment number */
+ unsigned short flags; /* Flags (lower 6 bits) */
+ unsigned short windowsize; /* Window size */
+ unsigned short tcpcsum; /* TCP checksum */
+ unsigned short urgentptr; /* Urgent pointer */
+/* options (if any) & data (if any) follow */
+} __PACKED__ ;
+
+/* Masks for flags (made up of flag bits, reserved bits & header length):
+ */
+#define TCP_FLAGMASK 0x003F
+#define TCP_RSVDMASK 0x0FC0
+#define TCP_HDRLENMASK 0xF000
+#define TCP_HLEN(tp) (((tp)->flags & TCP_HDRLENMASK) >> 10)
+
+/* Masks for flag bits within flags member:
+ */
+#define TCP_FINISH 0x0001
+#define TCP_SYNC 0x0002
+#define TCP_RESET 0x0004
+#define TCP_PUSH 0x0008
+#define TCP_ACK 0x0010
+#define TCP_URGENT 0x0020
+
+
+/************************************************************************
+ *
+ * Miscellaneous...
+ *
+ */
+
+/* Port that is used to issue monitor commands through ethernet.
+ */
+#define MONRESPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \
+ sizeof(struct Udphdr) + idx)
+#define IPPORT_MONCMD 777
+#define IPPORT_GDB 1234
+
+/* Verbosity levels used by various ethernet layers:
+ */
+#define SHOW_INCOMING 0x00000001
+#define SHOW_OUTGOING 0x00000002
+#define SHOW_HEX 0x00000004
+#define SHOW_BROADCAST 0x00000008
+#define SHOW_TFTP_TICKER 0x00000010
+#define SHOW_DHCP 0x00000020
+#define SHOW_ARP 0x00000040
+#define SHOW_ASCII 0x00000080
+#define SHOW_BADCSUM 0x00000100
+#define SHOW_BADCSUMV 0x00000200
+#define SHOW_PHY 0x00000400
+#define SHOW_GDB 0x00000800
+#define SHOW_TFTP_STATE 0x00001000
+#define SHOW_DRIVER_DEBUG 0x00002000
+#define SHOW_ALL 0xffffffff
+
+#define ENET_DEBUG_ENABLED() (EtherVerbose & SHOW_DRIVER_DEBUG)
+
+#define ETHER_INCOMING 1
+#define ETHER_OUTGOING 2
+
+extern char *Etheradd, *IPadd;
+extern unsigned char etheraddr[], ipaddr[];
+extern unsigned short MoncmdPort, TftpPort, TftpSrcPort;
+extern unsigned short DhcpClientPort, DhcpServerPort, DHCPState;
+extern int EtherVerbose, IPMonCmdActive, EtherIsActive, EtherPollingOff;
+extern unsigned char BinEnetAddr[], BinIpAddr[];
+extern unsigned char AllZeroAddr[], BroadcastAddr[];
+extern int EtherXFRAMECnt, EtherRFRAMECnt, EtherIPERRCnt, EtherUDPERRCnt;
+
+extern int getAddresses(void);
+extern int IpToBin(char *,unsigned char *);
+extern int EtherToBin(char *,unsigned char *);
+extern char *extGetIpAdd(void), *extGetEtherAdd(void);
+extern char *IpToString(unsigned long, char *);
+extern char *EtherToString(unsigned char *,char *);
+extern unsigned short ipId(void);
+extern unsigned char *ArpEther(unsigned char *,unsigned char *,int);
+extern unsigned char *getXmitBuffer(void);
+extern unsigned char *EtherFromCache(unsigned char *);
+extern void ipChksum(struct ip *), udpChksum(struct ip *);
+extern void tcpChksum(struct ip *);
+#if INCLUDE_ETHERVERBOSE
+extern void printPkt(struct ether_header *,int,int);
+#else
+#define printPkt(a,b,c)
+#endif
+extern void DhcpBootpDone(int, struct dhcphdr *,int);
+extern void DhcpVendorSpecific(struct dhcphdr *);
+extern int sendBuffer(int);
+extern struct ether_header *EtherCopy(struct ether_header *);
+extern int ValidDHCPOffer(struct dhcphdr *);
+extern int buildDhcpHdr(struct dhcphdr *);
+extern int printDhcpVSopt(int,int,char *);
+extern int RetransmitDelay(int);
+extern int tftpGet(unsigned long,char *,char *,char *,char *,char *,char *);
+extern void printDhcp(struct Udphdr *);
+extern int printIp(struct ip*);
+extern int printUdp(struct Udphdr *,char *);
+extern int printIgmp(struct Igmphdr *,char *);
+extern void processPACKET(struct ether_header *,unsigned short);
+extern void processTCP(struct ether_header *,unsigned short);
+extern int processTFTP(struct ether_header *,unsigned short);
+extern int processICMP(struct ether_header *,unsigned short);
+extern char *processARP(struct ether_header *,unsigned short);
+extern int processDHCP(struct ether_header *,unsigned short);
+extern int processRARP(struct ether_header *,unsigned short);
+extern int processGDB(struct ether_header *,unsigned short);
+extern int processDNS(struct ether_header *,unsigned short);
+extern int processMCASTDNS(struct ether_header *,unsigned short);
+extern int SendICMPUnreachable(struct ether_header *,unsigned char);
+extern void enresetmmu(void), enreset(void);
+extern void ShowEtherdevStats(void), ShowTftpStats(void), ShowDhcpStats(void);
+extern void enablePromiscuousReception(void);
+extern void disablePromiscuousReception(void);
+extern int enselftest(int), polletherdev(void), EtherdevStartup(int);
+extern void DisableEtherdev(void);
+extern void tftpStateCheck(void), dhcpStateCheck(void);
+extern int DhcpIPCheck(char *);
+extern void dhcpDisable(void);
+extern void tftpInit(void);
+extern void disableBroadcastReception(void);
+extern void enableBroadcastReception(void);
+extern void sendGratuitousArp(void);
+
+extern unsigned long getHostAddr(char *);
+extern int dnsCacheDelName(char *);
+extern void dnsCacheInit(void);
+extern int dnsCacheAdd(char *, unsigned long);
+extern int dnsCacheDelAddr(unsigned long);
+extern short DnsPort;
+
+#if INCLUDE_ETHERNET
+extern int pollethernet(void);
+extern int EthernetStartup(int,int);
+#else
+#define pollethernet()
+#define EthernetStartup(a,b)
+#endif
+
+#if INCLUDE_MONCMD
+extern int SendIPMonChar(unsigned char,int);
+#else
+#define SendIPMonChar(a,b)
+#endif
+
+extern int DisableEthernet(void);
+extern void storeMac(int);
+extern void GetBinNetMask(unsigned char *binnetmask);
+extern int monSendEnetPkt(char *pkt, int cnt);
+extern int monRecvEnetPkt(char *pkt, int cnt);
+extern void AppPrintPkt(char *buf, int size, int incoming);
+
+#endif
diff --git a/main/common/etheraddr.S b/main/common/etheraddr.S
new file mode 100644
index 0000000..901d87e
--- /dev/null
+++ b/main/common/etheraddr.S
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * etheraddr.S:
+ *
+ * Provide space to allow a programmer to place an ascii
+ * string in this location as an optional point
+ * of storage for MAC ...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+ .global etheraddr
+
+ .balign 0x10
+
+etheraddr:
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
diff --git a/main/common/ethernet.c b/main/common/ethernet.c
new file mode 100644
index 0000000..e24d0cd
--- /dev/null
+++ b/main/common/ethernet.c
@@ -0,0 +1,1808 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * ethernet.c:
+ *
+ * This code supports most of the generic ethernet/IP/ARP/UDP stuff.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "endian.h"
+#include "stddefs.h"
+#include "genlib.h"
+
+#if INCLUDE_ETHERNET
+#include "cpuio.h"
+#include "ether.h"
+#include "monflags.h"
+#include "cli.h"
+#include "timer.h"
+
+void ShowEthernetStats(void);
+
+#if INCLUDE_MONCMD
+void executeMONCMD(void);
+void processMONCMD(struct ether_header *,ushort);
+int SendIPMonChar(uchar,int);
+char IPMonCmdLine[CMDLINESIZE];
+int IPMonCmdVerbose;
+int IPMonCmdActive; /* Set if MONCMD is in progress. */
+#endif
+
+#if INCLUDE_DHCPBOOT
+#define dhcpStateCheck() dhcpStateCheck()
+#define dhcpDisable() dhcpDisable()
+#define ShowDhcpStats() ShowDhcpStats()
+#else
+#define dhcpStateCheck()
+#define dhcpDisable()
+#define ShowDhcpStats()
+#endif
+
+#if INCLUDE_TFTP
+#define tftpStateCheck() tftpStateCheck()
+#define tftpInit() tftpInit()
+#define ShowTftpStats() ShowTftpStats()
+#else
+#define tftpStateCheck()
+#define tftpInit()
+#define ShowTftpStats()
+#endif
+
+
+#if INCLUDE_ETHERVERBOSE
+int EtherVerbose; /* Verbosity flag (see ether.h). */
+#endif
+
+char *Etheradd, *IPadd; /* Pointers to ascii addresses */
+uchar BinIpAddr[4]; /* Space for binary IP address */
+uchar BinEnetAddr[6]; /* Space for binary MAC address */
+int EtherPollingOff; /* Non-zero if ethernet polling is off. */
+int EtherIsActive; /* Non-zero if ethernet is up. */
+int EtherIPERRCnt; /* Number of IP errors detected. */
+int EtherUDPERRCnt; /* Number of UDP errors detected. */
+int EtherXFRAMECnt; /* Number of packets transmitted. */
+int EtherRFRAMECnt; /* Number of packets received. */
+int EtherPollNesting; /* Incremented when pollethernet() is called. */
+int MaxEtherPollNesting; /* High-warter mark of EtherPollNesting. */
+ushort UniqueIpId;
+ulong IPMonCmdHdrBuf[(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + 128)/(sizeof(ulong))];
+struct ether_header *IPMonCmdHdr;
+
+/* AppPktPtr & AppPktLen:
+ * These two values are used to allow the monitor's ethernet driver
+ * to easily (not necessarily most efficiently) hook up to an application
+ * that needs to be able to send and/or receive ethernet packets.
+ * Refer to discussion above monRecvEnetPkt().
+ */
+char *AppPktPtr;
+int AppPktLen;
+
+/* Ports used by the monitor have defaults, but can be redefined using
+ * shell variables:
+ */
+ushort MoncmdPort; /* shell var: MCMDPORT */
+ushort GdbPort; /* shell var: GDBPORT */
+ushort DhcpClientPort; /* shell var: DCLIPORT */
+ushort DhcpServerPort; /* shell var: DSRVPORT */
+ushort TftpPort; /* shell var: TFTPPORT */
+ushort TftpSrcPort; /* shell var: TFTPPORT */
+
+uchar BroadcastAddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar AllZeroAddr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if INCLUDE_ETHERVERBOSE
+struct pinfo {
+ int pnum;
+ char *pname;
+} protocols[] = {
+ { IP_IP, "IP" },
+ { IP_ICMP, "ICMP" },
+ { IP_IGMP, "IGMP" },
+ { IP_GGP, "GGP" },
+ { IP_TCP, "TCP" },
+ { IP_PUP, "PUP" },
+ { IP_UDP, "UDP" },
+ { 0,0 },
+};
+
+struct enet_verbosity {
+ char letter;
+ ulong flags;
+} enet_verbose_tbl[] = {
+ { '0', 0 },
+ { 'a', SHOW_ARP | SHOW_BROADCAST },
+ { 'c', SHOW_BADCSUM },
+ { 'C', SHOW_BADCSUM | SHOW_BADCSUMV },
+ { 'd', SHOW_DHCP },
+#if INCLUDE_GDB
+ { 'g', SHOW_GDB },
+#endif
+ { 'i', SHOW_INCOMING },
+ { 'I', SHOW_INCOMING | SHOW_BROADCAST },
+ { 'o', SHOW_OUTGOING },
+ { 'p', SHOW_PHY },
+ { 't', SHOW_TFTP_STATE },
+ { 'x', SHOW_HEX },
+ { 'X', SHOW_HEX | SHOW_ASCII },
+ { 0,0 }
+};
+
+int
+SetEthernetVerbosity(char *letters)
+{
+ ulong verbose = 0;
+ struct enet_verbosity *evp = enet_verbose_tbl;
+
+ while(*letters) {
+ evp = enet_verbose_tbl;
+ while(evp->letter) {
+ if (*letters == evp->letter) {
+ verbose |= evp->flags;
+ break;
+ }
+ evp++;
+ }
+ if (evp->letter == 0) {
+ printf("Invalid verbosity: '%c'\n",*letters);
+ return(CMD_PARAM_ERROR);
+ }
+
+ letters++;
+ }
+ EtherVerbose = verbose;
+ return(CMD_SUCCESS);
+}
+#endif
+
+char *EtherHelp[] = {
+ "Ethernet interface",
+ "-[d:pt:v:V] {cmd} [cmd args]",
+#if INCLUDE_VERBOSEHELP
+ "Options...",
+ " -d {1|0} driver debug mode (1=on)",
+ " -p {1|0} promiscuous mode (1=on)",
+ " -t self-test ethernet interface",
+#if INCLUDE_ETHERVERBOSE
+ " -v {flgs} enable specific verbosity...",
+ " 0: turn off verbosity",
+ " a: enable ARP trace",
+ " c: print csum errmsg",
+ " C: dump csum errpkt",
+ " d: enable DHCP trace",
+#if INCLUDE_GDB
+ " g: enable GDB trace",
+#endif
+ " i: incoming packets (minus broadcast)",
+ " I: incoming packets (including broadcast)",
+ " o: outgoing packets",
+ " p: phy r/w accesses",
+ " t: enable TFTP trace",
+ " x: enable hex dump (requires i,I or o)",
+ " X: same as 'x' plus ascii",
+ " -V full verbosity (same as -v Iodtx)",
+#endif
+ "",
+ "Commands...",
+ " {on | off | mac | stat | {print I|i|O pkt len} | {psnd addr len}}",
+#endif
+ 0
+};
+
+
+int
+Ether(int argc,char *argv[])
+{
+ int opt;
+
+ /* Automatically turn polling on if this command is issued.
+ */
+ EtherPollingOff = 0;
+
+ while ((opt=getopt(argc,argv,"d:p:s:tv:V")) != -1) {
+ switch(opt) {
+ case 'p':
+ if (*optarg == '1')
+ enablePromiscuousReception();
+ else
+ disablePromiscuousReception();
+ return(CMD_SUCCESS);
+ case 't':
+ if (EtherIsActive == 0) {
+ printf("Selftest requires active driver to run\n");
+ return(CMD_FAILURE);
+ }
+ enselftest(1);
+ return(CMD_SUCCESS);
+#if INCLUDE_ETHERVERBOSE
+ case 'd':
+ if (*optarg == '1')
+ EtherVerbose |= SHOW_DRIVER_DEBUG;
+ else
+ EtherVerbose &= ~SHOW_DRIVER_DEBUG;
+ return(CMD_SUCCESS);
+ case 'V':
+ EtherVerbose = SHOW_ALL;
+ return(CMD_SUCCESS);
+ case 'v':
+ return(SetEthernetVerbosity(optarg));
+#endif
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc <= optind)
+ return(CMD_SUCCESS);
+
+ if (!strcmp(argv[optind],"off")) {
+ enreset();
+ EtherIsActive = 0;
+ return(CMD_SUCCESS);
+ }
+#if INCLUDE_ETHERVERBOSE
+ else if (!strcmp(argv[optind],"print")) {
+ if (argc == optind+4) {
+ int len, mode;
+ ulong overbose;
+ struct ether_header *pkt;
+
+ overbose = EtherVerbose;
+ switch(argv[optind+1][0]) {
+ case 'O':
+ mode = ETHER_OUTGOING;
+ EtherVerbose = SHOW_ALL;
+ break;
+ case 'I':
+ mode = ETHER_INCOMING;
+ EtherVerbose = SHOW_ALL;
+ break;
+ case 'i':
+ mode = ETHER_INCOMING;
+ EtherVerbose = (SHOW_ALL & ~SHOW_BROADCAST);
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ pkt = (struct ether_header *)strtol(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ printPkt(pkt,len,mode);
+ EtherVerbose = overbose;
+ return(CMD_SUCCESS);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+#endif
+ else if (!strcmp(argv[optind],"mac")) {
+ storeMac(1);
+ return(CMD_SUCCESS);
+ }
+ else if (!strcmp(argv[optind],"psnd")) {
+ ulong addr, len;
+ uchar *buf;
+ addr = strtol(argv[optind+1],0,0);
+ len = strtol(argv[optind+2],0,0);
+ buf = getXmitBuffer();
+ memcpy((char *)buf,(char *)addr,(int)len);
+ sendBuffer(len);
+ return(CMD_SUCCESS);
+ }
+ else if (!strcmp(argv[optind],"stat")) {
+ ShowEthernetStats();
+ ShowEtherdevStats();
+ ShowDhcpStats();
+ ShowTftpStats();
+ return(CMD_SUCCESS);
+ }
+ else if (strcmp(argv[optind],"on"))
+ return(CMD_PARAM_ERROR);
+
+#if INCLUDE_ETHERVERBOSE
+ EthernetStartup(EtherVerbose,0);
+#else
+ EthernetStartup(0,0);
+#endif
+ return(CMD_SUCCESS);
+}
+
+void
+ShowEthernetStats(void)
+{
+ printf("Ethernet interface currently %sabled.\n",
+ EtherIsActive ? "en" : "dis");
+ printf("Transmitted frames: %d\n",EtherXFRAMECnt);
+ printf("Received frames: %d\n",EtherRFRAMECnt);
+ printf("IP hdr cksum errors: %d\n",EtherIPERRCnt);
+ printf("UDP pkt cksum errors: %d\n",EtherUDPERRCnt);
+ printf("Max pollethernet nest: %d\n",MaxEtherPollNesting);
+}
+
+/* DisableEthernet():
+ * Shut down the interface, and return the state of the
+ * interface prior to forcing the shut down.
+ */
+int
+DisableEthernet(void)
+{
+ int eia;
+
+ eia = EtherIsActive;
+ EtherIsActive = 0;
+#if INCLUDE_MONCMD
+ IPMonCmdActive = 0;
+#endif
+ DisableEtherdev();
+ return(eia);
+}
+
+/* EthernetWaitforLinkup():
+ * If the ENET_LINK_IS_UP() macro is defined, then use it to poll
+ * the just-initialized ethernet link so that we don't return from
+ * this point until the port is active.
+ * Return:
+ * 0 if no macro is defined or poll is aborted
+ * 1 if link is up
+ * -1 if link is not up
+ */
+int
+EthernetWaitforLinkup(void)
+{
+ int linkup = 0;
+
+#ifdef ENET_LINK_IS_UP
+#ifndef LINKUP_TICK_MAX
+#define LINKUP_TICK_MAX 15
+#endif
+ extern int ENET_LINK_IS_UP(void);
+
+ int tick;
+ struct elapsed_tmr tmr;
+
+ if (getenv("ETHERNET_NOWAIT"))
+ return(0);
+
+ for(tick=0;tick<LINKUP_TICK_MAX;tick++) {
+ startElapsedTimer(&tmr,500);
+ while(1) {
+ if (gotachar())
+ goto done;
+
+ if (ENET_LINK_IS_UP()) {
+ linkup = 1;
+ goto done;
+ }
+ if(msecElapsed(&tmr)) {
+ if (tick == 0) {
+ tick++;
+ printf("Wait for enet link up (hit-a-key to abort) ");
+ }
+ else
+ putchar('.');
+ break;
+ }
+ }
+ }
+ if (tick == LINKUP_TICK_MAX) {
+ linkup = -1;
+ printf(" give up.");
+ DisableEthernet();
+ }
+
+done:
+ putchar('\n');
+#endif
+
+ return(linkup);
+}
+
+int
+EthernetStartup(int verbose, int justreset)
+{
+ /* Initialize the retransmission delay calculator: */
+ RetransmitDelay(DELAY_INIT_DHCP);
+
+ EtherIPERRCnt = 0;
+ EtherXFRAMECnt = 0;
+ EtherRFRAMECnt = 0;
+ EtherUDPERRCnt = 0;
+#if INCLUDE_MONCMD
+ IPMonCmdActive = 0;
+#endif
+ EtherPollNesting = 0;
+ MaxEtherPollNesting = 0;
+ DHCPState = DHCPSTATE_NOTUSED;
+#if INCLUDE_ETHERVERBOSE
+ if (getenv("ETHERNET_DEBUG"))
+ EtherVerbose |= SHOW_DRIVER_DEBUG;
+ else
+ EtherVerbose = 0;
+#endif
+
+ /* Setup all the IP addresses used by the monitor... */
+ if (getAddresses() == -1)
+ return(-1);
+
+ /* Call device specific startup code: */
+ if (EtherdevStartup(verbose) < 0)
+ return(-1);
+
+ /* Initialize some TFTP state... */
+ tftpInit();
+
+#if INCLUDE_DHCPBOOT
+ /* If EthernetStartup is called as a result of anything other than a
+ * target reset, don't startup any DHCP/BOOTP transaction...
+ */
+ if (!justreset)
+ dhcpDisable();
+#endif
+ EtherIsActive = 1;
+ EtherPollingOff = 0;
+
+ /* Wait for link up state before continuing...
+ */
+ EthernetWaitforLinkup();
+
+ /* Issue a gratuitous ARP to let other devices on the net know we're
+ * here, and also to make sure some other device isn't already using
+ * the IP address that this target is using...
+ */
+ sendGratuitousArp();
+
+ return(0);
+}
+
+/* pollethernet():
+ * Called at a few critical points in the monitor code to poll the
+ * ethernet device and keep track of the state of DHCP and TFTP.
+ */
+int
+pollethernet(void)
+{
+ int pcnt;
+
+ if ((!EtherIsActive) || EtherPollingOff || (EtherPollNesting > 4))
+ return(0);
+
+ EtherPollNesting++;
+ if (EtherPollNesting > MaxEtherPollNesting)
+ MaxEtherPollNesting = EtherPollNesting;
+
+ pcnt = polletherdev();
+#if INCLUDE_MONCMD
+ if (IPMonCmdLine[0] != 0)
+ executeMONCMD();
+#endif
+
+ dhcpStateCheck();
+ tftpStateCheck();
+
+ EtherPollNesting--;
+ return(pcnt);
+}
+
+/* getAddresses():
+ * Try getting ether/ip addresses from environment.
+ * If not there, try getting them from some target-specific interface.
+ * If not there, then get them from raw flash.
+ * If not there, just use the hard-coded default.
+ * Also, load all port numbers from shell variables, else default.
+ *
+ * Discussion regarding etheraddr[]...
+ * The purpose of this array is to provide a point in flash that is
+ * initialized to 0xff by the code (see reset.s). This then allows some
+ * other mechanism (storeMAC() or bed of nails, etc..) to program this
+ * location to some non-0xff value. This allows the base monitor image to
+ * be common, but then be modified by other code or external hardware.
+ */
+
+int
+getAddresses(void)
+{
+ char *gdbPort, *dcliPort, *dsrvPort, *tftpPort;
+
+ /* Set up port numbers: */
+ gdbPort = getenv("GDBPORT");
+ dcliPort = getenv("DCLIPORT");
+ dsrvPort = getenv("DSRVPORT");
+ tftpPort = getenv("TFTPPORT");
+
+#if INCLUDE_MONCMD
+ {
+ char *mcmdPort = getenv("MCMDPORT");
+ if (mcmdPort)
+ MoncmdPort = (ushort)strtol(mcmdPort,0,0);
+ else
+ MoncmdPort = IPPORT_MONCMD;
+ }
+#endif
+
+ if (gdbPort)
+ GdbPort = (ushort)strtol(gdbPort,0,0);
+ else
+ GdbPort = IPPORT_GDB;
+ if (dcliPort)
+ DhcpClientPort = (ushort)strtol(dcliPort,0,0);
+ else
+ DhcpClientPort = IPPORT_DHCP_CLIENT;
+ if (dsrvPort)
+ DhcpServerPort = (ushort)strtol(dsrvPort,0,0);
+ else
+ DhcpServerPort = IPPORT_DHCP_SERVER;
+ if (tftpPort)
+ TftpPort = (ushort)strtol(tftpPort,0,0);
+ else
+ TftpPort = IPPORT_TFTP; /* 69 */
+ TftpSrcPort = IPPORT_TFTPSRC; /* 8888 */
+
+ /* Retrieve MAC address and store in shell variable ETHERADD...
+ * First see if the shell variable is already loaded.
+ * If not see if some target-specific interface has it.
+ * If not see if the the string is stored in raw flash (usually this
+ * storage is initialized in reset.s of the target-specific code).
+ * Finally, as a last resort, use the default set up in config.h.
+ */
+ if (!(Etheradd = getenv("ETHERADD"))) {
+ if (!(Etheradd = extGetEtherAdd())) {
+#if INCLUDE_FLASH
+ if (etheraddr[0] != 0xff)
+ Etheradd = (char *)etheraddr;
+ else
+#endif
+ Etheradd = DEFAULT_ETHERADD;
+ }
+ setenv("ETHERADD",Etheradd);
+ }
+
+ /* Apply the same logic as above to the IP address... */
+ if (!(IPadd = getenv("IPADD"))) {
+ if (!(IPadd = extGetIpAdd()))
+ IPadd = DEFAULT_IPADD;
+ setenv("IPADD",IPadd);
+ }
+
+ /* Convert addresses to binary:
+ */
+ if (EtherToBin(Etheradd,BinEnetAddr) < 0)
+ return(-1);
+
+ /* If the ethernet address is 0:0:0:0:0:0, then we
+ * return an error here so that the interface is not
+ * brought up.
+ */
+ if (memcmp((char *)BinEnetAddr, (char *)AllZeroAddr,6) == 0) {
+ static int firsttime;
+
+ if (firsttime == 0) {
+ printf("\nNULL MAC address, network interface disabled.\n");
+ firsttime = 1;
+ }
+ return(-1);
+ }
+
+#if INCLUDE_DHCPBOOT
+ if (DhcpIPCheck(IPadd) == -1)
+ return(-1);
+#else
+ if (IpToBin(IPadd,BinIpAddr) < 0)
+ return(-1);
+#endif
+ /* Initialize a unique number based on MAC: */
+ UniqueIpId = xcrc16(BinEnetAddr,6);
+
+ return(0);
+}
+
+/* processPACKET():
+ * This is the top level of the message processing after a complete
+ * packet has been received over ethernet. It's all just a lot of
+ * parsing to determine whether the message is for this board's IP
+ * address (broadcast reception may be enabled), and the type of
+ * incoming protocol. Once that is determined, the packet is either
+ * processed (TFTP, DHCP, ARP, ICMP-ECHO, etc...) or discarded.
+ */
+void
+processPACKET(struct ether_header *ehdr, ushort size)
+{
+ int i, udpdone;
+ ushort *datap, udpport;
+ ulong csum;
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+
+ WATCHDOG_MACRO;
+
+ /* If source MAC address is this board, then assume the MAC is in
+ * full-duplex mode and we received our own outgoing broadcast
+ * message (i.e. ignore it)...
+ */
+ if (!memcmp((char *)&(ehdr->ether_shost),(char *)BinEnetAddr,6)) {
+ return;
+ }
+
+ printPkt(ehdr,size,ETHER_INCOMING);
+
+ /* AppPktPtr is used by monRecvEnetPkt() so that an application can
+ * use the monitor's ethernet driver. For more info, refer to notes
+ * above the monRecvEnetPkt() function.
+ */
+ if (AppPktPtr) {
+ memcpy(AppPktPtr,(char *)ehdr,size > AppPktLen ? AppPktLen : size);
+ AppPktPtr = 0;
+ AppPktLen = size;
+ return;
+ }
+
+ EtherRFRAMECnt++;
+
+ if (ehdr->ether_type == ecs(ETHERTYPE_ARP)) {
+ processARP(ehdr,size);
+ return;
+ }
+ else if (ehdr->ether_type == ecs(ETHERTYPE_REVARP)) {
+ processRARP(ehdr,size);
+ return;
+ }
+ else if (ehdr->ether_type != ecs(ETHERTYPE_IP)) {
+ return;
+ }
+
+ ihdr = (struct ip *) (ehdr + 1);
+
+ /* If not version # 4, return now... */
+ if (getIP_V(ihdr->ip_vhl) != 4) {
+ return;
+ }
+
+#if INCLUDE_RARPIPASSIGN
+ /* If destination MAC address matches ours, and our IP address is
+ * 0.0.0.0, and this is an ICMP request, then this may be a reverse
+ * ARP, so we allow this packet through...
+ * Note that this logic is only applicable if DHCP is NOT running.
+ */
+ if (DHCPState == DHCPSTATE_NOTUSED) {
+ if (!memcmp((char *)&(ehdr->ether_dhost),(char *)BinEnetAddr,6) &&
+ (BinIpAddr[0] == 0) && (BinIpAddr[1] == 0) &&
+ (BinIpAddr[2] == 0) && (BinIpAddr[3] == 0) &&
+ (ihdr->ip_p == IP_ICMP)) {
+ goto skipIPAddrFilter;
+ }
+ }
+#endif
+
+ /* IP address filtering:
+ * At this point, the only packets accepted are those destined for this
+ * board's IP address or broadcast to the subnet, plus DHCP, if active,
+ */
+ if (memcmp((char *)&(ihdr->ip_dst),(char *)BinIpAddr,4)) {
+ long net_mask, sub_net_addr;
+
+#if INCLUDE_DNS
+ if (memcmp((char *)&(ihdr->ip_dst),(char *)mDNSIp,4)) {
+#endif
+ GetBinNetMask( (uchar *) &net_mask );
+ sub_net_addr = ihdr->ip_dst.s_addr & ~net_mask; /* x.x.x.255 */
+ uhdr = (struct Udphdr *)(ihdr+1);
+
+ if ( ihdr->ip_p != IP_UDP
+ || ecs(uhdr->uh_dport) != MoncmdPort
+ || sub_net_addr != ~net_mask ) {
+#if INCLUDE_DHCPBOOT
+ if (DHCPState == DHCPSTATE_NOTUSED)
+ return;
+ if (ihdr->ip_p != IP_UDP)
+ return;
+ uhdr = (struct Udphdr *)(ihdr+1);
+ if (uhdr->uh_dport != ecs(DhcpClientPort)) {
+ return;
+ }
+#else
+ return;
+#endif
+ }
+#if INCLUDE_DNS
+ }
+#endif
+ }
+
+#if INCLUDE_RARPIPASSIGN
+skipIPAddrFilter:
+#endif
+
+ /* Verify incoming IP header checksum...
+ * Refer to section 3.2 of TCP/IP Illustrated, Vol 1 for details.
+ */
+ csum = 0;
+ datap = (ushort *) ihdr;
+ for (i=0;i<(sizeof(struct ip)/sizeof(ushort));i++,datap++)
+ csum += *datap;
+ csum = (csum & 0xffff) + (csum >> 16);
+ if (csum != 0xffff) {
+ EtherIPERRCnt++;
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_BADCSUM) {
+ printf("IP csum error: 0x%04x != 0xffff\n",(ushort)csum);
+ if (EtherVerbose & SHOW_BADCSUMV) {
+ int overbose = EtherVerbose;
+
+ EtherVerbose = SHOW_ALL;
+ printPkt(ehdr,size,ETHER_INCOMING);
+ EtherVerbose = overbose;
+ }
+ }
+#endif
+ return;
+ }
+
+#if INCLUDE_ICMP
+ if (ihdr->ip_p == IP_ICMP) {
+ processICMP(ehdr,size);
+ return;
+ }
+ else
+#endif
+ if (ihdr->ip_p == IP_TCP) {
+ processTCP(ehdr,size);
+ return;
+ }
+ else if (ihdr->ip_p != IP_UDP) {
+
+#if INCLUDE_ICMP
+ SendICMPUnreachable(ehdr,ICMP_UNREACHABLE_PROTOCOL);
+#endif
+#if INCLUDE_ETHERVERBOSE
+ {
+ int j;
+
+ if (!(EtherVerbose & SHOW_INCOMING))
+ return;
+ for(j=0;protocols[j].pname;j++) {
+ if (ihdr->ip_p == protocols[j].pnum) {
+ printf("%s not supported\n",
+ protocols[j].pname);
+ return;
+ }
+ }
+ }
+#endif
+ printf("<%02x> protocol unrecognized\n", ihdr->ip_p);
+ return;
+ }
+
+ uhdr = (struct Udphdr *)(ihdr+1);
+
+ /* If non-zero, verify incoming UDP packet checksum...
+ * Refer to section 11.3 of TCP/IP Illustrated, Vol 1 for details.
+ */
+ if (uhdr->uh_sum) {
+ int len;
+ struct UdpPseudohdr pseudohdr;
+
+ memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4);
+ memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4);
+ pseudohdr.zero = 0;
+ pseudohdr.proto = ihdr->ip_p;
+ pseudohdr.ulen = uhdr->uh_ulen;
+
+ csum = 0;
+ datap = (ushort *) &pseudohdr;
+ for (i=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++)
+ csum += *datap++;
+
+ /* If length is odd, pad and add one. */
+ len = ecs(uhdr->uh_ulen);
+ if (len & 1) {
+ uchar *ucp;
+ ucp = (uchar *)uhdr;
+ ucp[len] = 0;
+ len++;
+ }
+ len >>= 1;
+
+ datap = (ushort *) uhdr;
+ for (i=0;i<len;i++)
+ csum += *datap++;
+ csum = (csum & 0xffff) + (csum >> 16);
+ if (csum != 0xffff) {
+ EtherUDPERRCnt++;
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_BADCSUM) {
+ printf("UDP csum error: 0x%04x != 0xffff\n",(ushort)csum);
+ if (EtherVerbose & SHOW_BADCSUMV) {
+ int overbose = EtherVerbose;
+
+ EtherVerbose = SHOW_ALL;
+ printPkt(ehdr,size,ETHER_INCOMING);
+ printf("pseudohdr.ip_src: 0x%08lx\n",
+ pseudohdr.ip_src.s_addr);
+ printf("pseudohdr.ip_dst: 0x%08lx\n",
+ pseudohdr.ip_dst.s_addr);
+ printf("pseudohdr.zero: 0x%02x\n", pseudohdr.zero);
+ printf("pseudohdr.proto: 0x%02x\n", pseudohdr.proto);
+ printf("pseudohdr.ulen: 0x%04x\n", pseudohdr.ulen);
+ EtherVerbose = overbose;
+ }
+ }
+#endif
+ return;
+ }
+ }
+ udpport = ecs(uhdr->uh_dport);
+ udpdone = 0;
+
+#if INCLUDE_MONCMD
+ if (!udpdone && (udpport == MoncmdPort)) {
+ processMONCMD(ehdr,size);
+ udpdone = 1;
+ }
+#endif
+#if INCLUDE_DHCPBOOT
+ if (!udpdone && (udpport == DhcpClientPort)) {
+ processDHCP(ehdr,size);
+ udpdone = 1;
+ }
+#endif
+#if INCLUDE_TFTP
+ if (!udpdone && ((udpport == TftpPort) || (udpport == TftpSrcPort))) {
+ processTFTP(ehdr,size);
+ udpdone = 1;
+ }
+#endif
+#if INCLUDE_DNS
+ if (!udpdone && (udpport == DnsPort)) {
+ processDNS(ehdr,size);
+ udpdone = 1;
+ }
+ if (!udpdone && (ecl(ihdr->ip_dst.s_addr) == DNSMCAST_IP) &&
+ (udpport == DNSMCAST_PORT)) {
+ processMCASTDNS(ehdr,size);
+ udpdone = 1;
+ }
+#endif
+#if INCLUDE_GDB
+ if (!udpdone && (udpport == GdbPort)) {
+ processGDB(ehdr,size);
+ udpdone = 1;
+ }
+#endif
+ if (!udpdone) {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_INCOMING) {
+ uchar *cp;
+ cp = (uchar *)&(ihdr->ip_src);
+ printf(" Unexpected IP pkt from %d.%d.%d.%d ",
+ cp[0],cp[1],cp[2],cp[3]);
+ printf("(sport=0x%x,dport=0x%x)\n",
+ ecs(uhdr->uh_sport),ecs(uhdr->uh_dport));
+ }
+#endif
+#if INCLUDE_ICMP
+ SendICMPUnreachable(ehdr,ICMP_UNREACHABLE_PORT);
+#endif
+ }
+}
+
+#if INCLUDE_MONCMD
+#define MONCMD_SRCIP_VARNAME "MONCMD_SRCIP"
+#define MONCMD_SRCPORT_VARNAME "MONCMD_SRCPORT"
+
+/* processMONCMD():
+ * This function is called as a result of receiving a packet on port
+ * 777. It will process the incoming packet as if it was an ASCII
+ * command destined for MicroMonitor's CLI.
+ *
+ * As of Aug 16, 2004, support for NETCAT is also in this function.
+ * Differentiating between netcat and moncmd is done by looking
+ * for the terminating newline character which is only present with
+ * netcat. For example:
+ * The following host command line: <netcat -u 135.222.140.72 777>
+ * puts the netcat user into an interactive mode with uMon so
+ * normal uMon commands can be issued through netcat (until interrupted).
+ *
+ * As of Aug 5, 2005, another change has been made to uMon's MONCMD
+ * server as a result of a bug reported by Leon Pollack. The change
+ * breaks up the processing of the incoming moncmd request into two
+ * parts processMONCMD() and executeMONCMD() (refer to CVS log for
+ * more details):
+ *
+ * 1. processMONCMD():
+ * Retrieve the incoming message from the ethernet interface and
+ * store the message in a local buffer to be processed later.
+ * 2. executeMONCMD():
+ * After the ethernet packet has been properly dequeued, then
+ * process the remote command appropriately.
+ */
+
+void
+processMONCMD(struct ether_header *ehdr,ushort size)
+{
+ int verbose = 0, doitnow = 0;
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ char *moncmd;
+ uchar *src;
+
+ if (size > sizeof(IPMonCmdHdrBuf))
+ return;
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)(ihdr + 1);
+ moncmd = (char *)(uhdr + 1);
+ memcpy((char *)IPMonCmdHdrBuf,(char *)ehdr,size);
+ IPMonCmdHdr = (struct ether_header *)&IPMonCmdHdrBuf;
+ src = (uchar *)&ihdr->ip_src;
+
+ /* Keep track of who sent the most recent moncmd request:
+ */
+ shell_sprintf(MONCMD_SRCIP_VARNAME,"%d.%d.%d.%d",
+ src[0],src[1],src[2],src[3]);
+ shell_sprintf(MONCMD_SRCPORT_VARNAME,"%d",ecs(uhdr->uh_sport));
+
+ if (!MFLAGS_NOMONCMDPRN()) {
+ printf("MONCMD (from %s): ",getenv(MONCMD_SRCIP_VARNAME));
+ puts(moncmd);
+ verbose = 1;
+ }
+
+ if (strlen(moncmd) >= (sizeof(IPMonCmdLine) - 2)) {
+ printf("MONCMD (from %s): too long\n",getenv(MONCMD_SRCIP_VARNAME));
+ return;
+ }
+
+ /* A leading '.' tells the moncmd server to execute the command now,
+ * not after the pollethernet queue has been emptied...
+ */
+ if (*moncmd == '.') {
+ moncmd++;
+ doitnow = 1;
+ }
+
+ strcpy(IPMonCmdLine+1,moncmd);
+ IPMonCmdLine[0] = '+';
+ IPMonCmdVerbose = verbose;
+
+ if (doitnow)
+ executeMONCMD();
+}
+
+void
+executeMONCMD(void)
+{
+ char *ncnl; /* netcat newline */
+ char *moncmd;
+
+ /* Clear the initial '+' character so that this function is
+ * never executed multiple times because of calls to
+ * polletherdev() during the MONCMD transaction.
+ */
+ IPMonCmdLine[0] = 0;
+
+ /* If the first character of the incoming command is an '@', then
+ * the response is not sent back to the client...
+ */
+ moncmd = IPMonCmdLine + 1;
+ if (*moncmd == '@') {
+ IPMonCmdActive = 0;
+ moncmd++;
+ }
+ else
+ IPMonCmdActive = 1;
+
+ /* Added to support netcat...
+ */
+ ncnl = strchr(moncmd,0x0a);
+ if (ncnl)
+ *ncnl = 0;
+
+ docommand(moncmd,IPMonCmdVerbose);
+
+ if (ncnl)
+ writeprompt();
+
+ if (IPMonCmdActive) {
+ SendIPMonChar(0,1);
+ IPMonCmdActive = 0;
+ }
+
+ stkchk("Post-sendIPmonchar");
+ if (!ncnl)
+ writeprompt();
+
+ IPMonCmdLine[0] = 0;
+}
+
+int
+SendIPMonChar(uchar c, int done)
+{
+ static int idx;
+ static char linebuf[128];
+ int len, hdrlen;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct Udphdr *tu, *ru;
+
+ if (!IPMonCmdActive)
+ return(0);
+
+ /* Check for overflow and if detected, reset the buffer pointer...
+ */
+ if (idx >= sizeof(linebuf))
+ idx = 0;
+
+ linebuf[idx++] = c;
+
+ if ((idx < sizeof(linebuf)) && (!done) && (c != '\n'))
+ return(0);
+
+ /* Once inside the meat of this function, clear the IPMonCmdActive flag
+ * to avoid recursion if an error message is to be printed by some
+ * called by this function...
+ */
+ IPMonCmdActive = 0;
+
+ hdrlen = sizeof(struct ip) + sizeof(struct Udphdr);
+ len = idx + hdrlen ;
+
+ te = EtherCopy(IPMonCmdHdr);
+
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (IPMonCmdHdr + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ecs(len);
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + idx));
+ memcpy((char *)(tu+1),linebuf,idx);
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ sendBuffer(MONRESPSIZE);
+ idx = 0;
+ IPMonCmdActive = 1;
+ return(1);
+}
+#endif
+
+#if INCLUDE_ETHERVERBOSE
+/*
+ * printPkt(ehdr,len)
+ */
+void
+printPkt(struct ether_header *ehdr, int len, int direction)
+{
+ struct arphdr *arpp;
+ char *dir;
+
+ /* Filter based on verbosity level... */
+ switch(direction) {
+ case ETHER_INCOMING:
+ if (!(EtherVerbose & SHOW_INCOMING))
+ return;
+ dir = "INCOMING";
+ break;
+ case ETHER_OUTGOING:
+ if (!(EtherVerbose & SHOW_OUTGOING))
+ return;
+ dir = "OUTGOING";
+ break;
+ default:
+ printf("printPkt() direction error\n");
+ dir = "???";
+ break;
+ }
+
+ /* If direction is incoming and SHOW_BROADCAST is not set, then */
+ /* return here if the destination host is broadcast. */
+ if ((direction == ETHER_INCOMING) &&
+ (!(EtherVerbose & SHOW_BROADCAST)) &&
+ (!memcmp((char *)ehdr->ether_dhost.ether_addr_octet,(char *)BroadcastAddr,6)))
+ return;
+
+ printf("\n%s PACKET (%d bytes):\n",dir,len);
+ if (EtherVerbose & SHOW_HEX)
+ printMem((uchar *)ehdr,len,EtherVerbose & SHOW_ASCII);
+ printf(" Destination Host = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ehdr->ether_dhost.ether_addr_octet[0],
+ ehdr->ether_dhost.ether_addr_octet[1],
+ ehdr->ether_dhost.ether_addr_octet[2],
+ ehdr->ether_dhost.ether_addr_octet[3],
+ ehdr->ether_dhost.ether_addr_octet[4],
+ ehdr->ether_dhost.ether_addr_octet[5]);
+
+ printf(" Source Host = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ehdr->ether_shost.ether_addr_octet[0],
+ ehdr->ether_shost.ether_addr_octet[1],
+ ehdr->ether_shost.ether_addr_octet[2],
+ ehdr->ether_shost.ether_addr_octet[3],
+ ehdr->ether_shost.ether_addr_octet[4],
+ ehdr->ether_shost.ether_addr_octet[5]);
+
+
+ switch (ehdr->ether_type) {
+ case ecs(ETHERTYPE_IP):
+ printIp((struct ip *)(ehdr+1));
+ break;
+ case ecs(ETHERTYPE_PUP):
+ printf(" Type = PUP\n");
+ break;
+ case ecs(ETHERTYPE_ARP):
+ arpp = (struct arphdr *)(ehdr+1);
+ printf(" Type = ARP %s from IP %d.%d.%d.%d to %d.%d.%d.%d)\n",
+ arpp->operation == ecs(ARP_RESPONSE) ? "RESPONSE" : "REQUEST",
+ arpp->senderia[0],arpp->senderia[1],
+ arpp->senderia[2],arpp->senderia[3],
+ arpp->targetia[0],arpp->targetia[1],
+ arpp->targetia[2],arpp->targetia[3]);
+ break;
+ case ecs(ETHERTYPE_REVARP):
+ printf(" Type = REVARP\n");
+ break;
+ default:
+ printf(" Type = 0x%04x ???\n", ehdr->ether_type);
+ break;
+ }
+}
+
+void
+AppPrintPkt(char *buf, int size, int incoming)
+{
+ int overbose, mode;
+
+ overbose = EtherVerbose;
+ if (incoming) {
+ EtherVerbose = SHOW_ALL & ~SHOW_OUTGOING;
+ mode = ETHER_INCOMING;
+ }
+ else {
+ EtherVerbose = SHOW_ALL & ~SHOW_INCOMING;
+ mode = ETHER_OUTGOING;
+ }
+ printPkt((struct ether_header *)buf,size,mode);
+ EtherVerbose = overbose;
+}
+
+/*
+ * printIp(p)
+ */
+int
+printIp(struct ip *ihdr)
+{
+ ushort ipoff;
+ struct ip *icpy;
+ int i, ipsize;
+ char *fragmented;
+ char buf[16], buf1[16], *payload;
+ ulong tmp[sizeof(struct ip)/2];
+
+ ipsize = ((ihdr->ip_vhl & 0x0f) << 2);
+
+ /* Copy data to aligned memory space so printf doesn't crash. */
+ memcpy((char *)tmp,(char *)ihdr,sizeof(struct ip));
+ icpy = (struct ip *)tmp;
+ printf(" IP: vhl/tos len id offset ttl/proto csum\n");
+ printf(" x%02x%02x x%04x x%04x x%04x x%02x%02x x%04x\n",
+ icpy->ip_vhl,icpy->ip_tos, ecs(icpy->ip_len),
+ ecs(icpy->ip_id), ecs(icpy->ip_off),
+ icpy->ip_ttl, icpy->ip_p, ecs(icpy->ip_sum));
+
+ printf(" src/dest: %s / %s\n",
+ IpToString(icpy->ip_src.s_addr,buf),
+ IpToString(icpy->ip_dst.s_addr,buf1));
+
+ /* Check for options...
+ */
+ if (ipsize > sizeof(struct ip)) {
+ printf(" IP Options: x");
+ for(i=sizeof(struct ip);i<ipsize;i++)
+ printf("%02x",((char *)ihdr)[i]);
+ printf("\n");
+ }
+
+ payload = (char *)ihdr;
+ payload += ipsize;
+ ipoff = ecs(icpy->ip_off);
+
+ if (ipoff & 0x3fff) {
+ if (ipoff == IP_MOREFRAGS)
+ fragmented = " (first fragment)";
+ else if ((ipoff & IP_MOREFRAGS) == 0)
+ fragmented = " (last fragment)";
+ else
+ fragmented = " (fragment)";
+ }
+ else
+ fragmented = "";
+
+ /* Only print the header info if this is not a fragment or if it
+ * is the first fragment...
+ */
+ if ((ipoff == 0) || (ipoff == IP_MOREFRAGS) || (ipoff == IP_DONTFRAG)) {
+ if (icpy->ip_p == IP_UDP) {
+ printUdp((struct Udphdr *)payload,fragmented);
+ return(0);
+ }
+ else if (icpy->ip_p == IP_IGMP) {
+ printIgmp((struct Igmphdr *)payload,fragmented);
+ return(0);
+ }
+ }
+
+ for(i=0;protocols[i].pname;i++) {
+ if (icpy->ip_p == protocols[i].pnum) {
+ printf(" Protocol: %s%s\n",protocols[i].pname,fragmented);
+ return(0);
+ }
+ }
+ printf(" <%02x>: unknown IP protocol%s\n", icpy->ip_p,fragmented);
+ return (1);
+}
+
+/*
+ * printUdp(p)
+ */
+int
+printUdp(struct Udphdr *p,char *fragmented)
+{
+ ushort dport, sport;
+
+ dport = ecs(p->uh_dport);
+ sport = ecs(p->uh_sport);
+
+#if INCLUDE_DHCPBOOT
+ if ((dport == DhcpServerPort) || (dport == DhcpClientPort)) {
+ printDhcp(p);
+ return(0);
+ }
+#endif
+ printf(" UDP: sport dport ulen sum%s\n",fragmented);
+ printf(" %4d %4d %4d %4d\n",
+ sport, dport, ecs(p->uh_ulen),ecs(p->uh_sum));
+ return(0);
+}
+
+/*
+ * printIgmp(p)
+ */
+int
+printIgmp(struct Igmphdr *p,char *fragmented)
+{
+ uchar buf[16];
+
+ printf(" IGMP: type mrt csum group%s\n",fragmented);
+ printf(" x%02x x%02x x%04x %s\n",
+ p->type, p->mrt, p->csum, IpToString(p->group,(char *)buf));
+ return(0);
+}
+#endif
+
+/* IpToString():
+ * Incoming ascii pointer is assumed to be pointing to at least 16
+ * characters of available space. Conversion from long to ascii is done
+ * and string is terminated with NULL. The ascii pointer is returned.
+ */
+char *
+IpToString(ulong ipadd,char *ascii)
+{
+ uchar *cp;
+
+ cp = (uchar *)&ipadd;
+ sprintf(ascii,"%d.%d.%d.%d",
+ (int)cp[0],(int)cp[1],(int)cp[2],(int)cp[3]);
+ return(ascii);
+}
+
+char *
+EtherToString(uchar *etheradd,char *ascii)
+{
+ sprintf(ascii,"%02x:%02x:%02x:%02x:%02x:%02x",(int)etheradd[0],
+ (int)etheradd[1],(int)etheradd[2],(int)etheradd[3],
+ (int)etheradd[4],(int)etheradd[5]);
+ return(ascii);
+}
+
+/* ipChksum():
+ * Compute the checksum of the incoming IP header. The size of
+ * the header is variable because of the possibility of there
+ * being options; hence, the size of the header is taken from
+ * the ip_vhl field instead of assuming sizeof(struct ip).
+ * The incoming pointer to an IP header is directly populated with
+ * the result.
+ */
+void
+ipChksum(struct ip *ihdr)
+{
+ register int i, stot;
+ register ushort *sp;
+ register long csum;
+
+ csum = 0;
+ ihdr->ip_sum = 0;
+ stot = (((ihdr->ip_vhl & 0x0f) << 2) / (int)sizeof(ushort));
+ sp = (ushort *) ihdr;
+ for (i=0;i<stot;i++,sp++) {
+ csum += *sp;
+ if (csum & 0x80000000)
+ csum = (csum & 0xffff) + (csum >> 16);
+ }
+ while(csum >> 16)
+ csum = (csum & 0xffff) + (csum >> 16);
+ ihdr->ip_sum = ~csum;
+}
+
+/* udpChksum():
+ * Compute the checksum of the UDP packet.
+ * The incoming pointer is to an ip header, the udp header after that ip
+ * header is directly populated with the result.
+ * Got part of this code out of Steven's TCP/IP Illustrated Volume 2.
+ */
+void
+udpChksum(struct ip *ihdr)
+{
+ register int i;
+ register ushort *datap;
+ register long sum;
+ int len;
+ struct Udphdr *uhdr;
+ struct UdpPseudohdr pseudohdr;
+
+ uhdr = (struct Udphdr *)(ihdr+1);
+ uhdr->uh_sum = 0;
+
+ /* Note that optionally, the checksum can be forced to zero here,
+ * so a return could replace the remaining code.
+ * That would be kinda dangerous, but it is an option according to
+ * the spec.
+ */
+
+ /* Start with the checksum of the pseudo header:
+ * Note that we have to use memcpy because we don't know if the incoming
+ * stream is aligned properly.
+ */
+ memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4);
+ memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4);
+ pseudohdr.zero = 0;
+ pseudohdr.proto = ihdr->ip_p;
+ pseudohdr.ulen = uhdr->uh_ulen;
+
+ /* Get checksum of pseudo header: */
+ sum = 0;
+ datap = (ushort *) &pseudohdr;
+ for (i=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++) {
+ sum += *datap++;
+ if (sum & 0x80000000)
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ len = ecs(uhdr->uh_ulen);
+ datap = (ushort *) uhdr;
+
+ /* If length is odd, pad with zero and add 1... */
+ if (len & 1) {
+ uchar *ucp;
+ ucp = (uchar *)uhdr;
+ ucp[len] = 0;
+ len++;
+ }
+
+ while(len) {
+ sum += *datap++;
+ if (sum & 0x80000000)
+ sum = (sum & 0xffff) + (sum >> 16);
+ len -= 2;
+ }
+
+ while(sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ uhdr->uh_sum = ~sum;
+}
+
+struct ether_header *
+EtherCopy(struct ether_header *re)
+{
+ struct ether_header *te;
+
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&(te->ether_shost),(char *)BinEnetAddr,6);
+ memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6);
+ te->ether_type = re->ether_type;
+ return(te);
+}
+
+ushort
+ipId(void)
+{
+ return(++UniqueIpId);
+}
+
+
+/* getTuneup():
+ * The DHCP, TFTP and ARP timeout & retry mechanism can be tuned based on
+ * the content of the shell variables DHCPRETRYTUNE, TFTPRETRYTUNE and
+ * ARPRETRYTUNE respectively.
+ * Return 0 if variable is not found, -1 if there is a detected error in
+ * the content of the shell variable; else 1 indicating that the three
+ * parameters have been loaded from the content of the shell variable.
+ */
+int
+getTuneup(char *varname,int *rexmitdelay,int *giveupcount,int *rexmitdelaymax)
+{
+ char *vp, *colon1, *colon2;
+
+ vp = getenv(varname);
+ if (!vp)
+ return(0);
+ colon1 = strchr(vp,':');
+ if (colon1) {
+ colon2 = strchr(colon1+1,':');
+ if (colon2) {
+ *rexmitdelay = (int)strtol(vp,0,0);
+ *giveupcount = (int)strtol(colon1+1,0,0);
+ *rexmitdelaymax = (int)strtol(colon2+1,0,0);
+ return(1);
+ }
+ }
+ printf("Syntax error in %s\n",varname);
+ return(-1);
+}
+
+/* RetransmitDelay():
+ * This function provides a common point for retransmission delay
+ * calculation. It is an implementation "similar" to the recommendation
+ * made in the RFC 2131 (DHCP) section 4.1 paragraph #8...
+ *
+ * The delay before the first retransmission is 4 seconds randomized by
+ * the value of a uniform random number chosen from the range -1 to +2.
+ * The delay before the next retransmission is 8 seconds randomized by
+ * the same number as previous randomization. Each subsequent retransmission
+ * delay is doubled up to a maximum of 66 seconds. Once a delay of 66
+ * seconds is reached, return that value for 6 subsequent delay
+ * requests, then return RETRANSMISSION_TIMEOUT (-1) indicating that the
+ * requestor should give up.
+ *
+ * The value of randomdelta will be 2, 1, 0 or -1 depending on the target's
+ * IP address.
+ *
+ * The return values will be...
+ * 4+randomdelta, 8+randomdelta, 16+randomdelta, etc... up to 64+randomdelta.
+ * Then after returning 64+randomdelta 6 times, return RETRANSMISSION_TIMEOUT.
+ *
+ * NOTE: if DELAY_RETURN is the opcode, then RETRANSMISSION_TIMEOUT is
+ * never returned, once the max is reached, it is always the value
+ * returned;
+ * if DELAY_OR_TIMEOUT_RETURN is the opcode, then once maxoutcount
+ * reaches 6, RETRANSMISSION_TIMEOUT is returned.
+ *
+ * NOTE1: this function supports the ability to modify the above-discussed
+ * parameters. Start with DELAY_INIT_DHCP to set up the parameters
+ * discussed above; start with DELAY_INIT_XXXX for others.
+ */
+int
+RetransmitDelay(int opcode)
+{
+ static int randomdelta; /* Used to slightly randomize the delay.
+ * Taken from the 2 least-significant-bits
+ * of the IP address (range = -1 to 2).
+ */
+ static int rexmitdelay; /* Doubled each time DELAY_INCREMENT
+ * is called until it is greater than the
+ * value stored in rexmitdelaymax.
+ */
+ static int rexmitdelaymax; /* See rexmitdelay. */
+ static int maxoutcount; /* Number of times the returned delay has
+ * reached its max.
+ */
+ static int giveupcount; /* Once maxoutcount reaches this value, we
+ * give up and return TIMEOUT.
+ */
+ int rexmitstate;
+
+ rexmitstate = RETRANSMISSION_ACTIVE;
+ switch(opcode) {
+ case DELAY_INIT_DHCP:
+ if (getTuneup("DHCPRETRYTUNE",&rexmitdelay,
+ &giveupcount,&rexmitdelaymax) <= 0) {
+ rexmitdelay = 4;
+ giveupcount = 6;
+ rexmitdelaymax = 64;
+ }
+ maxoutcount = 0;
+ randomdelta = (int)(BinIpAddr[3] & 3) - 1;
+ break;
+ case DELAY_INIT_TFTP:
+ if (getTuneup("TFTPRETRYTUNE",&rexmitdelay,
+ &giveupcount,&rexmitdelaymax) <= 0) {
+ rexmitdelay = 2;
+ giveupcount = 4;
+ rexmitdelaymax = 8;
+ }
+ maxoutcount = 0;
+ randomdelta = (int)(BinIpAddr[3] & 3) - 1;
+ break;
+ case DELAY_INIT_ARP:
+ if (getTuneup("ARPRETRYTUNE",&rexmitdelay,
+ &giveupcount,&rexmitdelaymax) <= 0) {
+ rexmitdelay = 1;
+ giveupcount = 0;
+ rexmitdelaymax = 4;
+ }
+ maxoutcount = 0;
+ randomdelta = 0;
+ break;
+ case DELAY_INCREMENT:
+ if (rexmitdelay < rexmitdelaymax)
+ rexmitdelay <<= 1; /* double it. */
+ else
+ maxoutcount++;
+
+ if (maxoutcount > giveupcount)
+ rexmitstate = RETRANSMISSION_TIMEOUT;
+ break;
+ case DELAY_OR_TIMEOUT_RETURN:
+ if (maxoutcount > giveupcount)
+ rexmitstate = RETRANSMISSION_TIMEOUT;
+ break;
+ case DELAY_RETURN:
+ break;
+ default:
+ printf("\007TimeoutAlgorithm error 0x%x.\n",opcode);
+ rexmitstate = RETRANSMISSION_TIMEOUT;
+ break;
+ }
+ if (rexmitstate == RETRANSMISSION_TIMEOUT)
+ return(RETRANSMISSION_TIMEOUT);
+ else
+ return(rexmitdelay+randomdelta);
+}
+
+/* monSendEnetPkt() & monRecvEnetPkt():
+ * These two functions allow the monitor to provide a primitive
+ * connect to the ethernet interface for an application (using
+ * mon_sendenetpkt() and mon_recvenetpkt()).
+ *
+ * Note: These are obviously not very sophisticated; however, they
+ * provide an immediate mechanism for LWIP to access the raw driver.
+ * without the application even being aware of the type of ethernet
+ * device.
+ */
+int
+monSendEnetPkt(char *pkt, int pktlen)
+{
+ /* If pkt is zero and pktlen is either 0 or -1, we use this as a
+ * mechanism that changes uMon's ethernet polling state. This is
+ * necessary so that an application can use the monitor's API along
+ * with the monitor's hook to ethernet, but without having other
+ * hooks in uMon do any pollethernet() calls.
+ */
+ if (pkt == 0) {
+ if (pktlen == 0) {
+ EtherPollingOff = 1;
+ return(0);
+ }
+ if (pktlen == -1) {
+ EtherPollingOff = 0;
+ return(0);
+ }
+ }
+
+ /* Copy the incoming packet into a packet that has been allocated
+ * by the monitor's packet allocator for this ethernet device:
+ */
+ memcpy((char *)getXmitBuffer(),(char *)pkt,pktlen);
+ sendBuffer(pktlen);
+ return(pktlen);
+}
+
+int
+monRecvEnetPkt(char *pkt, int pktlen)
+{
+ int pcnt, len;
+
+ /* Prior to calling polletherdev(), this function sets up the globals
+ * AppPktPtr and AppPktLen so that if a packet is recived, and
+ * polletherdev() calls processPACKET(), the data will simply be
+ * copied to the requested buffer space instead of being processed
+ * by the monitor's packet handler (see the top of processPACKET()
+ * for the use of AppPktPtr & AppPktLen).
+ *
+ * NOTE: this assumes that the target-specific function polletherdev()
+ * will only process one packet per call. If it can process more than
+ * one per call, then packets will be lost here.
+ */
+ AppPktPtr = pkt;
+ AppPktLen = pktlen;
+ pcnt = polletherdev();
+ if (pcnt == 0) {
+ len = 0;
+ }
+ else {
+ if (pcnt > 1)
+ len = -AppPktLen;
+ else
+ len = AppPktLen;
+ }
+ AppPktPtr = 0;
+ return(len);
+}
+
+#ifndef USE_ALT_STOREMAC
+
+/* storeMac():
+ * This function can be called in system startup (after flash drivers
+ * are initialized) to give the user the opportunity to program a
+ * MAC address into the "etheraddr" block of flash in monitor space.
+ * This is only done if that space is erased (0xff), so only on the
+ * first pass will it be called.
+ * It is useful for monitors that want to exist without a monrc file,
+ * but should still have a MAC address.
+ * As of uMon_1.0, this function can also be called by the ether command.
+ */
+void
+storeMac(int verbose)
+{
+#if INCLUDE_FLASH
+ int snum, yes;
+ char macascii[24], prefill[24], buf[6];
+ uchar *realetheraddr;
+#ifdef TO_FLASH_ADDR
+ /* The address the program is linked to is not necessarily the
+ * physical address where flash operations can be performed on.
+ * A typical use could be that the program is linked to run in
+ * a cacheable region but writing to the flash can only be done
+ * in an uncached region.
+ * "config.h" is a good place to define the TO_FLASH_ADDR macro.
+ */
+ realetheraddr = (uchar *)TO_FLASH_ADDR(etheraddr);
+#else
+ realetheraddr = etheraddr;
+#endif
+
+ if (realetheraddr[0] != 0xff) {
+ if (verbose)
+ printf("MAC store abort: etheraddr[] contains data\n");
+ return;
+ }
+
+ /* If etheraddr[] is writeable (RAM), then assume that this
+ * function is being called as part of a RAM based temporary
+ * monitor; hence, no need to do it...
+ */
+ realetheraddr[0] = 0;
+ monDelay(100);
+ if (realetheraddr[0] == 0) {
+ realetheraddr[0] = 0xff;
+ if (verbose)
+ printf("MAC store abort: etheraddr[] in RAM\n");
+ return;
+ }
+
+ /* Use whatever is in config.h as the default MAC address,
+ * then allow the user to override it with getline_p()...
+ */
+ strcpy(prefill,DEFAULT_ETHERADD);
+
+#if INCLUDE_ETHERVERBOSE
+ printf("\nMAC address must be configured.\n");
+ printf("The system's MAC address is a 6-digit, colon-delimited string\n");
+ printf("(for example: 12:34:56:78:9a:bc). It must be unique for all\n");
+ printf("ethernet controllers present on a given subnet. MAC addresses\n");
+ printf("are often allocated by a product vendor to prevent duplication,\n");
+ printf("and are frequently documented on decals or other materials\n");
+ printf("provided with the product. The following prompt allows you\n");
+ printf("to specify the MAC address for this device.\n");
+ if (strlen(prefill) != 0)
+ printf("Use backspace if the printed default needs modification...\n");
+ printf("\n");
+#endif
+
+ do {
+ printf("Enter MAC address (xx:xx:xx:xx:xx:xx):\n");
+ if (getline_p(macascii,sizeof(macascii),0,prefill) == 0)
+ return;
+ } while (EtherToBin((char *)macascii,(uchar *)buf) == -1);
+
+ printf("Configuring '%s' as MAC address, ok?",macascii);
+ yes = askuser(" (y or n)");
+
+ putchar('\n');
+ if (!yes)
+ return;
+
+ if (addrtosector((uchar *)realetheraddr,&snum,0,0) < 0)
+ return;
+
+ sprintf(buf,"%d",snum);
+ sectorProtect(buf,0);
+ AppFlashWrite((uchar *)realetheraddr,(uchar *)macascii,strlen(macascii)+1);
+ sectorProtect(buf,1);
+
+ printf("MAC address burned in at 0x%lx\n",(long)realetheraddr);
+#else
+ printf("Error: MAC storage requires flash driver\n");
+#endif
+}
+#endif
+
+#endif /* INCLUDE_ETHERNET */
+
+/* EtherToBin():
+ * Convert ascii MAC address string to binary. Note that this is outside
+ * the #if INCLUDE_ETHERNET because it is used by password.c. This correctly
+ * implies that if there is no ethernet interface, then we need a different
+ * solution for the password backdoor!.
+ */
+int
+EtherToBin(char *ascii,uchar *binary)
+{
+ int i, digit;
+ char *acpy, *acpy1;
+
+ acpy = ascii;
+ for(i=0;i<6;i++) {
+ digit = (int)strtol(acpy,&acpy1,16);
+ if (((i != 5) && (*acpy1++ != ':')) ||
+ ((i == 5) && (*acpy1 != 0)) ||
+ ((acpy1 - acpy) < 2) ||
+ (digit < 0) || (digit > 255)) {
+ printf("Misformed ethernet addr at: 0x%lx\n",(long)ascii);
+ return(-1);
+ }
+ acpy = acpy1;
+ binary[i] = (uchar)digit;
+ }
+ return(0);
+}
+
+int
+IpToBin(char *ascii,uchar *binary)
+{
+ int i, digit;
+ char *acpy;
+
+ acpy = ascii;
+ for(i=0;i<4;i++) {
+ digit = (int)strtol(acpy,&acpy,10);
+ if (((i != 3) && (*acpy++ != '.')) ||
+ ((i == 3) && (*acpy != 0)) ||
+ (digit < 0) || (digit > 255)) {
+ printf("Misformed IP addr at 0x%lx\n",(long)ascii);
+ return(-1);
+ }
+ binary[i] = (uchar)digit;
+ }
+ return(0);
+}
+
diff --git a/main/common/fbi.c b/main/common/fbi.c
new file mode 100755
index 0000000..583fb47
--- /dev/null
+++ b/main/common/fbi.c
@@ -0,0 +1,1728 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * fbi.c:
+ *
+ * Frame Buffer Interface...
+ * This file started out as a simple means to transfer a .bmp formatted
+ * file onto a framebuffer. It has since expanded into what I think is a
+ * pretty complete set of frame-buffer utilities to run in both pixel mode
+ * (for images) and console mode (for text).
+ * As of this writing, pixel mode allows the user to display raw frame-buffer
+ * images or 24-bit RGB .bmp formatted images. In console mode, the font
+ * rendering supports variable size fonts (using one font file) and console
+ * scrolling using a dual-buffer algorithm.
+ *
+ *****
+ *
+ * Configuration:
+ * If you're hardware has a frame buffer interface (typically, this will be
+ * an LCD, but doesn't have to be), then do the following:
+ *
+ * - provide the basic initialization code for the framebuffer
+ * device: void fbdev_init(void), which will be called by uMon
+ * startup code automatically.
+ *
+ * - establish these three macros as per your device's specifications...
+ * PIXELS_PER_COL (height of framebuffer device)
+ * PIXELS_PER_ROW (height of framebuffer device)
+ * FRAME_BUFFER_BASE_ADDR (starting point of the frame-buffer memory)
+ *
+ * - establish one (and only one) of the following to be 1, with all
+ * others being 0:
+ * PIXFMT_IS_RGB565
+ * PIXFMT_IS_RGB555
+ *
+ * (as of this writing only 16-bit color depth RGB565/RGB555 has been
+ * tested).
+ *
+ * - set INCLUDE_FBI to 1 in the config.h file;
+ * - add font.c and fbi.c to the common files list in your makefile;
+ * - to support more efficient consolemode screen scrolling, optionally
+ * set FBDEV_SETSTART to the name of a function in the driver that
+ * when called, will re-establish the base address of the frame
+ * buffer memory using the 'addr' value provided.
+ * - the console mode feature includes a blinking cursor. To build without
+ * the cursor, add...
+ * #define FBI_NO_CURSOR
+ * to your config.h file.
+ *
+ *****
+ *
+ * Startup:
+ * At startup, the target can come up in console mode or pixel mode
+ * based on the presence of a splash image. The function fbi_splash()
+ * is called and it will look for a few different filenames (see function
+ * below). If a splash image is found, it is dumped to the frame buffer
+ * and the system will start up in pixel mode. If a splash image is not
+ * found, then the system will come up in console mode, meaning that all
+ * characters typed at the serial port will be printed out the frame buffer
+ * device.
+ *
+ *****
+ *
+ * Acknowledgements:
+ * I got the majority of my information regarding the format of the BMP
+ * file from Wikipedia (http://en.wikipedia.org/wiki/BMP_file_format).
+ * I got the basic idea for the scrolling algorithm out of code from
+ * one of Cogent's LCD drivers. Also, the file font.c has one font that
+ * I tediously created by hand (kinda ugly), and one that I got from Cogent.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#if INCLUDE_FBI
+#include "cpuio.h"
+#include "genlib.h"
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "warmstart.h"
+#include "font.h"
+#include "fbi.h"
+#include "timer.h"
+
+/* FBI_DEBUG:
+ * Primarily used for debugging the fb_scroll() algorithm...
+ */
+//#define FBI_DEBUG
+
+#ifdef FBDEV_SETSTART
+extern void FBDEV_SETSTART(long addr);
+#endif
+
+/* PIXELS_PER_ROW, PIXELS_PER_COL and LCD_BUF_ADD are assumed to be
+ * defined in cpuio.h...
+ */
+#define SCREEN_WIDTH PIXELS_PER_ROW
+#define SCREEN_HEIGHT PIXELS_PER_COL
+#define FB_BASE ((unsigned long)FRAME_BUFFER_BASE_ADDR)
+
+#define RED(val) (char)((val & 0x00ff0000) >> 16)
+#define GREEN(val) (char)((val & 0x0000ff00) >> 8)
+#define BLUE(val) (char)((val & 0x000000ff))
+
+#define FILLTYPE_BOX 1
+#define FILLTYPE_COLOR 2
+
+#define BOX_XSIZE 10
+#define BOX_YSIZE 10
+
+#define DEFAULT_FG_COLOR 0x00f0f0f0
+#define DEFAULT_BG_COLOR 0x00101010
+
+#if PIXFMT_IS_RGB565
+#define fbtype unsigned short
+#define FB_GRAY 0x632c
+#define FB_WHITE 0xffff
+#define FB_BLACK 0x0821
+#elif PIXFMT_IS_RGB555
+# warning: pixel format RGB555 not yet tested
+#define fbtype unsigned short
+#define FB_GRAY 0x318c
+#define FB_WHITE 0xffff
+#define FB_BLACK 0x0421
+#else
+# error: unknown pixel format
+#endif
+
+#define FB_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(fbtype))
+#define FB_END (FB_BASE + FB_SIZE)
+
+struct bmpstuff {
+ unsigned long size;
+ unsigned long offset;
+ unsigned long hdrsz;
+ unsigned long width;
+ unsigned long height;
+ unsigned short planes;
+ unsigned short bpp;
+ unsigned long cprs;
+ unsigned long rawsize;
+ unsigned long hrez;
+ unsigned long vrez;
+ unsigned long palettesiz;
+ unsigned long impcol;
+};
+
+/* Whenever color is represented where it will be stored in the frame buffer
+ * but also queriable by the user, we store the RGB value and the FBTYPE
+ * value because once converted to the FBTYPE, it doesn't necessarily
+ * convert directly back to the original RGB value it was derived from.
+ */
+struct fbicolor {
+ fbtype fbval;
+ long rgbval;
+};
+
+void fbi_cursor_clear(void);
+void fbi_consolemode_enable(int enable, int fbinit);
+
+static struct bmpstuff bmpinfo;
+static struct fbicolor font_fgcolor, font_bgcolor;
+static int font_totalcharheight, font_totalcharwidth, font_linemodulo;
+static int font_rowsperscreen, font_colsperscreen, font_scrolltot;
+static int font_style, font_xscale, font_yscale, font_xpos, font_ypos;
+static fbtype *fbi_cursorpos;
+static char fbi_linewrap, fbi_cursorstate;
+static char fbi_consolemode_enabled, font_initialized, font_is_opaque;
+
+/* ecl() & ecs:
+ * The .bmp file is inherently Windows/Intel-ish. As a result, all integers
+ * in that file are little endian. These functions automatically convert
+ * as needed...
+ *
+ * If this host is little endian, just return the value; else do the
+ * endian swap and return.
+ */
+unsigned long
+ecl(unsigned long val)
+{
+ short tval = 1;
+ char *tp;
+
+ tp = (char *)&tval;
+ if (*tp == 1) {
+ return(val);
+ }
+ else {
+ return((( val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) |
+ ((val & 0xff000000) >> 24));
+ }
+}
+
+unsigned short
+ecs(unsigned short val)
+{
+ short tval = 1;
+ char *tp;
+
+ tp = (char *)&tval;
+ if (*tp == 1) {
+ return(val);
+ }
+ else {
+ return(((val & 0x00ff) << 8) | ((val & 0xff00) >> 8));
+ }
+}
+
+/* rgb_to_fb() / fb_to_rgb():
+ * Convert 24-bit RGB to (or from) whatever the frame buffer type is...
+ */
+
+#if PIXFMT_IS_RGB565
+/* Assume incoming RGB values 8-bits each (24-bit RGB).
+ * Convert that to 16-bit RGB565 format (5-bit red, 6-bit grn, 5-bit blue).
+ */
+fbtype
+rgb_to_fb(long rgb)
+{
+ char red, grn, blue;
+
+ red = RED(rgb);
+ grn = GREEN(rgb);
+ blue = BLUE(rgb);
+
+ return(((short)(red >> 3) << 11) |
+ ((short)(grn >> 2) << 5) | (short)(blue >> 3));
+}
+
+#elif PIXFMT_IS_RGB555
+
+/* Assume incoming RGB values 8-bits each (24-bit RGB).
+ * Convert that to 16-bit RGB555 format (5-bit red, 5-bit grn, 5-bit blue).
+ * (NOT READY YET)
+ */
+fbtype
+rgb_to_fb(long rgb)
+{
+ unsigned long red, green, blue;
+
+ red = ((fbval & 0xf800) >> 11);
+ green = ((fbval & 0x07e0) >> 5);
+ blue = (fbval & 0x001f);
+
+ return(((short)(red >> 3) << 10) |
+ ((short)(grn >> 5) << 5) | (short)(blue >> 3));
+}
+
+#endif
+
+/* fb_memset():
+ * A version of memset that is written to efficiently populate the frame
+ * buffer with a value of type fbtype. The incoming total is assumed to
+ * be in fbtype units.
+ */
+void
+fb_memset(fbtype *dest, fbtype val, int tot)
+{
+ /* If the size of a framebuffer element is half the size of a long,
+ * then we can double up the memory fill by populating one long value
+ * with two framebuffer fill values (one being shifted left 16)...
+ */
+ if (sizeof(fbtype) == sizeof(unsigned long)/2) {
+ unsigned long l_val, *l_fp, *l_end;
+
+ l_val = (unsigned long)val;
+ l_val <<= 16;
+ l_val |= (unsigned long)val;
+ l_fp = (unsigned long *)dest;
+ l_end = (unsigned long *)(dest+tot);
+ while(l_fp < l_end)
+ *l_fp++ = l_val;
+
+ }
+ /* Otherwise, we just do an fbtype-oriented memset...
+ */
+ else {
+ fbtype *end = dest+tot;
+
+ while(dest < end)
+ *dest++ = val;
+ }
+}
+
+void
+fb_memcpy(fbtype *dest, fbtype *src, int tot)
+{
+ /* If the size of a framebuffer element is half the size of a long,
+ * then we can double up the memory fill by populating one long value
+ * with two framebuffer fill values (one being shifted left 16)...
+ */
+ if (sizeof(fbtype) == sizeof(unsigned long)/2) {
+ unsigned long *l_dest, *l_src, *l_end;
+
+ l_dest = (unsigned long *)dest;
+ l_src = (unsigned long *)src;
+ l_end = (unsigned long *)(dest+tot);
+ while(l_dest < l_end)
+ *l_dest++ = *l_src++;
+
+ }
+ /* Otherwise, we just do an fbtype-oriented memcpy...
+ */
+ else {
+ fbtype *end = dest+tot;
+
+ while(dest < end)
+ *dest++ = *src++;
+ }
+}
+
+void
+font_defaults(void)
+{
+ struct font *fontp;
+
+ if (font_initialized)
+ return;
+
+ font_xpos = 0;
+ font_ypos = 0;
+ font_style = 1;
+ font_xscale = 1;
+ font_yscale = 1;
+ font_scrolltot = 0;
+ font_fgcolor.rgbval = DEFAULT_FG_COLOR;
+ font_fgcolor.fbval = rgb_to_fb(font_fgcolor.rgbval);
+ font_bgcolor.rgbval = DEFAULT_BG_COLOR;
+ font_bgcolor.fbval = rgb_to_fb(font_bgcolor.rgbval);
+ font_is_opaque = 1;
+ fbi_linewrap = 0;
+ fbi_cursorstate = 0;
+ fbi_cursorpos = 0;
+
+ fontp = &font_styles[font_style];
+ font_totalcharheight = ((fontp->height + fontp->above + fontp->below) *
+ font_yscale);
+ font_totalcharwidth = ((fontp->width + fontp->between) * font_xscale);
+ font_rowsperscreen = SCREEN_HEIGHT / font_totalcharheight;
+ font_colsperscreen = SCREEN_WIDTH / font_totalcharwidth;
+ font_linemodulo = SCREEN_HEIGHT % font_totalcharheight;
+ font_initialized = 1;
+}
+
+
+/* fb_scroll():
+ * This could be done with a simple memory-to-memory transfer which copies
+ * row 2 to row 1, row 3 to row 2, etc... all the way down the screen.
+ * However, this would be *really* slow, so an alternative solution is
+ * used that takes advantage of the fact that we can adjust which portion
+ * of memory is looked at by the DMA engine connected to the device that is
+ * actually displaying the pixels (typically this will be an LCD).
+ *
+ * Consider the double buffer here, with the start of the second buffer
+ * being adjacent to the end of the first buffer...
+ *
+ * ---------------------------
+ * | -| *
+ * | | *
+ * | | *
+ * | | *
+ * ___| -|___ *
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * ---------------------------
+ *
+ * For the sake of this discussion, assume each buffer deals with five
+ * lines of text. Also, initially the visible portion of the frame
+ * buffer aligns with the top buffer (note the asterisks to the right).
+ * As text is typed, each character is put into both buffers...
+ *
+ * ---------------------------
+ * | text for line 1 -| *
+ * | another line here | *
+ * | another line is here | *
+ * | this is the fourth line | *
+ * ___| and this is line five -|___ *
+ * | text for line 1 |
+ * | another line here |
+ * | another line is here |
+ * | this is the fourth line |
+ * | and this is line five |
+ * ---------------------------
+ *
+ * Up to this point, the viewing window has not changed.
+ * The next line of text is simply placed at the top of both of the
+ * buffers, just like a circular queue...
+ *
+ * ---------------------------
+ * | this is now line #6 |
+ * | another line here -| *
+ * | another line is here | *
+ * | this is the fourth line | *
+ * ___| and this is line five |___ *
+ * | this is now line #6 -| *
+ * | another line here |
+ * | another line is here |
+ * | this is the fourth line |
+ * | and this is line five |
+ * ---------------------------
+ *
+ * The only added trick now is that the viewing window is shifted down
+ * one row; thus, giving the appearance of a single line scroll, but without
+ * the memcpy overhead.
+ * Then, continuing with this, when the viewing window gets to the bottom
+ * of the second buffer as shown below...
+ *
+ * ---------------------------
+ * | this is now line #6 |
+ * | line seven |
+ * | this would be line 8 |
+ * | and nine... |
+ * ___| this is line ten |___
+ * | this is now line #6 -| *
+ * | line seven | *
+ * | this would be line 8 | *
+ * | and nine... | *
+ * | this is line ten -| *
+ * ---------------------------
+ *
+ * the next "scroll" would simply put to one line from the top...
+ *
+ * ---------------------------
+ * | eleventh line now |
+ * | line seven -| *
+ * | this would be line 8 | *
+ * | and nine... | *
+ * ___| this is line ten |___ *
+ * | eleventh line now -| *
+ * | line seven |
+ * | this would be line 8 |
+ * | and nine... |
+ * | this is line ten |
+ * ---------------------------
+ *
+ * One 'gotcha' that I discovered (and fixed) with this algorithm is that
+ * it only works perfectly if the character height of the font divides
+ * evenly into the height of the visible frame. If this is not the case,
+ * then as the lines are scrolling, there will be a larger gap between
+ * one line and the next as each 'N' lines scroll by (where 'N' is the nuber
+ * of lines that can fit on the screen.
+ * To get around this problem, when the font is first established I determine
+ * what the modulo is between the character height and the screen height.
+ * Then for each character-oriented line generated I insert one extra pixel
+ * oriented line until the modulo reaches zero. This simply distributes the
+ * extra space across each of the lines and only one pixel (at most) of
+ * difference is visible.
+ * In short, the font_linemodulo value is the number of character-lines that
+ * need to have one additional pixel added to their height so that the final
+ * character-line is at the very bottom of the screen.
+ */
+
+void
+fb_erase_line(int lno)
+{
+ int linesize, linesize1;
+ fbtype *dest, *end, *dest1;
+#ifdef FBI_DEBUG
+ int erasetype;
+#endif
+
+ linesize = SCREEN_WIDTH * font_totalcharheight;
+
+ if (font_linemodulo == 0) {
+ dest = (fbtype *)(FB_BASE + (lno * linesize * sizeof(fbtype)));
+ end = dest + linesize;
+#ifdef FBI_DEBUG
+ erasetype = 0;
+#endif
+ }
+ else {
+ linesize1 = linesize + SCREEN_WIDTH;
+
+ if (lno < font_linemodulo) {
+ dest = (fbtype *)(FB_BASE + (lno * linesize1 * sizeof(fbtype)));
+ end = dest + linesize1;
+#ifdef FBI_DEBUG
+ erasetype = 1;
+#endif
+ }
+ else if (lno == font_linemodulo) {
+ dest = (fbtype *)(FB_BASE + (lno * linesize1 * sizeof(fbtype)));
+ end = dest + linesize1;
+ end = dest + linesize;
+#ifdef FBI_DEBUG
+ erasetype = 2;
+#endif
+ }
+ else {
+ dest = (fbtype *)(FB_BASE + (font_linemodulo * linesize1 * sizeof(fbtype)));
+ dest += ((lno-font_linemodulo) * linesize);
+ end = dest + linesize;
+#ifdef FBI_DEBUG
+ erasetype = 3;
+#endif
+ }
+ }
+
+ dest1 = dest + FB_SIZE/sizeof(fbtype);
+ fb_memset(dest,font_bgcolor.fbval,end-dest);
+#ifdef FBDEV_SETSTART
+ fb_memset(dest1,font_bgcolor.fbval,end-dest);
+#endif
+
+#ifdef FBI_DEBUG
+ if (!fbi_consolemode_enabled) /* don't print if console is enabled */
+ printf("fb_erase_line_%d(%d)\n",erasetype,lno);
+#endif
+
+}
+
+#ifdef FBDEV_SETSTART
+
+/* fb_scroll()
+ * Called each time a 'newline' character is put to the screen.
+ */
+void
+fb_scroll(void)
+{
+ int adjust, next_ypos;
+ unsigned long fbstart;
+
+ font_scrolltot++;
+
+ if (font_ypos >= (font_rowsperscreen-1))
+ next_ypos = 0;
+ else
+ next_ypos = font_ypos+1;
+
+ if (font_scrolltot >= (font_rowsperscreen*2)) {
+ fb_erase_line(next_ypos);
+
+ fbstart = (FB_BASE +
+ (SCREEN_WIDTH*font_totalcharheight * sizeof(fbtype)));
+
+ if (font_linemodulo)
+ fbstart += SCREEN_WIDTH * sizeof(fbtype);
+
+ FBDEV_SETSTART(fbstart);
+
+#ifdef FBI_DEBUG
+ if (!fbi_consolemode_enabled) { /* don't print if console is enabled */
+ printf("fb_scroll_1: %d %d %d (fbstart=0x%lx)\n",
+ font_ypos,font_scrolltot,font_rowsperscreen,fbstart);
+ }
+#endif
+ font_scrolltot = font_rowsperscreen;
+ }
+ else if (font_scrolltot >= font_rowsperscreen) {
+ int ldiff = font_scrolltot - font_rowsperscreen;
+
+ fb_erase_line(ldiff);
+
+ adjust =
+ (SCREEN_WIDTH * font_totalcharheight * sizeof(fbtype));
+
+ fbstart = (FB_BASE + ((ldiff+1) * adjust));
+
+ if (font_linemodulo) {
+ if (ldiff <= font_linemodulo)
+ fbstart += ldiff * (SCREEN_WIDTH * sizeof(fbtype));
+ else
+ fbstart += font_linemodulo * (SCREEN_WIDTH * sizeof(fbtype));
+ }
+
+ FBDEV_SETSTART(fbstart);
+
+#ifdef FBI_DEBUG
+ if (!fbi_consolemode_enabled) { /* don't print if console is enabled */
+ printf("fb_scroll_2: %d %d %d %d (fbstart=0x%lx)\n",
+ font_ypos,font_scrolltot,font_rowsperscreen,adjust,fbstart);
+ }
+#endif
+ }
+
+ font_ypos = next_ypos;
+}
+
+#else
+
+void
+fb_scroll(void)
+{
+ int i, tot;
+ struct font *fp;
+ fbtype *dest, *src;
+
+ if (font_ypos >= (font_rowsperscreen-1)) {
+ /* Starting at the point in the frame buffer where the second line
+ * starts, copy that to the top of the frame buffer. Effectively
+ * moving every line below the first line up by one.
+ * Then clear the newly created bottom line.
+ *
+ * NOTE: this is the *slow* way. Ideally, the hardware has the ability
+ * to support the fbdev_setstart() functionality so the double-buffer
+ * algorithm (described above) can be used.
+ */
+ fp = &font_styles[font_style];
+ dest = (fbtype *)FB_BASE;
+ src = (fbtype *)FB_BASE + (SCREEN_WIDTH * font_totalcharheight);
+
+ tot = ((FB_END - FB_BASE)/2) - (src - dest);
+
+ for(i=0;i<tot;i++)
+ *dest++ = *src++;
+
+ /* Clear the new bottom line...
+ */
+ while(dest < (fbtype *)FB_END)
+ *dest++ = font_bgcolor.fbval;
+ }
+ else
+ font_ypos++;
+}
+
+#endif
+
+/* fb_putchar():
+ * Using the current font settings and frame buffer position, set the
+ * pixels that correspond to the incoming character 'inchar'.
+ * This function supports the double-buffer line scroll technique discussed
+ * above; hence, the use of fp1 & fp2 below.
+ */
+static void
+fb_putchar(char inchar)
+{
+ struct font *fp;
+ int i, j, k;
+ char *bmppos;
+ unsigned char mask, endmask, fontchar;
+ fbtype *fp1, *fp2, *position, *start, *end;
+
+ if (!font_initialized)
+ font_defaults();
+
+ fp = &font_styles[font_style];
+
+#ifndef FBI_NO_CURSOR
+ fbi_cursor_clear();
+#endif
+
+ if (inchar == '\r') {
+ font_xpos = 0;
+ return;
+ }
+ else if (inchar == '\n') {
+ fb_scroll();
+ return;
+ }
+ else if (inchar == '\b') {
+ if (font_xpos > 0) {
+ font_xpos--;
+ fb_putchar(' ');
+ font_xpos--;
+ }
+ return;
+ }
+
+ /* Chop at end of screen...
+ */
+ if (font_xpos >= font_colsperscreen) {
+ if (fbi_linewrap) {
+ font_xpos = 0;
+ fb_scroll();
+ }
+ else
+ return;
+ }
+
+ position = start = (fbtype *)FB_BASE +
+ (font_ypos * font_totalcharheight * SCREEN_WIDTH) +
+ (font_xpos * font_totalcharwidth);
+
+ if (font_ypos < font_linemodulo) {
+ position += font_ypos*SCREEN_WIDTH;
+ }
+ else {
+ position += font_linemodulo*SCREEN_WIDTH;
+ }
+
+ bmppos = fp->bitmap + ((inchar - 0x20) * fp->height);
+ for(i=0;i<fp->above * font_yscale;i++) {
+ fp1 = (fbtype *)position;
+ fp2 = fp1 + FB_SIZE/2;
+ end = fp1 + (fp->width * font_xscale) + (fp->between * font_xscale);
+ while(fp1 < end) {
+ if (font_is_opaque) {
+ *fp1++ = font_bgcolor.fbval;
+ *fp2++ = font_bgcolor.fbval;
+ }
+ else {
+ fp1++;
+ fp2++;
+ }
+ }
+ position += SCREEN_WIDTH;
+ }
+
+ /* Some fonts will only use the left-most 7 columns of pixels, so
+ * we support that here...
+ */
+ if (fp->width == 7)
+ endmask = 1;
+ else
+ endmask = 0;
+
+ for(i=0;i<fp->height;i++) {
+ fontchar = *bmppos++;
+
+ for(k=0;k<font_yscale;k++) {
+ fp1 = (fbtype *)position;
+ fp2 = fp1 + FB_SIZE/2;
+ for(mask = 0x80; mask != endmask; mask >>= 1) {
+ if (fontchar & mask) {
+ for(j=0;j<font_xscale;j++) {
+ *fp1++ = font_fgcolor.fbval;
+ *fp2++ = font_fgcolor.fbval;
+ }
+ }
+ else if (font_is_opaque) {
+ for(j=0;j<font_xscale;j++) {
+ *fp1++ = font_bgcolor.fbval;
+ *fp2++ = font_bgcolor.fbval;
+ }
+ }
+ else {
+ for(j=0;j<font_xscale;j++) {
+ fp1++;
+ fp2++;
+ }
+ }
+ }
+
+ end = fp1 + (fp->between * font_xscale);
+ while(fp1 < end) {
+ if (font_is_opaque) {
+ *fp1++ = font_bgcolor.fbval;
+ *fp2++ = font_bgcolor.fbval;
+ }
+ else {
+ fp1++;
+ fp2++;
+ }
+ }
+ position += SCREEN_WIDTH;
+ }
+ }
+
+ for(i=0;i<fp->below*font_yscale;i++) {
+ fp1 = position;
+ fp2 = fp1 + FB_SIZE/2;
+ end = fp1 + (fp->width * font_xscale) + (fp->between * font_xscale);
+ while(fp1 < end) {
+ if (font_is_opaque) {
+ *fp1++ = font_bgcolor.fbval;
+ *fp2++ = font_bgcolor.fbval;
+ }
+ else {
+ fp1++;
+ fp2++;
+ }
+ }
+ position += SCREEN_WIDTH;
+ }
+
+ font_xpos++;
+}
+
+static int
+fbi_puts(char *str)
+{
+ int tot, slash;
+ char nextchar;
+
+ tot = slash = 0;
+ while(*str) {
+ if (slash) {
+ switch(*str) {
+ case 'n':
+ nextchar = '\n';
+ break;
+ case 'r':
+ nextchar = '\r';
+ break;
+ case 'b':
+ nextchar = '\b';
+ break;
+ default:
+ tot++;
+ fb_putchar('\\');
+ nextchar = *str;
+ break;
+ }
+ str++;
+ }
+ else {
+ if (*str == '\\') {
+ slash = 1;
+ str++;
+ continue;
+ }
+ nextchar = *str++;
+ }
+ tot++;
+ fb_putchar(nextchar);
+ slash = 0;
+ }
+
+ return(tot);
+}
+
+/* get_bmphdr_long():
+ * Given an offset, copy 4 bytes of data to a temporary long
+ * value, then endian-swap if necessary.
+ */
+unsigned long
+get_bmphdr_long(char *offset, char *msg, int verbose)
+{
+ unsigned long tmp1, tmp2;
+
+ memcpy((char *)&tmp1,(char *)offset,4);
+ tmp2 = ecl(tmp1);
+
+ if (verbose)
+ printf(" %-20s: %ld\n",msg,tmp2);
+
+ return(tmp2);
+}
+
+/* get_bmphdr_short():
+ * Given an offset, copy 2 bytes of data to a temporary short
+ * value, then endian-swap if necessary.
+ */
+unsigned short
+get_bmphdr_short(char *offset, char *msg, int verbose)
+{
+ unsigned short tmp1, tmp2;
+
+ memcpy((char *)&tmp1,(char *)offset,2);
+ tmp2 = ecs(tmp1);
+
+ if (verbose)
+ printf(" %-20s: %d\n",msg,tmp2);
+
+ return(tmp2);
+}
+
+/* get_bmpinfo():
+ * Using the incoming base address as the pointer to the incoming data,
+ * return 1 if the data is not BMP formatted
+ * return 0 if the data is BMP formatted
+ * return -1 if the data is BMP formatted but something is not compatible
+ * with this tool
+ */
+int
+get_bmpinfo(char *base, int verbose)
+{
+ if ((base[0] != 'B') || (base[1] != 'M')) {
+ return(1);
+ }
+
+ /* Retrieve the .bmp file's header info...
+ */
+ bmpinfo.size = get_bmphdr_long(base+2,"Size",verbose);
+ bmpinfo.offset = get_bmphdr_long(base+10,"Offset",verbose);
+ bmpinfo.hdrsz = get_bmphdr_long(base+14,"Hdrsize",verbose);
+ bmpinfo.width = get_bmphdr_long(base+18,"Width",verbose);
+ bmpinfo.height = get_bmphdr_long(base+22,"Height",verbose);
+ bmpinfo.planes = get_bmphdr_short(base+26,"Planes",verbose);
+ bmpinfo.bpp = get_bmphdr_short(base+28,"Bpp",verbose);
+ bmpinfo.cprs = get_bmphdr_long(base+30,"Cprs",verbose);
+ bmpinfo.rawsize = get_bmphdr_long(base+34,"RawSize",verbose);
+ bmpinfo.hrez = get_bmphdr_long(base+38,"Hrez",verbose);
+ bmpinfo.vrez = get_bmphdr_long(base+42,"Vrez",verbose);
+ bmpinfo.palettesiz = get_bmphdr_long(base+46,"Palettesiz",verbose);
+ bmpinfo.impcol = get_bmphdr_long(base+50,"Important colors",verbose);
+
+ if (bmpinfo.cprs != 0) {
+ printf("Can't deal with non-zero compression method.\n");
+ return(-1);
+ }
+ if (bmpinfo.bpp != 24) {
+ printf("BMP file pixel format is not 24 bits per pixel.\n");
+ return(-1);
+ }
+ return(0);
+}
+
+void
+fbi_consolemode_enable(int enable, int fbinit)
+{
+ font_scrolltot = 0;
+ font_ypos = font_xpos = 0;
+
+ if (enable) {
+ if (!font_initialized)
+ font_defaults();
+ }
+
+ if (fbinit) {
+ /* Regardless of whether we are enabling or disableing console
+ * mode we need to init the frame buffer. We fill it with with the
+ * same color that is used by the font's background.
+ *
+ * If FBDEV_SETSTART is defined, then we assume that we're
+ * using the double-buffer technique (described above) for
+ * scrolling; hence, we need to initialize twice the space...
+ */
+#ifdef FBDEV_SETSTART
+ fb_memset((fbtype *)FB_BASE,font_bgcolor.fbval,
+ ((FB_END-FB_BASE)/sizeof(fbtype))*2);
+
+ FBDEV_SETSTART(FB_BASE);
+#else
+ fb_memset((fbtype *)FB_BASE,font_bgcolor.fbval,
+ (FB_END-FB_BASE)/sizeof(fbtype));
+#endif
+ }
+
+ fbi_consolemode_enabled = (char)enable;
+}
+
+int
+is_fbi_consolemode_enabled(void)
+{
+ if (fbi_consolemode_enabled)
+ return(1);
+ return(0);
+}
+
+void
+fillbox(int x_offset,int y_offset,int type,fbtype *dest_base,fbtype *src_base)
+{
+ int x, y, offset;
+ fbtype *src, *dest;
+
+ offset = (y_offset * BOX_YSIZE * SCREEN_WIDTH) + (x_offset * BOX_XSIZE);
+ dest = dest_base + offset;
+
+ if (type & FILLTYPE_COLOR) {
+ for(y=0;y<BOX_YSIZE;y++) {
+ for(x=0;x<BOX_XSIZE;x++)
+ dest[x] = *src_base;
+
+ dest += SCREEN_WIDTH;
+ }
+ }
+ else {
+ src = src_base + offset;
+
+ for(y=0;y<BOX_YSIZE;y++) {
+ for(x=0;x<BOX_XSIZE;x++)
+ dest[x] = src[x];
+
+ dest += SCREEN_WIDTH;
+ src += SCREEN_WIDTH;
+ }
+ }
+}
+
+/* copypixel():
+ * Copy the frame buffer data that corresponds to the specified x/y
+ * coordinate from one frame buffer block to another...
+ * Note, if filltype is FILLTYPE_COLOR, then we assume that 'frm'
+ * is pointing to a fixed color.
+ */
+void
+copypixel(fbtype *to, fbtype *frm, int filltype, int x, int y)
+{
+ fbtype *dst, *src;
+
+ dst = to + ((y * PIXELS_PER_ROW) + x);
+
+ if (filltype & FILLTYPE_COLOR)
+ src = frm;
+ else
+ src = frm + ((y * PIXELS_PER_ROW) + x);
+
+ *dst = *src;
+}
+
+/* fillscreen():
+ * Fill the screen from top to bottom in four scans, skipping around between
+ * each scan just to improve the effect. If 'box' is set, then the fill
+ * area is a 10x10 box; otherwise its a pixel.
+ */
+void
+fillscreen(fbtype *to,fbtype *frm,int filltype, int delay)
+{
+ int x, y;
+ int xInit, yInit, xEnd, yEnd;
+
+ yInit = xInit = 0;
+ xEnd = SCREEN_WIDTH;
+ yEnd = SCREEN_HEIGHT;
+ if (filltype & FILLTYPE_BOX) {
+ xEnd = xEnd/BOX_XSIZE;
+ yEnd = yEnd/BOX_YSIZE;
+ }
+
+repeat:
+ for(y=yInit;y<yEnd;y+=2) {
+ for(x=xInit;x<xEnd;x+=2) {
+ if (filltype & FILLTYPE_BOX) {
+ fillbox(x,y,filltype,to,frm);
+ if (delay)
+ monDelay(delay);
+ }
+ else if (filltype & FILLTYPE_COLOR) {
+ *(to + (y*SCREEN_WIDTH)+x) = *frm;
+ }
+ else {
+ *(to + (y*SCREEN_WIDTH)+x) = *(frm + (y*SCREEN_WIDTH)+x);
+ }
+ }
+ if (!(filltype & FILLTYPE_BOX)) {
+ if (delay)
+ monDelay(delay);
+ }
+ }
+ if ((xInit == 0) && (yInit == 0)) {
+ xInit = 1; yInit = 1;
+ goto repeat;
+ }
+ if ((xInit == 1) && (yInit == 1)) {
+ xInit = 0; yInit = 1;
+ goto repeat;
+ }
+ if ((xInit == 0) && (yInit == 1)) {
+ xInit = 1; yInit = 0;
+ goto repeat;
+ }
+ /* If FILTYPE_BOX is set and the boxsize is not evenly
+ * divided into the actual screen size, then we need to
+ * fill in the edges (right & bottom).
+ */
+ if (filltype & FILLTYPE_BOX) {
+ int xmod, ymod;
+
+ xmod = SCREEN_WIDTH % BOX_XSIZE;
+ ymod = SCREEN_HEIGHT % BOX_YSIZE;
+ if (xmod) {
+ for(y=0;y<SCREEN_HEIGHT;y++) {
+ for(x=SCREEN_WIDTH-xmod;x<SCREEN_WIDTH;x++)
+ copypixel(to,frm,filltype,x,y);
+ }
+ }
+ if (ymod) {
+ for(y=SCREEN_HEIGHT-ymod;y<SCREEN_HEIGHT;y++) {
+ for(x=0;x<SCREEN_WIDTH;x++)
+ copypixel(to,frm,filltype,x,y);
+ }
+ }
+ }
+}
+
+void
+fill_centerout(fbtype *to,fbtype *frm,int filltype, int delay)
+{
+ int i, j, x, y, row, col, maxcol, maxrow;
+
+ x = SCREEN_WIDTH/2;
+ y = SCREEN_HEIGHT/2;
+ copypixel(to,frm,filltype,x,y);
+ for(i=0;x>=0 && y>=0;x--,y--,i+=2) {
+ for(j=0,row=y,col=x;j<i;j++,col++)
+ copypixel(to,frm,filltype,col,row);
+ maxcol = col;
+ maxrow = row;
+ for(j=0,row=y;j<i;j++,row++)
+ copypixel(to,frm,filltype,col,row);
+ for(j=0;j<i;j++,col--)
+ copypixel(to,frm,filltype,col,row);
+ for(j=0;j<i;j++,row--)
+ copypixel(to,frm,filltype,col,row);
+ }
+ if (x == -1) {
+ while(y >= 0) {
+ for(x=0;x<SCREEN_WIDTH;x++) {
+ copypixel(to,frm,filltype,x,y);
+ copypixel(to,frm,filltype,x,maxrow);
+ }
+ y--; maxrow++;
+ }
+ }
+ else if (y == -1) {
+ while(x >= 0) {
+ for(y=0;y<SCREEN_HEIGHT;y++) {
+ copypixel(to,frm,filltype,x,y);
+ copypixel(to,frm,filltype,maxcol,y);
+ }
+ x--; maxcol++;
+ }
+ }
+}
+
+/* fb_setcolor():
+ * Fill the frame buffer with the incoming RGB-24 formatted
+ * color value...
+ */
+void
+fb_setcolor(long rgb, int transition_type)
+{
+ fbtype fillval, *to, *from;
+
+ to = (fbtype *)FB_BASE;
+ from = &fillval;
+ fillval = rgb_to_fb(rgb);
+
+ switch(transition_type) {
+ case 1: /* Pixel fill */
+ fillscreen(to,from,FILLTYPE_COLOR,0);
+ break;
+ case 2: /* Box fill */
+ fillscreen(to,from,FILLTYPE_BOX | FILLTYPE_COLOR,0);
+ break;
+ case 3: /* Center-out fill */
+ fill_centerout(to,from,FILLTYPE_COLOR,0);
+ break;
+ default: /* Standard top-to-bottom fill */
+ fb_memset(to,fillval,(FB_END-FB_BASE)/sizeof(fbtype));
+ break;
+ }
+}
+
+char *FbiHelp[] = {
+ "Frame buffer interface",
+ "-[d:f:o:t:v] {cmd} [args...]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -d ## delay the transition speed",
+ " -f RGB enable (and set) frame-buffer fill value",
+ " -o X,Y offset into frame buffer",
+ " -t ## apply transition when updating screen",
+ " (doesn't work with .bmp formated source data)",
+ " -v additive verbosity",
+ "",
+ "Commands:",
+ " color {rgb-value} # fill screen with specified color",
+ " consolemode {on|wrap|off} # enable/disable console mode",
+ " fb2file {filename} # copy frame-buffer to TFS file",
+ " fill {filename | hex_address} # fill screen with file or data",
+ " font {style} {xscale} {yscale} {fgcolor} {bgcolor}",
+ " print {text} # print to screen",
+ " setpixel {x} {y} {size} {color}",
+#ifdef FBDEV_SETSTART
+ " setstart {hex address} # establish base address of frame buffer",
+#endif
+#endif
+ 0,
+};
+
+int
+FbiCmd(int argc,char *argv[])
+{
+ TFILE *tfp;
+ unsigned char *bmp;
+ unsigned long fill_rgb;
+ fbtype *fp, fill_fbvalue;
+ char *cmd, *arg1, fill_is_set, *base, *comma;
+ int x, y, widthadjust, transition_type;
+ int data_is_raw, transition_delay, rowsize, verbose, opt;
+
+ if (!font_initialized)
+ font_defaults();
+
+ verbose = 0;
+ fill_rgb = 0;
+ fill_fbvalue = 0;
+ transition_delay = transition_type = fill_is_set = 0;
+ while((opt=getopt(argc,argv,"d:f:o:t:v")) != -1) {
+ switch(opt) {
+ case 'd':
+ transition_delay = (int)strtol(optarg,0,0);
+ break;
+ case 'f':
+ fill_is_set = 1;
+ fill_rgb = strtoul(optarg,0,0);
+ break;
+ case 'o':
+ comma = strchr(optarg,',');
+ if (!comma)
+ return(CMD_PARAM_ERROR);
+ font_xpos = strtol(optarg,0,0);
+ font_ypos = strtol(comma+1,0,0);
+ if ((font_xpos > SCREEN_WIDTH) || (font_ypos > SCREEN_HEIGHT)) {
+ printf("Offset out of range\n");
+ return(CMD_FAILURE);
+ }
+ break;
+ case 't':
+ transition_type = atoi(optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc == optind) {
+ printf("Frame buffer info...\n");
+ printf(" Base addr: 0x%lx\n",FB_BASE);
+ printf(" LCD width x height (pixels): %dx%d\n",
+ SCREEN_WIDTH,SCREEN_HEIGHT);
+#if PIXFMT_IS_RGB565
+ printf(" Pixel fmt: RGB565 (16 bits-per-pixel)\n");
+#elif PIXFMT_IS_RGB555
+ printf(" Pixel fmt: RGB555 (16 bits-per-pixel)\n");
+#endif
+ printf("Font (style=%d)...\n",font_style);
+ printf(" Scale: x=%d, y=%d\n", font_xscale,font_yscale);
+ printf(" Color: fg=0x%06x, bg=0x%06x\n",
+ font_fgcolor.rgbval, font_bgcolor.rgbval);
+ printf(" Total per-char font height: %d, width: %d\n",
+ font_totalcharheight,font_totalcharwidth);
+ printf(" Total rows: %d (mod %d), cols: %d\n",
+ font_rowsperscreen, font_linemodulo, font_colsperscreen);
+ printf(" Current position: x=%d, y=%d\n",font_xpos,font_ypos);
+
+ shell_sprintf("FBIBASE","0x%x",FB_BASE);
+ shell_sprintf("FBIROWS","%d",font_rowsperscreen);
+ shell_sprintf("FBICOLS","%d",font_colsperscreen);
+ return(CMD_SUCCESS);
+ }
+ if (argc < optind + 1)
+ return(CMD_FAILURE);
+
+ cmd = argv[optind];
+ arg1 = argv[optind+1];
+
+ if (strcmp(cmd,"fill") == 0) {
+ if (argc != (optind+2))
+ return(CMD_PARAM_ERROR);
+
+ if ((arg1[0] == '0') && (arg1[1] == 'x')) {
+ base = (char *)strtoul(arg1,0,0);
+ }
+ else {
+ if ((tfp = tfsstat(arg1)) == (TFILE *)0) {
+ printf("File '%s' not found\n",arg1);
+ return(1);
+ }
+ base = TFS_BASE(tfp);
+ }
+
+ if ((data_is_raw = get_bmpinfo(base,verbose)) == -1)
+ return(CMD_FAILURE);
+
+ if (fill_is_set) {
+ fill_fbvalue = rgb_to_fb(fill_rgb);
+ }
+
+ /* If the input data is raw, then just copy it directly to the frame
+ * buffer memory space and be done.
+ * Note, the transition_type set up with the -t option only works when
+ * we're pushing in raw data...
+ */
+ if (data_is_raw) {
+ fbtype *to = (fbtype *)FB_BASE;
+ fbtype *from = (fbtype *)base;
+
+ switch(transition_type) {
+ case 1: /* Pixel fill */
+ fillscreen(to,from,0,transition_delay);
+ break;
+ case 2: /* Box fill */
+ fillscreen(to,from,FILLTYPE_BOX,transition_delay);
+ break;
+ case 3: /* Center-out fill */
+ fill_centerout(to,from,0,transition_delay);
+ break;
+ default: /* Standard top-to-bottom fill */
+ if (transition_delay) {
+ while(to < (fbtype *)FB_END) {
+ *to++ = *from++;
+ if (((int)to & 0x1ff) == 0x1ff)
+ monDelay(transition_delay);
+ }
+ }
+ else {
+ fb_memcpy(to,from,(fbtype *)FB_END-to);
+ }
+ }
+ return(CMD_SUCCESS);
+ }
+
+ fp = (fbtype *)FB_BASE;
+
+ /* Adust the starting point based on x & y offsets (if any)...
+ */
+ fp += (font_ypos * SCREEN_WIDTH) + font_xpos;
+
+ /* Each row of pixels is extended to a 4-byte boundary, filling
+ * with an unspecified value so that the next row will start on
+ * a multiple-of-four byte location in memory or in the file.
+ * This equation establishes a row size variable that is compliant
+ * with that rule. The equation is taken directly out of the
+ * wikipedia page mentioned at the top of this file.
+ *
+ * (n * width) + 31
+ * rowsize = 4 * ( ---------------- )
+ * 32
+ *
+ * (where 'n' is the number of bits per pixel).
+ */
+ rowsize = ((((24*bmpinfo.width) + 31)/32) * 4);
+ if (verbose > 1)
+ printf("rowsize: %d\n",rowsize);
+
+ widthadjust = 0;
+ while ((bmpinfo.width * 3) % 4) {
+ widthadjust++;
+ bmpinfo.width++;
+ }
+
+ if ((verbose > 1) && widthadjust) {
+ printf("%d-byte width adjustment: %ld -> %ld\n",
+ widthadjust, bmpinfo.width-widthadjust, bmpinfo.width);
+ }
+
+ if (bmpinfo.rawsize == 0) {
+ bmpinfo.rawsize = (bmpinfo.height * bmpinfo.width) * 3;
+ }
+ else {
+ if ((verbose > 1) &&
+ (bmpinfo.rawsize != (bmpinfo.height * bmpinfo.width) * 3)) {
+ printf("size off: %d %d\n",
+ bmpinfo.rawsize,(bmpinfo.height * bmpinfo.width) * 3);
+ }
+ }
+
+ bmp = (unsigned char *)base + bmpinfo.offset + bmpinfo.rawsize;
+
+ /* Below there are 4 distinct cases regarding the size of the .bmp
+ * image vs the size of the LCD screen...
+ * If the bitmap is larger than the LCD, then just fit the upper
+ * left corner of the bitmap into the LCD.
+ * If the LCD is larger than the bitmap, just put the bitmap in
+ * the upper left corner of the LCD and allow portions to be cut off.
+ *
+ * - Pixels are stored "upside-down" with respect to normal image raster
+ * scan order, starting in the lower left corner, going from left to
+ * right, and then row by row from the bottom to the top of the image.
+ * As a result, this code has to also deal with that.
+ */
+
+ if (bmpinfo.width > SCREEN_WIDTH) {
+ if (bmpinfo.height > SCREEN_HEIGHT) {
+ if (verbose > 2)
+ printf("case 1\n");
+ for(y=0;y<SCREEN_HEIGHT;y++) {
+ volatile unsigned char *bp;
+
+ bmp -= rowsize;
+ bp = bmp;
+ for(x=0;x<SCREEN_WIDTH;x++,fp++) {
+ *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue
+ *fp |= ((short)(*bp++ & 0xfc) << 3); // Green
+ *fp |= ((short)(*bp++ & 0xf8) << 8); // Red
+ }
+ if (transition_delay) monDelay(transition_delay);
+ }
+ }
+ else {
+ if (verbose > 2)
+ printf("case 2\n");
+ for(y=0;y<bmpinfo.height;y++) {
+ volatile unsigned char *bp;
+
+ bmp -= rowsize;
+ bp = bmp;
+ for(x=0;x<SCREEN_WIDTH;x++,fp++) {
+ *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue
+ *fp |= ((short)(*bp++ & 0xfc) << 3); // Green
+ *fp |= ((short)(*bp++ & 0xf8) << 8); // Red
+ }
+ if (transition_delay) monDelay(transition_delay);
+ }
+ if (fill_is_set) {
+ while(fp < (unsigned short *)FB_END)
+ *fp++ = fill_fbvalue;
+ }
+ }
+ }
+ else {
+ if (bmpinfo.height > SCREEN_HEIGHT) {
+ if (verbose > 2)
+ printf("case 3\n");
+ for(y=0;y<SCREEN_HEIGHT;y++) {
+ volatile unsigned char *bp;
+
+ bmp -= rowsize;
+ bp = bmp;
+ for(x=0;x<bmpinfo.width;x++,fp++) {
+ *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue
+ *fp |= ((short)(*bp++ & 0xfc) << 3); // Green
+ *fp |= ((short)(*bp++ & 0xf8) << 8); // Red
+ }
+ if (fill_is_set) {
+ while(x++ < SCREEN_WIDTH)
+ *fp++ = fill_fbvalue;
+ }
+ else {
+ fp += (SCREEN_WIDTH - x);
+ }
+ if (transition_delay) monDelay(transition_delay);
+ }
+ }
+ else {
+ if (verbose > 2)
+ printf("case 4\n");
+ for(y=0;y<bmpinfo.height;y++) {
+ volatile unsigned char *bp;
+
+ bmp -= rowsize;
+ bp = bmp;
+ for(x=0;x<bmpinfo.width;x++,fp++) {
+ *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue
+ *fp |= ((short)(*bp++ & 0xfc) << 3); // Green
+ *fp |= ((short)(*bp++ & 0xf8) << 8); // Red
+ }
+ if (fill_is_set) {
+ while(x++ < SCREEN_WIDTH)
+ *fp++ = fill_fbvalue;
+ }
+ else {
+ fp += (SCREEN_WIDTH - x);
+ }
+ if (transition_delay) monDelay(transition_delay);
+ }
+ if (fill_is_set) {
+ while(fp < (unsigned short *)FB_END)
+ *fp++ = fill_fbvalue;
+ }
+ }
+ }
+ }
+#ifdef FBDEV_SETSTART
+ else if (strcmp(cmd,"setstart") == 0) {
+ if (argc != (optind+2))
+ return(CMD_PARAM_ERROR);
+
+ FBDEV_SETSTART(strtol(arg1,0,0));
+ return(CMD_SUCCESS);
+ }
+#endif
+ else if (strcmp(cmd,"color") == 0) {
+ if (argc != (optind+2))
+ return(CMD_PARAM_ERROR);
+
+ fb_setcolor(strtoul(arg1,0,0),transition_type);
+ return(CMD_SUCCESS);
+ }
+ else if (strcmp(cmd,"consolemode") == 0) {
+ if (argc == (optind+1)) {
+ printf("Consolemode currently %sabled\n",
+ fbi_consolemode_enabled ? "en" : "dis");
+ return(CMD_SUCCESS);
+ }
+
+ if (argc != (optind+2))
+ return(CMD_PARAM_ERROR);
+
+ if (strcmp(arg1,"on") == 0) {
+ fbi_consolemode_enable(1,1);
+ fbi_linewrap = 0;
+ }
+ else if (strcmp(arg1,"wrap") == 0) {
+ fbi_consolemode_enable(1,1);
+ fbi_linewrap = 1;
+ }
+ else if (strcmp(arg1,"off") == 0) {
+ fbi_consolemode_enable(0,1);
+ }
+ else {
+ return(CMD_PARAM_ERROR);
+ }
+
+ return(CMD_SUCCESS);
+ }
+ else if (strcmp(cmd,"font") == 0) {
+ int newstyle;
+ struct font *fontp;
+
+ if (argc != (optind+6))
+ return(CMD_PARAM_ERROR);
+
+ newstyle = atoi(argv[optind+1]);
+ if ((newstyle < 0) || (newstyle >= font_style_total())) {
+ printf("Invalid font style\n");
+ return(CMD_FAILURE);
+ }
+
+ font_style = newstyle;
+ font_xscale = atoi(argv[optind+2]);
+ font_yscale = atoi(argv[optind+3]);
+ if (strcmp(argv[optind+4],"--")) {
+ font_fgcolor.rgbval = strtol(argv[optind+4],0,0);
+ font_fgcolor.fbval = rgb_to_fb(font_fgcolor.rgbval);
+ }
+
+
+ if (strcmp(argv[optind+5],"transparent") == 0) {
+ font_is_opaque = 0;
+ }
+ else if (strcmp(argv[optind+5],"--")) {
+ font_is_opaque = 1;
+ font_bgcolor.rgbval = strtol(argv[optind+5],0,0);
+ font_bgcolor.fbval = rgb_to_fb(font_bgcolor.rgbval);
+ }
+
+
+ fontp = &font_styles[font_style];
+ font_totalcharheight = ((fontp->height + fontp->above + fontp->below) *
+ font_yscale);
+ font_totalcharwidth = ((fontp->width + fontp->between) * font_xscale);
+
+ font_rowsperscreen = SCREEN_HEIGHT / font_totalcharheight;
+ font_colsperscreen = SCREEN_WIDTH / font_totalcharwidth;
+ font_linemodulo = SCREEN_HEIGHT % font_totalcharheight;
+
+ font_initialized = 1;
+ }
+ else if (strcmp(cmd,"setpixel") == 0) {
+ long color;
+ int x, y, xx, yy, width;
+
+ if (argc != optind+5)
+ return(CMD_PARAM_ERROR);
+
+ x = strtol(argv[optind+1],0,0);
+ y = strtol(argv[optind+2],0,0);
+ width = strtol(argv[optind+3],0,0);
+ color = strtol(argv[optind+4],0,0);
+
+ for(xx = x-width;xx <= x+width;xx++) {
+ for(yy = y-width;yy <= y+width;yy++)
+ fbi_setpixel(xx,yy,color);
+ }
+ }
+ else if (strcmp(cmd,"print") == 0) {
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ if (verbose)
+ printf("Print: <%s>\n",argv[optind+1]);
+
+ fbi_puts(argv[optind+1]);
+ return(CMD_SUCCESS);
+ }
+ else if (strcmp(cmd,"fb2file") == 0) {
+ int err;
+
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ if (verbose)
+ printf("Copying frame buffer to '%s'...\n",arg1);
+
+ err = tfsadd(arg1,0,0,(unsigned char *)FB_BASE,FB_SIZE);
+ if (err != TFS_OKAY)
+ printf("Failed: %s\n",(char *)tfsctrl(TFS_ERRMSG,err,0));
+ return(CMD_SUCCESS);
+ }
+ else {
+ return(CMD_PARAM_ERROR);
+ }
+
+ return(CMD_SUCCESS);
+}
+
+/* fbi_putchar():
+ * This is the external putchar available to other parts of the code.
+ */
+void
+fbi_putchar(char c)
+{
+ if (!fbi_consolemode_enabled)
+ return;
+
+ fb_putchar(c);
+}
+
+#ifndef FBI_NO_CURSOR
+void
+fbi_cursor(void)
+{
+ static char beenhere;
+ static struct elapsed_tmr tmr;
+
+ if (!fbi_consolemode_enabled)
+ return;
+
+ if (!beenhere) {
+ startElapsedTimer(&tmr,500);
+ beenhere = 1;
+ return;
+ }
+
+ if(msecElapsed(&tmr)) {
+ fbi_cursorpos = (fbtype *)FB_BASE +
+ (font_ypos * font_totalcharheight * SCREEN_WIDTH) +
+ (font_xpos * font_totalcharwidth);
+
+ if (font_ypos < font_linemodulo) {
+ fbi_cursorpos += font_ypos*SCREEN_WIDTH;
+ }
+ else {
+ fbi_cursorpos += font_linemodulo*SCREEN_WIDTH;
+ }
+ fbi_cursorpos += (font_totalcharheight-3) * SCREEN_WIDTH;
+ if (fbi_cursorstate) {
+ fb_memset(fbi_cursorpos,font_bgcolor.fbval,font_totalcharwidth);
+#ifdef FBDEV_SETSTART
+ fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype),
+ font_bgcolor.fbval,font_totalcharwidth);
+#endif
+ fbi_cursorstate = 0;
+ }
+ else {
+ fb_memset(fbi_cursorpos,font_fgcolor.fbval,font_totalcharwidth);
+#ifdef FBDEV_SETSTART
+ fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype),
+ font_fgcolor.fbval,font_totalcharwidth);
+#endif
+ fbi_cursorstate = 1;
+ }
+ startElapsedTimer(&tmr,500);
+ }
+}
+
+void
+fbi_cursor_clear(void)
+{
+ if (fbi_cursorstate == 1) {
+ fb_memset(fbi_cursorpos,font_bgcolor.fbval,font_totalcharwidth);
+#ifdef FBDEV_SETSTART
+ fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype),
+ font_bgcolor.fbval,font_totalcharwidth);
+#endif
+ fbi_cursorstate = 0;
+ }
+}
+#endif
+
+/* fbi_splash():
+ * This function should be called at system startup to push out a
+ * "splash screen" if the appropriate file is installed in TFS.
+ * The presence of this file also establishes the initial state of
+ * the console...
+ * If the file is present, then consolemode is disabled and the splash
+ * screen is displayed. If the file is not present, then just set
+ * up the system with consolemode enabled.
+ */
+void
+fbi_splash(void)
+{
+ TFILE *tfp;
+ fbtype *fp;
+
+#if INCLUDE_UNZIP
+ tfp = tfsstat("splash.gz");
+ if (tfp) {
+ decompress((char *)TFS_BASE(tfp),(int)TFS_SIZE(tfp),(char *)FB_BASE);
+ return;
+ }
+#endif
+
+ tfp = tfsstat("splash.bin");
+ fp = (fbtype *)FB_BASE;
+
+ if (tfp) {
+ fbtype *splash;
+
+ splash = (fbtype *)TFS_BASE(tfp);
+ fb_memcpy(fp,splash,(fbtype *)FB_END-fp);
+ fbi_consolemode_enable(0,0);
+ }
+ else {
+ fbi_consolemode_enable(1,1);
+ }
+}
+
+void
+fbi_setpixel(int x, int y, long rgbcolor)
+{
+ fbtype *fbp;
+
+ if (x > PIXELS_PER_ROW)
+ x = PIXELS_PER_ROW;
+ else if (x < 0)
+ x = 0;
+ if (y > PIXELS_PER_COL)
+ y = PIXELS_PER_COL;
+ else if (y < 0)
+ y = 0;
+
+ fbp = (fbtype *)FB_BASE + ((y * PIXELS_PER_ROW) + x);
+ *fbp = rgb_to_fb(rgbcolor);
+}
+
+#endif
diff --git a/main/common/fbi.h b/main/common/fbi.h
new file mode 100755
index 0000000..1cdb9e6
--- /dev/null
+++ b/main/common/fbi.h
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * fbi.h:
+ *
+ * Frame Buffer Interface...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+
+#if INCLUDE_FBI
+
+#define fbi_putchar(a) fbi_putchar(a)
+extern void fbi_putchar(char c);
+
+#ifdef FBI_NO_CURSOR
+#define fbi_cursor()
+#else
+#define fbi_cursor(a) fbi_cursor(a)
+extern void fbi_cursor(void);
+#endif
+
+#else
+
+#define fbi_putchar(a)
+#define fbi_cursor()
+
+#endif
+
+extern void fbi_setpixel(int x, int y, long rgbcolor);
+extern void fbi_splash(void);
+extern void fbdev_init(void);
diff --git a/main/common/flash.c b/main/common/flash.c
new file mode 100755
index 0000000..9e01586
--- /dev/null
+++ b/main/common/flash.c
@@ -0,0 +1,1399 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * flash.c:
+ *
+ * This file contains the portions of the flash code that are device
+ * independent. Refer to the appropriate device sub-directory for the
+ * code that is specific to the flash device on the target.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#if INCLUDE_FLASH
+#include "cpu.h"
+#include "flash.h"
+#include <ctype.h>
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+
+extern struct flashdesc FlashNamId[];
+
+int FlashTrace;
+int FlashCurrentBank;
+int sectortoaddr(int,int *,uchar **);
+
+#define SRANGE_ERROR -1
+#define SRANGE_SINGLE 1
+#define SRANGE_RANGE 2
+#define SRANGE_ALL 3
+
+/* FlashProtectWindow:
+ * Must be set to allow any flash operation to be done on space assumed
+ * to be software protected.
+ */
+int FlashProtectWindow;
+
+/* FlashBank[]:
+ * This table contains all of the information that is needed to keep the
+ * flash code somewhat generic across multiple flash devices.
+ */
+struct flashinfo FlashBank[FLASHBANKS];
+
+#ifdef DISABLE_INTERRUPTS_DURING_FLASHOPS
+#define FLASH_INTSDECL unsigned long oints
+#define FLASH_INTSOFF() oints = intsoff()
+#define FLASH_INTSRESTORE(ival) intsrestore(oints)
+#else
+#define FLASH_INTSDECL
+#define FLASH_INTSOFF()
+#define FLASH_INTSRESTORE(ival)
+#endif
+
+/* showlockop():
+ * Return a string that verbosely represents the flash lock
+ * operation...
+ */
+char *
+showlockop(int operation)
+{
+ switch(operation) {
+ case FLASH_LOCK:
+ return("lock");
+ case FLASH_UNLOCK:
+ return("unlock");
+ case FLASH_LOCKDWN:
+ return("lock_down");
+ case FLASH_LOCKQRY:
+ return("lock_qry");
+ case FLASH_LOCKABLE:
+ return("lockable");
+ default:
+ return("???");
+ }
+}
+
+/* showflashtype():
+ * Find a match between the incoming id and an entry in the FlashNamId[]
+ * table. The FlashNamId[] table is part of the device-specific code.
+ */
+int
+showflashtype(ulong id, int showid)
+{
+ struct flashdesc *fdp;
+
+ if (showid)
+ printf("Flash ID: 0x%lx\n",id);
+
+ fdp = FlashNamId;
+ while(fdp->desc) {
+ if (id == fdp->id) {
+ printf("Device = %s\n",fdp->desc);
+ return(0);
+ }
+ fdp++;
+ }
+ if (id == FLASHRAM) {
+ printf("Device = FLASH-RAM\n");
+ return(0);
+ }
+ printf("Flash id 0x%lx not recognized\n",id);
+ return(-1);
+}
+
+void
+showflashtotal(void)
+{
+#if FLASHBANKS > 1
+ printf("Total of %d banks (0-%d), current default bank: %d\n",
+ FLASHBANKS,FLASHBANKS-1,FlashCurrentBank);
+#else
+ printf("Current flash bank: 0\n");
+#endif
+}
+
+/* showflashinfo():
+ * Dump information about specified flash device.
+ */
+int
+showflashinfo(char *devrange)
+{
+ uchar *base;
+ struct sectorinfo *sp;
+ struct flashinfo *fdev;
+ char *range, varname[32];
+ int first_sector_of_device, devtot;
+ int locksupported, sector, lastsector, hdrprinted;
+
+ devtot = 0;
+ hdrprinted = 0;
+ lastsector = lastflashsector();
+
+ /* An incoming NULL range implies "any" sector...
+ */
+ if (devrange == 0) {
+ showflashtotal();
+ range = "any";
+ }
+ else {
+ range = devrange;
+ }
+
+ /* Loop through all sectors on all devices, picking only those
+ * sectors that fall in the specified range.
+ */
+ for(sector = 0; sector <= lastsector; sector++) {
+ if (gotachar()) {
+ getchar();
+ printf("<break>\n");
+ break;
+ }
+ if (!inRange(range,sector))
+ continue;
+
+ if (!(fdev = snumtofdev(sector)))
+ return(-1);
+
+ first_sector_of_device = fdev->sectors[0].snum;
+
+ if (flashlock(first_sector_of_device,FLASH_LOCKABLE) > 0)
+ locksupported = 1;
+ else
+ locksupported = 0;
+
+ /* If sector is first sector of a device, then print
+ * device info also...
+ */
+ if ((sector == first_sector_of_device) && (!strcmp(range,"any"))) {
+ if (showflashtype(fdev->id,0) < 0)
+ return(-1);
+ printf(" Bank width : %d\n",fdev->width);
+ printf(" Sectors : %d\n",fdev->sectorcnt);
+ printf(" Base addr : 0x%08lx\n",(ulong)(fdev->base));
+ hdrprinted = 0;
+
+ if (devrange == 0) {
+ sprintf(varname,"FLASH_BASE_%d",devtot);
+ shell_sprintf(varname,"0x%lx",(ulong)(fdev->base));
+ sprintf(varname,"FLASH_SCNT_%d",devtot);
+ shell_sprintf(varname,"%d",fdev->sectorcnt);
+ sprintf(varname,"FLASH_END_%d",devtot);
+ shell_sprintf(varname,"0x%lx",(ulong)(fdev->end));
+ }
+ devtot++;
+ }
+
+ if (!hdrprinted) {
+ printf(" Sctr TFS? Begin End Size %s %s%s",
+ "SWProt?", "Erased?", locksupported ? " Locked?\n" : "\n");
+ hdrprinted = 1;
+ }
+
+ sp = &fdev->sectors[sector - first_sector_of_device];
+ sectortoaddr(sp->snum,0,&base);
+ if ((range == 0) || inRange(range,sp->snum)) {
+ printf(" %3d %c 0x%08lx 0x%08lx 0x%06lx %s %s ",
+ sp->snum, tfsspace((char *)base) ? '*' : ' ',
+ (ulong)(sp->begin), (ulong)(sp->end), sp->size,
+ sp->protected ? "yes" : " no",
+ flasherased(sp->begin,sp->end) ? "yes" : " no");
+ if (locksupported) {
+ switch(flashlock(sp->snum,FLASH_LOCKQRY)) {
+ case -1:
+ printf("???");
+ break;
+ case 1:
+ printf("yes");
+ break;
+ case 0:
+ printf(" no");
+ break;
+ }
+ }
+ printf("\n");
+ }
+ }
+
+ if (devrange == 0)
+ shell_sprintf("FLASH_DEVTOT","%d",devtot);
+
+ return(0);
+}
+
+#ifdef FLASH_COPY_TO_RAM
+
+/* flashopload():
+ * Copy flash operation to ram space.
+ * Note that this function assumes that cache is disabled at this point.
+ * This is important because we are copying text into bss space and if
+ * cache was on, there could be a coherency problem.
+ */
+int
+flashopload(ulong *begin,ulong *end,ulong *copy,int size)
+{
+ /* Some CPUs have 16bit opcodes and can only do aligned accesses. */
+ unsigned short *sBegin = (unsigned short *)begin;
+ unsigned short *sEnd = (unsigned short *)end;
+ unsigned short *sCopy = (unsigned short *)copy;
+
+ /* Verify space availability: */
+ if (((int)end - (int)begin) >= size) {
+ printf("flashopload overflow ((0x%lx-0x%lx) > 0x%x)\n",
+ (ulong)end,(ulong)begin,size);
+ return(-1);
+ }
+
+ /* Initially fill the copy space with 0xff so that the space
+ * remaining is viewable...
+ */
+ memset((char *)copy,0xff,size);
+
+ /* Copy function() to RAM, then verify: */
+ while(sBegin < sEnd) {
+ *sCopy = *sBegin;
+ if (*sCopy++ != *sBegin++) {
+ printf("flashopload failed\n");
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+#endif
+
+/* flashtype():
+ * Use the device-specific function pointer to call the routine
+ * relocated to RAM space.
+ */
+int
+flashtype(struct flashinfo *fdev)
+{
+ return(fdev->fltype(fdev));
+}
+
+/* flasherase():
+ * Use the device-specific function pointer to call the routine
+ * relocated to RAM space.
+ * Note that flasherase() is called with a sector number. The sector
+ * number is relative to the entire system, not just the particular device.
+ * This means that if there is more than one flash device in the system that
+ * the actual sector number (relative to the device) may not be the same
+ * value. This adjustment is made here so that the underlying code that is
+ * pumped into ram for execution does not have to be aware of this.
+ * Return...
+ * 1 if successful
+ * -1 if failure
+ * 0 if sector is protected or locked
+ */
+int
+flasherase(int snum)
+{
+ uchar *tmp;
+ ulong *base, *end;
+ int size, rc, dev_snum;
+ struct flashinfo *fdev;
+ struct sectorinfo *sinfo;
+
+ if (FlashTrace)
+ printf("flasherase(%d)\n",snum);
+
+ if (!(fdev = snumtofdev(snum)))
+ return(-1);
+
+ /* If the device type is RAM, the erase is a bit different...
+ */
+ if (fdev->id == FLASHRAM) {
+ // Use 'tmp' here to eliminate a 3.4 toolset warning.
+ sectortoaddr(snum,&size,&tmp);
+ base = (ulong *)tmp;
+ end = base + (size/sizeof(long));
+ while(base < end) {
+ *base = 0xffffffff;
+ if (*base != 0xffffffff)
+ return(-1);
+ base++;
+ }
+ return(1);
+ }
+
+ /* If the sector is soft-protected or locked, return negative
+ * and print failure. If the sector is already erased, then
+ * there is no need to issue the device-specific erase algorithm.
+ */
+ dev_snum = snum - fdev->sectors[0].snum;
+ sinfo = &fdev->sectors[dev_snum];
+ if (!flasherased(sinfo->begin,sinfo->end)) {
+ if ((!FlashProtectWindow) && (sinfo->protected)) {
+ printf("Sector %d protected\n",snum);
+ return(0);
+ }
+
+ if (flashlocked(snum,1))
+ return(0);
+
+ rc = fdev->flerase(fdev,dev_snum);
+ if (rc < 0)
+ return(rc);
+ }
+ return(1);
+}
+
+
+/* flashwrite():
+ * Use the device-specific function pointer to call the routine
+ * relocated to RAM space.
+ * First make a few checks on the request, then write to flash if all
+ * checks succeed.
+ */
+int
+flashwrite(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
+{
+ int j, lowsector, highsector, rc, first_sector_of_device;
+ register uchar *dp, *sp, *edp;
+
+ if (FlashTrace)
+ printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
+
+ if (fdev->id == FLASHRAM) {
+ uchar *sp, *dp, *end;
+ sp = src;
+ dp = dest;
+ end = dp+bytecnt;
+ while(dp < end) {
+ *dp = *sp;
+ if (*dp != *sp)
+ return(-1);
+ dp++; sp++;
+ }
+ return(0);
+ }
+
+ dp = dest;
+ sp = src;
+ edp = (dest + bytecnt) - 1;
+ first_sector_of_device = fdev->sectors[0].snum;
+
+ /* If outside the devices space, return failed.. */
+ if ((edp < fdev->sectors[0].begin) ||
+ (dp > fdev->sectors[fdev->sectorcnt-1].end)) {
+ printf("flashwrite() failed: dest out of flash range\n");
+ return(-1);
+ }
+
+ /* Make sure the destination is not within a protected sector */
+ if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {
+
+ /* First determine the sectors that overlap with the
+ * flash space to be written...
+ */
+
+ lowsector = highsector = -1;
+ for(j=0;j<fdev->sectorcnt;j++) {
+ if ((dp >= fdev->sectors[j].begin) &&
+ (dp <= fdev->sectors[j].end))
+ lowsector = j;
+ }
+ for(j=0;j<fdev->sectorcnt;j++) {
+ if ((edp >= fdev->sectors[j].begin) &&
+ (edp <= fdev->sectors[j].end))
+ highsector = j;
+ }
+ if ((lowsector == -1) || (highsector == -1)) {
+ printf("flashwrite() failed: can't find sector\n");
+ return(-1);
+ }
+
+ /* Now that the range of affected sectors is known,
+ * verify that those sectors are not protected or locked...
+ */
+ for(j=lowsector;j<=highsector;j++) {
+ if (fdev->sectors[j].protected) {
+ printf("flashwrite() failed: sector protected\n");
+ return(-1);
+ }
+ if (flashlocked(j+first_sector_of_device,1))
+ return(-1);
+ }
+ }
+
+ /* Now make sure that there is no attempt to transition a bit
+ * in the affected range from 0 to 1... A flash write can only
+ * bring bits low (erase brings them high).
+ */
+ while(dp < edp) {
+ if ((*dp & *sp) != *sp) {
+ printf("flashwrite(0x%lx) failed: bit 0->1 rqst denied.\n",
+ (long)dp);
+ return(-1);
+ }
+ dp++;
+ sp++;
+ WATCHDOG_MACRO;
+ }
+ rc = fdev->flwrite(fdev,dest,src,bytecnt);
+ if (rc < 0)
+ return(rc);
+
+ /* Assuming everything else appears to have passed, make sure the
+ * source and destination addresses match...
+ */
+ if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) {
+ printf("flashwrite() post-verify failed.\n");
+ return(-1);
+ }
+ return(0);
+}
+
+/* flashewrite():
+ * Use the device-specific function pointer to call the routine
+ * relocated to RAM space.
+ */
+int
+flashewrite(uchar *dest,uchar *src,long bytecnt)
+{
+ int i;
+ struct flashinfo *fdev;
+
+ if (FlashTrace)
+ printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
+
+ if ((fdev = addrtobank(dest)) == 0)
+ return(-1);
+
+ /* Source and destination addresses must be long-aligned. */
+ if (((int)src & 3) || ((int)dest & 3))
+ return(-1);
+
+ /* If the protection window is closed, then verify that no protected
+ * sectors will be written over...
+ */
+ if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {
+ for (i=0;i<fdev->sectorcnt;i++) {
+ if((((uchar *)dest) > (fdev->sectors[i].end)) ||
+ (((uchar *)dest+bytecnt) < (fdev->sectors[i].begin)))
+ continue;
+ else
+ if (fdev->sectors[i].protected)
+ return(-1);
+ }
+ }
+ return(fdev->flewrite(fdev,dest,src,bytecnt));
+}
+
+/* flashlock():
+ Use a function pointer to call the routine relocated to RAM space.
+*/
+int
+flashlock(int snum,int operation)
+{
+ int dev_snum;
+ struct flashinfo *fdev;
+
+ if (FlashTrace)
+ printf("flashlock(%d,%s)\n",snum,showlockop(operation));
+
+ fdev = snumtofdev(snum);
+ dev_snum = snum - fdev->sectors[0].snum;
+ return(fdev->fllock(fdev,dev_snum,operation));
+}
+
+int
+flashlocked(int snum, int verbose)
+{
+ if ((flashlock(snum,FLASH_LOCKABLE) > 0) &&
+ (flashlock(snum,FLASH_LOCKQRY) == 1)) {
+ if (verbose)
+ printf("Sector %d locked\n",snum);
+ return(1);
+ }
+ return(0);
+}
+
+/* snumtofdev():
+ * Return the flash device pointer that corresponds to the incoming
+ * sector number.
+ */
+struct flashinfo *
+snumtofdev(int snum)
+{
+ int dev;
+ struct flashinfo *fbnk;
+
+ fbnk = FlashBank;
+ for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
+ if ((snum >= fbnk->sectors[0].snum) &&
+ (snum <= fbnk->sectors[fbnk->sectorcnt-1].snum))
+ return(fbnk);
+ }
+ printf("snumtofdev(%d) failed\n",snum);
+ return(0);
+}
+
+/* addrtosector():
+ * Incoming address is translated to sector number, size of sector
+ * and base of sector.
+ * Return 0 if successful; else -1.
+ */
+int
+addrtosector(uchar *addr,int *sector,int *size,uchar **base)
+{
+ struct flashinfo *fbnk;
+ struct sectorinfo *sinfo;
+ int dev, sec, i;
+
+ sec = 0;
+ fbnk = FlashBank;
+ for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
+ for(i=0;i<fbnk->sectorcnt;i++,sec++) {
+ sinfo = &fbnk->sectors[i];
+ if ((addr >= sinfo->begin) && (addr <= sinfo->end)) {
+ if (sector) {
+ *sector = sec;
+ }
+ if (base) {
+ *base = sinfo->begin;
+ }
+ if (size) {
+ *size = sinfo->size;
+ }
+ return(0);
+ }
+ }
+ }
+ printf("addrtosector(0x%lx) failed\n",(ulong)addr);
+ return(-1);
+}
+
+/* addrtobank():
+ * From the incoming address, return a pointer to the flash bank that
+ * this address is within.
+ */
+struct flashinfo *
+addrtobank(uchar *addr)
+{
+ struct flashinfo *fbnk;
+ int dev;
+
+ fbnk = FlashBank;
+ for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
+ if ((addr >= fbnk->base) && (addr <= fbnk->end))
+ return(fbnk);
+ }
+ printf("addrtobank(0x%lx) failed\n",(ulong)addr);
+ return(0);
+}
+
+int
+sectortoaddr(int sector,int *size,uchar **base)
+{
+ struct flashinfo *fbnk;
+ struct sectorinfo *sinfo;
+ int dev, sec, i;
+
+ sec = 0;
+ fbnk = FlashBank;
+ for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
+ for(i=0;i<fbnk->sectorcnt;i++,sec++) {
+ if (sec == sector) {
+ sinfo = &fbnk->sectors[i];
+ if (base) *base = sinfo->begin;
+ if (size) *size = sinfo->size;
+ return(0);
+ }
+ }
+ }
+ printf("sectortoaddr(%d) failed\n",sector);
+ return(-1);
+}
+
+/* InFlashSpace():
+ * Return 1 if the block of memory is within flash space;
+ * else return 0.
+ */
+int
+InFlashSpace(uchar *begin, int size)
+{
+ int dev;
+ uchar *end;
+ struct flashinfo *fbnk;
+
+ end = begin+size;
+ fbnk = FlashBank;
+ for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
+ if (((begin >= fbnk->base) && (begin <= fbnk->end)) ||
+ ((end >= fbnk->base) && (end <= fbnk->end)))
+ return(1);
+ }
+ return(0);
+}
+
+/* flashbankinfo():
+ * Based on the incoming bank number, return the beginning, end and
+ * number of sectors within that bank.
+ */
+int
+flashbankinfo(int bank,uchar **begin,uchar **end,int *sectorcnt)
+{
+ struct flashinfo *fbnk;
+
+ if (bank >= FLASHBANKS)
+ return(-1);
+
+ fbnk = &FlashBank[bank];
+ if (begin)
+ *begin = fbnk->base;
+ if (end)
+ *end = fbnk->end;
+ if (sectorcnt)
+ *sectorcnt = fbnk->sectorcnt;
+ return(0);
+}
+
+/* lastlargesector():
+ * Incoming bank number is used to populate the sector information
+ * (sector number, sector size and address) of the last large sector
+ * in the specified bank.
+ * * from_addr defines the search start address:
+ * * from_addr = 0 means start from the first sector;
+ * * from_addr MUST be sector aligned.
+ * * sectorcnt defines the numbers of contiguous sectors to search across;
+ * * sectorcnt = 0 means search to the last sector.
+ * Return 0 if successful; else -1.
+ */
+int
+lastlargesector(int bank, uchar *from_addr,
+ int sectorcnt, int *sector, int *size, uchar **base)
+{
+ struct flashinfo *fbnk;
+ struct sectorinfo *sinfo;
+ uchar *largest_sbase;
+ int i, from_sector, to_sector, largest_ssize, largest_snum;
+
+ if (bank >= FLASHBANKS) {
+ printf("lastlargesector(%d) failed\n",bank);
+ return(-1);
+ }
+
+ fbnk = &FlashBank[bank];
+ largest_ssize = 0;
+ largest_snum = 0;
+ largest_sbase = (uchar *)0;
+
+ if (from_addr) {
+ if (addrtosector(from_addr, &from_sector, 0, 0) == -1)
+ return(-1);
+ if (fbnk->sectors[from_sector].begin != from_addr) {
+ printf("lastlargesector failed:\n"
+ " parameter from_addr (%0x08X) must be sector aligned\n",
+ from_addr);
+ return(-1);
+ }
+ }
+ else {
+ from_sector = 0;
+ }
+
+ to_sector = from_sector + sectorcnt - 1;
+ if (to_sector > fbnk->sectorcnt - 1) {
+ to_sector = fbnk->sectorcnt - 1;
+ }
+
+ //printf("from_addr = 0x%08X\n", from_addr);
+ //printf("from_sector = %d\n", from_sector);
+ //printf("to_sector = %d\n", to_sector);
+
+ sinfo = &fbnk->sectors[from_sector];
+ for(i=from_sector; i<=to_sector; i++, sinfo++) {
+ if (sinfo->size >= largest_ssize) {
+ largest_ssize = sinfo->size;
+ largest_snum = sinfo->snum;
+ largest_sbase = sinfo->begin;
+ }
+ }
+
+ //printf("largest_sbase = 0x%08X\n", largest_sbase);
+ //printf("largest_snum = %d\n", largest_snum);
+ //printf("largest_ssize = 0x%08X\n", largest_ssize);
+
+ if (sector)
+ *sector = largest_snum;
+ if (size)
+ *size = largest_ssize;
+ if (base)
+ *base = largest_sbase;
+ return(0);
+}
+
+void
+LowerFlashProtectWindow()
+{
+ if (FlashProtectWindow)
+ FlashProtectWindow--;
+}
+
+/* AppFlashWrite():
+ * Takes in a source, destination and byte count and converts that to
+ * the appropriate flashwrite() call. This function supports the possibility
+ * of having one write request span across multiple devices in contiguous
+ * memory space.
+ */
+int
+AppFlashWrite(uchar *dest,uchar *src,long bytecnt)
+{
+ int ret;
+ FLASH_INTSDECL;
+ long tmpcnt;
+ struct flashinfo *fbnk;
+
+ ret = 0;
+ while(bytecnt > 0) {
+ fbnk = addrtobank((uchar *)dest);
+ if (!fbnk)
+ return(-1);
+
+ if ((dest + bytecnt) <= fbnk->end)
+ tmpcnt = bytecnt;
+ else
+ tmpcnt = (fbnk->end - dest) + 1;
+
+ FLASH_INTSOFF();
+ ret = flashwrite(fbnk,dest,src,tmpcnt);
+ FLASH_INTSRESTORE();
+ if (ret < 0) {
+ printf("AppFlashWrite(0x%lx,0x%lx,%ld) failed (%d)\n",
+ (ulong)dest,(ulong)src,bytecnt,ret);
+ break;
+ }
+ src += tmpcnt;
+ dest += tmpcnt;
+ bytecnt -= tmpcnt;
+ }
+ return(ret);
+}
+
+#if INCLUDE_FLASHREAD
+
+/* flashread():
+ * Use the device-specific function pointer to call the routine
+ * relocated to RAM space.
+ * First make a few checks on the request, then read from flash
+ * if the checks succeed.
+ */
+int
+flashread(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
+{
+ int rc, first_sector_of_device;
+ register uchar *dp, *sp, *edp;
+
+ if (FlashTrace)
+ printf("flashread(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);
+
+ if (fdev->id == FLASHRAM) {
+ uchar *sp, *dp, *end;
+ sp = src;
+ dp = dest;
+ end = dp+bytecnt;
+ while(dp < end) {
+ *dp = *sp;
+ if (*dp != *sp)
+ return(-1);
+ dp++; sp++;
+ }
+ return(0);
+ }
+
+ dp = dest;
+ sp = src;
+ edp = (dest + bytecnt) - 1;
+ first_sector_of_device = fdev->sectors[0].snum;
+
+ /* If outside the devices space, return failed.. */
+ if ((edp < fdev->sectors[0].begin) ||
+ (dp > fdev->sectors[fdev->sectorcnt-1].end)) {
+ printf("flashread() failed: dest out of flash range\n");
+ return(-1);
+ }
+
+ rc = fdev->flread(fdev,dest,src,bytecnt);
+ if (rc < 0)
+ return(rc);
+
+ /* Assuming everything else appears to have passed, make sure the
+ * source and destination addresses match...
+ */
+ if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) {
+ printf("flashread() post-verify failed.\n");
+ return(-1);
+ }
+ return(0);
+}
+
+/* AppFlashRead():
+ * Takes in a source, destination and byte count and converts that to
+ * the appropriate flashwrite() call. This function supports the possibility
+ * of having one write request span across multiple devices in contiguous
+ * memory space.
+ */
+int
+AppFlashRead(uchar *dest,uchar *src,long bytecnt)
+{
+ int ret;
+ FLASH_INTSDECL;
+ long tmpcnt;
+ struct flashinfo *fbnk;
+
+ ret = 0;
+ while(bytecnt > 0) {
+ fbnk = addrtobank((uchar *)dest);
+ if (!fbnk)
+ return(-1);
+
+ if ((dest + bytecnt) <= fbnk->end)
+ tmpcnt = bytecnt;
+ else
+ tmpcnt = (fbnk->end - dest) + 1;
+
+ FLASH_INTSOFF();
+ ret = flashread(fbnk,dest,src,tmpcnt);
+ FLASH_INTSRESTORE();
+ if (ret < 0) {
+ printf("AppFlashRead(0x%lx,0x%lx,%ld) failed (%d)\n",
+ (ulong)dest,(ulong)src,bytecnt,ret);
+ break;
+ }
+ src += tmpcnt;
+ dest += tmpcnt;
+ bytecnt -= tmpcnt;
+ }
+ return(ret);
+}
+#endif
+
+int
+lastflashsector(void)
+{
+ int lastsnum;
+ struct flashinfo *lastfbnk;
+
+ lastfbnk = &FlashBank[FLASHBANKS-1];
+ lastsnum = lastfbnk->sectors[lastfbnk->sectorcnt-1].snum;
+ return(lastsnum);
+}
+
+int
+AppFlashEraseAll()
+{
+ FLASH_INTSDECL;
+ int ret, snum, lastsnum;
+
+ ret = 0;
+ FLASH_INTSOFF();
+
+ /* Loop through all sectors of all banks...
+ */
+ lastsnum = lastflashsector();
+ for(snum=0;snum<=lastsnum;snum++) {
+ WATCHDOG_MACRO;
+ ret = flasherase(snum);
+ if (ret <= 0)
+ break;
+ }
+
+ FLASH_INTSRESTORE();
+ return(ret);
+}
+
+/* Erase the flash sector specified. */
+int
+AppFlashErase(int snum) /* erase specified sector */
+{
+ int ret;
+ FLASH_INTSDECL;
+
+ FLASH_INTSOFF();
+ ret = flasherase(snum);
+ FLASH_INTSRESTORE();
+ return(ret);
+}
+
+/* sectorProtect():
+ * Set or clear (based on value of protect) the protected flag for the
+ * specified range of sectors...
+ * This supports incoming ranges that can be dash and/or comma delimited.
+ * For example a range can be "0", "0-3", or "0,2-4", etc...
+ */
+int
+sectorProtect(char *range, int protect)
+{
+ struct flashinfo *fbnk;
+ int i, dev, snum;
+
+ snum = 0;
+ for(dev = 0;dev < FLASHBANKS;dev++) {
+ fbnk = &FlashBank[dev];
+ for(i = 0;i < fbnk->sectorcnt;i++,snum++) {
+ if ((range == 0) || (*range == 0) || inRange(range,snum))
+ fbnk->sectors[i].protected = protect;
+ }
+ }
+ return(0);
+}
+
+#ifdef FLASHRAM_BASE
+
+struct sectorinfo sinfoRAM[FLASHRAM_SECTORCOUNT];
+
+/* FlashRamInit():
+ * This monitor supports TFS space allocated across multiple flash devices
+ * that may not be in contiguous memory space. To allow RAM to be seen
+ * as a "flash-like" device to TFS, we set it up in sectors similar to
+ * those in a real flash device.
+ * Input...
+ * snum: All the "flash" space is broken up into individual sectors.
+ * This is the starting sector number that is to be used for
+ * the block of sectors within this RAM space.
+ * fbnk: Pointer to the structure that must be populated with the
+ * flash bank information. Usually this contains pointers to the
+ * functions that operate on the flash; but for RAM they aren't
+ * necessary.
+ * sinfo: Table populated with the characteristics (size, start, etc...)
+ * of each sector.
+ * ssizes: A table containing the size of each of the sectors. This is
+ * copied to the sinfo space. If this pointer is NULL, then
+ * this function sets all sector sizes to FLASHRAM_SECTORSIZE.
+ */
+int
+FlashRamInit(int snum, int scnt, struct flashinfo *fbnk,
+ struct sectorinfo *sinfo, int *ssizes)
+{
+ int i;
+ uchar *begin;
+
+ /* FLASHRAM_SECTORCOUNT (in config.h) must match the number of sectors
+ * allocated to the flash ram device in flashdev.c...
+ */
+ if (scnt != FLASHRAM_SECTORCOUNT)
+ printf("Warning: flashram sector count inconsistency\n");
+
+ fbnk->id = FLASHRAM; /* Device id. */
+ fbnk->base = (uchar *)FLASHRAM_BASE; /* Base address of bank. */
+ fbnk->end = (uchar *)FLASHRAM_END; /* End address of bank. */
+ fbnk->sectorcnt = scnt; /* Number of sectors. */
+ fbnk->width = 1; /* Width (in bytes). */
+ fbnk->fltype = FlashOpNotSupported; /* Flashtype() function. */
+ fbnk->flerase = FlashOpNotSupported; /* Flasherase() function. */
+ fbnk->flwrite = FlashOpNotSupported; /* Flashwrite() function. */
+ fbnk->flewrite = FlashOpNotSupported; /* Flashewrite() function. */
+ fbnk->fllock = FlashOpNotSupported; /* Flashlock() function. */
+ fbnk->sectors = sinfo; /* Ptr to sector size table. */
+ begin = fbnk->base;
+ for(i=0;i<fbnk->sectorcnt;i++,snum++) {
+ sinfo[i].snum = snum;
+ if (ssizes == 0)
+ sinfo[i].size = FLASHRAM_SECTORSIZE;
+ else
+ sinfo[i].size = ssizes[i];
+ sinfo[i].begin = begin;
+ sinfo[i].end = sinfo[i].begin + sinfo[i].size - 1;
+ sinfo[i].protected = 0;
+ begin += sinfo[i].size;
+ }
+
+ return(snum);
+}
+#endif
+
+char *FlashHelp[] = {
+ "Flash memory operations",
+ "{op} [args]",
+#if INCLUDE_VERBOSEHELP
+ "Ops...",
+ " opw",
+ " init",
+ " type",
+ " bank [#]",
+ " prot {rnge}",
+ " info [rnge]",
+ " unprot {rnge}",
+ " lock {rnge}",
+ " unlock [rnge]",
+ " lockdwn {rnge}",
+ " erase {rnge}",
+ " trace {lvl}",
+ " write {dest} {src} {byte_cnt}",
+ " ewrite {dest} {src} {byte_cnt}",
+ "",
+ " rnge = range of affected sectors",
+ " Range syntax examples: <1> <1-5> <1,3,7> <all>",
+#endif
+ 0,
+};
+
+/* FlashCmd():
+ * Code that handles the user interface. See FlashHelp[] below for usage.
+ */
+int
+FlashCmd(int argc,char *argv[])
+{
+ int ret;
+ FLASH_INTSDECL;
+ ulong dest, src;
+ long bytecnt, rslt;
+ struct flashinfo *fbnk;
+
+ FLASH_INTSOFF();
+
+ fbnk = &FlashBank[FlashCurrentBank];
+ ret = CMD_SUCCESS;
+
+ if (strcmp(argv[1],"init") == 0)
+ FlashInit();
+ else if (strcmp(argv[1],"info") == 0) {
+ showflashinfo(argv[2]);
+ }
+ else if (strcmp(argv[1],"type") == 0) {
+ showflashtype((ulong)flashtype(fbnk),1);
+ }
+ else if (strcmp(argv[1],"trace") == 0) {
+ if (argc == 3)
+ FlashTrace = atoi(argv[2]);
+ else if (argc == 2)
+ printf("Flash trace lvl: %d\n",FlashTrace);
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (strcmp(argv[1],"bank") == 0) {
+ int tmpbank;
+ if (argc == 3) {
+ tmpbank = atoi(argv[2]);
+ if (tmpbank < FLASHBANKS) {
+ FlashCurrentBank = tmpbank;
+ }
+ else {
+ printf("Bank %d out of range\n",tmpbank);
+ return(CMD_PARAM_ERROR);
+ }
+ printf("Subsequent flash ops apply to bank %d\n",
+ FlashCurrentBank);
+ }
+ else {
+ showflashtotal();
+ }
+ }
+ else if (strcmp(argv[1],"ewrite") == 0) {
+ if (argc == 5) {
+ dest = strtoul(argv[2],(char **)0,0);
+ src = strtoul(argv[3],(char **)0,0);
+ bytecnt = (long)strtoul(argv[4],(char **)0,0);
+ rslt = flashewrite((uchar *)dest,(uchar *)src,bytecnt);
+ if (rslt < 0) {
+ printf("ewrite failed (%ld)\n",rslt);
+ ret = CMD_FAILURE;
+ }
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+ else if (!strcmp(argv[1],"write")) {
+ if (argc == 5) {
+ dest = strtoul(argv[2],(char **)0,0);
+ src = strtoul(argv[3],(char **)0,0);
+ bytecnt = (long)strtoul(argv[4],(char **)0,0);
+ rslt = AppFlashWrite((uchar *)dest,(uchar *)src,bytecnt);
+ if (rslt < 0) {
+ printf("Write failed (%ld)\n",rslt);
+ ret = CMD_FAILURE;
+ }
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+#if INCLUDE_FLASHREAD
+ else if (!strcmp(argv[1],"read")) {
+ if (argc == 5) {
+ dest = strtoul(argv[2],(char **)0,0);
+ src = strtoul(argv[3],(char **)0,0);
+ bytecnt = (long)strtoul(argv[4],(char **)0,0);
+ rslt = AppFlashRead((uchar *)dest,(uchar *)src,bytecnt);
+ if (rslt < 0) {
+ printf("Read failed (%ld)\n",rslt);
+ ret = CMD_FAILURE;
+ }
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+#endif
+ else if (!strcmp(argv[1],"opw")) {
+ if (getUsrLvl() != MAXUSRLEVEL)
+ printf("Must be user level %d\n",MAXUSRLEVEL);
+ else
+ FlashProtectWindow = 2;
+ }
+ else if (!strcmp(argv[1],"unprot")) {
+ if (argc != 3)
+ ret = CMD_PARAM_ERROR;
+ else
+ sectorProtect(argv[2],0);
+ }
+ else if (!strcmp(argv[1],"prot")) {
+ if (argc != 3)
+ ret = CMD_PARAM_ERROR;
+ else
+ sectorProtect(argv[2],1);
+ }
+ else if (!strcmp(argv[1],"erase")) {
+ if (argc != 3) {
+ ret = CMD_PARAM_ERROR;
+ }
+ else {
+ uchar *base;
+ int rc, snum, size, stot = 0;
+
+ if (strncmp(argv[2],"0x",2) == 0) {
+ ulong begin, end;
+ char *dash = strchr(argv[2],'-');
+
+ begin = end = strtoul(argv[2],0,0);
+ if (dash)
+ end = strtoul(dash+1,0,0);
+
+ while(begin <= end) {
+ if (addrtosector((uchar *)begin,&snum,&size,&base) < 0)
+ break;
+ begin = (ulong)base;
+ rc = flasherase(snum);
+ if (rc != 1) {
+ printf("Erase failed (%d)\n",rc);
+ ret = CMD_FAILURE;
+ break;
+ }
+ stot++;
+ begin += size;
+ }
+ }
+ else {
+ int last;
+
+ last = lastflashsector();
+ for(snum=0;snum<=last;snum++) {
+ int rc;
+
+ if ((argv[2] == 0) || inRange(argv[2],snum)) {
+ ticktock();
+ rc = flasherase(snum);
+ if (rc != 1) {
+ printf("Erase failed (%d)\n",rc);
+ ret = CMD_FAILURE;
+ break;
+ }
+ stot++;
+ }
+ }
+ }
+ printf("%d sectors erased\n",stot);
+ }
+ }
+ else if ((!strcmp(argv[1],"lock")) || (!strcmp(argv[1],"unlock")) ||
+ (!strcmp(argv[1],"lockdwn"))) {
+ int operation, snum;
+
+ if (!strcmp(argv[1],"lock"))
+ operation = FLASH_LOCK;
+ else if (!strcmp(argv[1],"unlock"))
+ operation = FLASH_UNLOCK;
+ else
+ operation = FLASH_LOCKDWN;
+
+ if (argc == 2) {
+#ifdef FLASH_PROTECT_RANGE
+ argv[2] = FLASH_PROTECT_RANGE;
+ argc = 3;
+ printf("Applying %s to sector(s) %s...\n",argv[1],argv[2]);
+#else
+ printf("Monitor not built with specified protection range\n");
+ ret = CMD_FAILURE;
+#endif
+ }
+
+ if (argc != 3) {
+ ret = CMD_PARAM_ERROR;
+ }
+ else {
+ int last;
+ struct flashinfo *fdev;
+
+ last = lastflashsector();
+ for(snum=0;snum<=last;snum++) {
+ if (inRange(argv[2],snum)) {
+ ticktock();
+ if ((fdev = snumtofdev(snum)) == 0) {
+ ret = CMD_FAILURE;
+ break;
+ }
+ if (flashlock(fdev->sectors[0].snum,FLASH_LOCKABLE) <= 0) {
+ printf("Sector %d does not support %s\n",snum,argv[1]);
+ ret = CMD_FAILURE;
+ break;
+ }
+ rslt = flashlock(snum,operation);
+ if (rslt < 0) {
+ printf("%s failed (%ld) at sector %d\n",
+ argv[1],rslt,snum);
+ ret = CMD_FAILURE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ ret = CMD_PARAM_ERROR;
+ }
+
+ FLASH_INTSRESTORE();
+ return(ret);
+}
+
+/* FlashOpOverride():
+ * This function is used by monlib to provide the application with the
+ * ability to override the underlying flash operations with functions
+ * provided by the application.
+ * The finfo parameter is actually a flashinfo pointer; set void here
+ * to eliminate confusion when used with monlib.h and the application .
+ */
+int
+FlashOpOverride(void *finfo, int get, int bank)
+{
+ char *src, *dst;
+ struct flashinfo *fdev;
+
+ if ((!finfo) || (bank >= FLASHBANKS))
+ return(-1);
+
+ fdev = &FlashBank[bank];
+
+ if (get) {
+ src = (char *)fdev;
+ dst = (char *)finfo;
+ }
+ else {
+ src = (char *)finfo;
+ dst = (char *)fdev;
+ }
+ memcpy(dst,src,sizeof(struct flashinfo));
+ return(0);
+}
+
+int
+FlashOpNotSupported(void)
+{
+ if (FlashTrace)
+ printf("flash operation not supported\n");
+
+ return(-1);
+}
+
+/* Used as a placeholder for the flash drivers that don't
+ * support flash lock...
+ */
+int
+FlashLockNotSupported(struct flashinfo *fdev,int snum,int operation)
+{
+ if (operation == FLASH_LOCKABLE)
+ return(0);
+ else
+ return(-1);
+}
+
+#endif
+
+/* flasherased():
+ * Return 1 if range of memory is all 0xff; else 0.
+ * Scan through the range of memory specified by begin-end (inclusive)
+ * looking for anything that is not 0xff. Do this in three sections so
+ * that the pointers can be 4-byte aligned for the bulk of the comparison
+ * range...
+ * The beginning steps through as a char pointer until aligned on a 4-byte
+ * boundary. Then do ulong * comparisons until the just before the end
+ * where we once again use char pointers to align on the last few
+ * non-aligned bytes (if any).
+ */
+int
+flasherased(unsigned char *begin, unsigned char *end)
+{
+ unsigned long *lp, *lp1, ltmp;
+
+ /* If begin is greater than end, the range is illegal. The only
+ * exception to this is the case where end may be zero. This is
+ * considered an exception because in cases where we are dealing
+ * with the last sector of a device that sits at the end of memory
+ * space, the end point will wrap.
+ */
+ if ((begin > end) && (end != 0)) {
+ printf("flasherased(): bad range\n");
+ return(0);
+ }
+
+ /* Get pointers aligned so that we can do the bulk of the comparison
+ * with long pointers...
+ */
+ while(((long)begin & 3) && (begin <= end)) {
+ if (*begin != 0xff)
+ return(0);
+ begin++;
+ }
+ if (begin > end)
+ return(1);
+
+ lp = (unsigned long *)begin;
+ ltmp = (unsigned long)end;
+ ltmp &= ~3;
+ lp1 = (unsigned long *)ltmp;
+
+ while(lp != lp1) {
+ if (*lp != 0xffffffff)
+ return(0);
+ lp++;
+
+#ifdef WATCHDOG_ENABLED
+ /* For each 64K through this loop, tickle the watchdog.
+ */
+ if ((0xffff & (unsigned long)lp) == 0) {
+ WATCHDOG_MACRO;
+ }
+#endif
+ }
+ if (lp > (unsigned long *)end)
+ return(1);
+
+ begin = (unsigned char *)lp;
+ do {
+ if (*begin != 0xff)
+ return(0);
+ } while(begin++ != end);
+ return(*end == 0xff);
+}
+
diff --git a/main/common/flash.h b/main/common/flash.h
new file mode 100755
index 0000000..118f845
--- /dev/null
+++ b/main/common/flash.h
@@ -0,0 +1,125 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * flash.h:
+ *
+ * Device-independent macros and data structures used by flash driver.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _FLASH_H_
+#define _FLASH_H_
+
+#define FLASH_PROTECT_WINDOW_CLOSED 0
+#define ALL_SECTORS -1
+
+#ifndef FLASH_LOOP_TIMEOUT
+#define FLASH_LOOP_TIMEOUT 1000000
+#endif
+
+#define FLASH_LOCK 1
+#define FLASH_UNLOCK 2
+#define FLASH_LOCKDWN 3
+#define FLASH_LOCKQRY 4
+#define FLASH_LOCKABLE 5 /* query driver for lock support */
+
+/* Device ID used for ram that is "pretending" to be a flash bank. */
+#define FLASHRAM 0x9999
+
+struct flashdesc {
+ unsigned long id; /* manufacturer & device id */
+ char *desc; /* ascii string */
+};
+
+struct sectorinfo {
+ long size; /* size of sector */
+ int snum; /* number of sector (amongst possibly */
+ /* several devices) */
+ int protected; /* if set, sector is protected by window */
+ unsigned char *begin; /* base address of sector */
+ unsigned char *end; /* end address of sector */
+};
+
+struct flashinfo {
+ unsigned long id; /* manufacturer & device id */
+ unsigned char *base; /* base address of device */
+ unsigned char *end; /* end address of device */
+ int sectorcnt; /* number of sectors */
+ int width; /* 1, 2, or 4 */
+ int (*fltype)(struct flashinfo *);
+ int (*flerase)(struct flashinfo *, int);
+#if INCLUDE_FLASHREAD
+ int (*flread)(struct flashinfo *,unsigned char *,\
+ unsigned char *,long);
+#endif
+ int (*flwrite)(struct flashinfo *,unsigned char *,\
+ unsigned char *,long);
+ int (*flewrite)(struct flashinfo *,unsigned char *,\
+ unsigned char *,long);
+ int (*fllock)(struct flashinfo *,int,int);
+ struct sectorinfo *sectors;
+};
+
+extern int FlashTrace;
+extern int FlashProtectWindow;
+extern int FlashCurrentBank;
+extern struct flashinfo FlashBank[FLASHBANKS];
+extern int flashopload(unsigned long *begin,unsigned long *end, \
+ unsigned long *copy,int size);
+
+extern int showflashtype(unsigned long, int);
+extern int showflashinfo(char *);
+extern int flashopload(unsigned long *,unsigned long *,unsigned long *,int);
+extern int flashtype(struct flashinfo *);
+extern int flasherase(int snum);
+extern int flashwrite(struct flashinfo *,unsigned char *,unsigned char *,long);
+extern int flashewrite(unsigned char *,unsigned char *,long);
+extern int flasherased(unsigned char *,unsigned char *);
+extern int flashlock(int, int);
+extern int flashlocked(int, int);
+extern int addrtosector(unsigned char *,int *,int *,unsigned char **);
+extern struct flashinfo *snumtofdev(int);
+extern struct flashinfo *addrtobank(unsigned char *);
+extern int sectortoaddr(int,int *,unsigned char **);
+extern int flashbankinfo(int,unsigned char **,unsigned char **,int *);
+extern void LowerFlashProtectWindow(void);
+extern int AppFlashWrite(unsigned char *,unsigned char *,long);
+extern int AppFlashEraseAll(void);
+extern int AppFlashErase(int);
+extern int srange(char *,int *,int *);
+extern int sectorProtect(char *,int);
+extern int FlashOpNotSupported(void);
+extern int FlashLockNotSupported(struct flashinfo *,int,int);
+extern int lastlargesector(int,unsigned char *,int,int *,int *,unsigned char **);
+extern int lastflashsector(void);
+extern int FlashRamInit(int, int, struct flashinfo *,struct sectorinfo *,int *);
+extern int InFlashSpace(unsigned char *begin, int size);
+extern int FlashOpOverride(void *flashinfo,int get,int bank);
+
+#define NotAligned16(add) ((long)add & 1)
+#define NotAligned32(add) ((long)add & 3)
+
+#ifdef FLASHRAM_BASE
+extern int ramSectors[];
+extern struct sectorinfo sinfoRAM[];
+#endif
+
+#endif
diff --git a/main/common/flashram.c b/main/common/flashram.c
new file mode 100644
index 0000000..d2f0841
--- /dev/null
+++ b/main/common/flashram.c
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * flashram.c
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+
+#ifdef FLASHRAM_BASE
+/* As of Jan 2004, this module is no longer needed.
+ * I added an option to FlashRamInit() so that if the incoming sector
+ * size table is NULL, then all sectors are initialized to the same
+ * size. For cases where this table was used, the call to FlashRamInit
+ * should have the ssizes argument changed to zero. See FlashRamInit()
+ * for more on this.
+ */
+#if 0
+#include "flash.h"
+
+/* Generic Flash RAM configuration information...
+ * The assumption is a 16-element array (FLASHRAM_SECTORCOUNT = 16).
+ *
+ * This can be included in a monitor build if the build has
+ * a block of RAM dedicated to TFS file storage. If some other
+ * configuration is required, then copy this to target-specific space
+ * and modify a local version.
+ */
+int
+ramSectors[FLASHRAM_SECTORCOUNT] = {
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE,
+};
+#endif
+#endif
diff --git a/main/common/font.c b/main/common/font.c
new file mode 100755
index 0000000..87d1df9
--- /dev/null
+++ b/main/common/font.c
@@ -0,0 +1,6751 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * font.c:
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ * Contribution by: Mike Kelly (www.cogcomp.com)
+ *
+ */
+
+#include "config.h"
+#include "font.h"
+
+/* If none of the three fonts are defined in config.h, then we just
+ * default to using the 8x13 font (which is probably the only font
+ * really needed).
+ */
+#ifndef USE_FONT_8x12
+#ifndef USE_FONT_8x16
+#ifndef USE_FONT_8x13
+#define USE_FONT_8x13
+#endif
+#endif
+#endif
+
+#ifdef USE_FONT_8x12
+/* font:
+ * This is a homemade 8x12 pixel font. Crude at best.
+ * It uses the entire 8x12 space, does not put any fixed
+ * edge on the pixel. It therefore looks better if the
+ * font definition structure used with this font provide
+ * at least an 'above' and 'between' setting of 1.
+ */
+char font8x12[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // SPACE
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x00,0x38,0x38,0x00, // !
+ 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
+ 0x00,0x66,0x66,0xff,0xff,0x66,0x66,0xff,0xff,0x66,0x66,0x00, // #
+ 0x3c,0x7e,0xdb,0xdb,0xd8,0x7c,0x3e,0x1b,0xdb,0xdb,0x7e,0x3c, // $
+ 0x00,0x61,0x63,0x06,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00, // %
+ 0x00,0x00,0x00,0x18,0x18,0x7f,0xfe,0x18,0x18,0x00,0x00,0x00, // &
+ 0x18,0x18,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
+ 0x1e,0x1e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1e,0x1e, // (
+ 0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x78, // )
+ 0x00,0x00,0x00,0x66,0x18,0x7f,0xfe,0x18,0x66,0x00,0x00,0x00, // *
+ 0x00,0x00,0x00,0x18,0x18,0x7f,0xfe,0x18,0x18,0x00,0x00,0x00, // +
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60, // ,
+ 0x00,0x00,0x00,0x00,0x00,0x7e,0x7e,0x00,0x00,0x00,0x00,0x00, // -
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18, // .
+ 0x00,0x01,0x03,0x07,0x0e,0x1c,0x38,0x70,0xe0,0xc0,0x80,0x00, // /
+
+ 0x3c,0x7e,0xc7,0xc7,0xcb,0xcb,0xd3,0xd3,0xe3,0xe3,0x7e,0x3c, // 0
+ 0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x7e, // 1
+ 0x7e,0xff,0xc3,0x03,0x07,0x1e,0x78,0xe0,0xc0,0xc0,0xff,0xff, // 2
+ 0x7c,0xfe,0x03,0x03,0x03,0x7e,0x7e,0x03,0x03,0x03,0xfe,0x7c, // 3
+ 0xc0,0xc0,0xc6,0xc6,0xc6,0xff,0xff,0x06,0x06,0x06,0x06,0x06, // 4
+ 0xfe,0xff,0xc0,0xc0,0xfc,0x7e,0x03,0x03,0xc3,0xc3,0x7e,0x3c, // 5
+ 0x3c,0x7e,0xc3,0xc0,0xc0,0xfc,0xfe,0xc3,0xc3,0xc3,0x7e,0x3c, // 6
+ 0x7f,0xff,0x03,0x03,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc0, // 7
+ 0x3c,0x7e,0xc3,0xc3,0xc3,0x7e,0x7e,0xc3,0xc3,0xc3,0x7e,0x3c, // 8
+ 0x3c,0x7e,0xc3,0xc3,0xc3,0x7f,0x3f,0x03,0x03,0x03,0x03,0x03, // 9
+
+ 0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00, // :
+ 0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x80,0x01, // ;
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x20,0x10,0x08,0x04,0x02,0x01, // <
+ 0x00,0x00,0x00,0x7e,0x7e,0x00,0x00,0x7e,0x7e,0x00,0x00,0x00, // =
+ 0x80,0x40,0x20,0x10,0x08,0x04,0x04,0x08,0x10,0x20,0x40,0x80, // >
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ?
+
+ 0x3c,0x7e,0xc3,0xcf,0xdf,0xdb,0xdb,0xdf,0xce,0xc0,0x7e,0x3c, // @
+ 0x3c,0x7e,0x66,0xc3,0xc3,0xc3,0xff,0xff,0xc3,0xc3,0xc3,0xc3, // A
+ 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc, // B
+ 0x3c,0x7e,0xe7,0xc3,0xc0,0xc0,0xc0,0xc0,0xc3,0xe7,0x7e,0x3c, // C
+ 0xfc,0xfe,0xc7,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc7,0xfe,0xfc, // D
+ 0xff,0xff,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0,0xc0,0xff,0xff, // E
+ 0xff,0xff,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0,0xc0,0xc0,0xc0, // F
+ 0x3c,0x7e,0xe3,0xc3,0xc0,0xc0,0xcf,0xcf,0xc3,0xe3,0x7f,0x3e, // G
+ 0xc3,0xc3,0xc3,0xc3,0xc3,0xff,0xff,0xc3,0xc3,0xc3,0xc3,0xc3, // H
+ 0xff,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0xff, // I
+ 0xff,0xff,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0xfc,0x78, // J
+ 0xc3,0xc3,0xc7,0xce,0xdc,0xf8,0xf8,0xdc,0xce,0xc7,0xc3,0xc3, // K
+ 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xff,0xff, // L
+ 0xc3,0xe7,0xff,0xff,0xdb,0xdb,0xdb,0xdb,0xc3,0xc3,0xc3,0xc3, // M
+ 0xc3,0xe3,0xf3,0xfb,0xdf,0xcf,0xc7,0xc3,0xc3,0xc3,0xc3,0xc3, // N
+ 0x3c,0x7e,0x66,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x7e,0x3c, // O
+ 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc,0xc0,0xc0,0xc0,0xc0,0xc0, // P
+ 0x38,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7f,0x3b, // Q
+ 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc,0xce,0xc7,0xc3,0xc3,0xc3, // R
+ 0x3c,0x7e,0xc3,0xc3,0xc0,0x7c,0x3e,0x03,0xc3,0xc3,0x7e,0x3c, // S
+ 0xff,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // T
+ 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xe7,0x7e,0x3c, // U
+ 0xc3,0xc3,0x66,0x66,0x66,0x66,0x66,0x66,0x7e,0x3c,0x3c,0x18, // V
+ 0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xdb,0xdb,0xff,0xff,0xe7,0xc3, // W
+ 0xc3,0xc3,0xc3,0x66,0x3c,0x3c,0x66,0x66,0xc3,0xc3,0xc3,0xc3, // X
+ 0xc3,0xc3,0xe7,0x66,0x3c,0x3c,0x18,0x18,0x18,0x18,0x18,0x18, // Y
+ 0xff,0xff,0x03,0x07,0x0e,0x1c,0x38,0x70,0xe0,0xc0,0xff,0xff, // Z
+
+ 0x1e,0x1e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1e,0x1e, // [
+ 0x00,0x80,0xc0,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00,0x00, // BACKSLASH
+ 0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x78, // ]
+ 0x00,0x18,0x66,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, // _
+
+ 0x30,0x30,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // `
+ 0x00,0x00,0x00,0x00,0x3e,0x63,0x03,0x3f,0x63,0x63,0x3f,0x01, // a
+ 0x00,0x60,0x60,0x60,0x7e,0x63,0x63,0x63,0x63,0x63,0x7e,0x00, // b
+ 0x00,0x00,0x00,0x00,0x3e,0x63,0x60,0x60,0x60,0x63,0x3e,0x00, // c
+ 0x00,0x03,0x03,0x03,0x3f,0x63,0x63,0x63,0x63,0x63,0x3f,0x00, // d
+ 0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x7f,0x60,0x63,0x3e,0x00, // e
+ 0x00,0x1e,0x33,0x33,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x00, // f
+ 0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x3f,0x03,0x03,0x63,0x3e, // g
+ 0x00,0x60,0x60,0x60,0x7e,0x63,0x63,0x63,0x63,0x63,0x63,0x00, // h
+ 0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0c,0x00, // i
+ 0x00,0x03,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x63,0x63,0x3e, // j
+ 0x00,0x60,0x60,0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x66,0x00, // k
+ 0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x00, // l
+ 0x00,0x00,0x00,0x00,0xe6,0xdb,0xdb,0xdb,0xdb,0xc3,0xc3,0x00, // m
+ 0x00,0x00,0x00,0x00,0x6e,0x73,0x63,0x63,0x63,0x63,0x63,0x00, // n
+ 0x00,0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00, // o
+ 0x00,0x00,0x00,0x00,0x7e,0x63,0x63,0x63,0x7e,0x60,0x60,0x60, // p
+ 0x00,0x00,0x00,0x00,0x7c,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x06, // q
+ 0x00,0x00,0x00,0x00,0x6e,0x73,0x63,0x60,0x60,0x60,0x60,0x00, // r
+ 0x00,0x00,0x00,0x00,0x3e,0x63,0x60,0x3e,0x03,0x63,0x3e,0x00, // s
+ 0x00,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x00, // t
+ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3a,0x00, // u
+ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00, // v
+ 0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xdb,0x66,0x00, // w
+ 0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00, // x
+ 0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x3f,0x03,0x03,0x63,0x3e, // y
+ 0x00,0x00,0x00,0x00,0x7f,0x06,0x0c,0x18,0x30,0x60,0x7f,0x00, // z
+
+ 0x03,0x06,0x06,0x06,0x0c,0x18,0x0c,0x06,0x06,0x06,0x03,0x00, // {
+ 0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x18,0x18,0x18, // |
+ 0xc0,0x60,0x60,0x60,0x30,0x18,0x30,0x60,0x60,0x60,0xc0,0x00, // }
+ 0x00,0x00,0x61,0x92,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //
+};
+
+#endif
+
+#ifdef USE_FONT_8x16
+
+char font8x16[] = {
+
+/* Character (0x20):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ! (0x21):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | **** |
+ | **** |
+ | **** |
+ | **** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x3c,
+0x3c,
+0x3c,
+0x3c,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character " (0x22):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | * * |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x36,
+0x36,
+0x36,
+0x36,
+0x14,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character # (0x23):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x6c,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character $ (0x24):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** |
+ | **** |
+ | **** |
+ | ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x7c,
+0xc6,
+0xc0,
+0x78,
+0x3c,
+0x06,
+0xc6,
+0x7c,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character % (0x25):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** * |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x62,
+0x66,
+0x0c,
+0x18,
+0x30,
+0x66,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character & (0x26):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ | *** |
+ | ** |
+ | *** ** |
+ | ****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x38,
+0x6c,
+0x38,
+0x30,
+0x76,
+0x7e,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ' (0x27):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ( (0x28):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ) (0x29):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x30,
+0x18,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x30,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character * (0x2a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ | *** |
+ |******* |
+ | *** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0x38,
+0xfe,
+0x38,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character + (0x2b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ****** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x7e,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character , (0x2c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+
+/* Character - (0x2d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character . (0x2e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character / (0x2f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ |* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x02,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x80,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 0 (0x30):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ |** **** |
+ |**** ** |
+ |*** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xce,
+0xde,
+0xf6,
+0xe6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 1 (0x31):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x78,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 2 (0x32):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc6,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 3 (0x33):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ | ** |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0x06,
+0x06,
+0x3c,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 4 (0x34):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | *** |
+ | **** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x1c,
+0x3c,
+0x6c,
+0xcc,
+0xcc,
+0xfe,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 5 (0x35):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** |
+ |** |
+ |** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc0,
+0xc0,
+0xc0,
+0xfc,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 6 (0x36):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xfc,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 7 (0x37):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 8 (0x38):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 9 (0x39):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7e,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character : (0x3a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ; (0x3b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+
+/* Character < (0x3c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character = (0x3d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character > (0x3e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ? (0x3f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x0c,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character @ (0x40):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** **** |
+ |** **** |
+ |** **** |
+ |** *** |
+ |** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xde,
+0xde,
+0xde,
+0xdc,
+0xc0,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character A (0x41):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character B (0x42):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character C (0x43):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** ** |
+ |** * |
+ |** |
+ |** |
+ |** |
+ |** |
+ |** * |
+ | ** ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x66,
+0xc2,
+0xc0,
+0xc0,
+0xc0,
+0xc0,
+0xc2,
+0x66,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character D (0x44):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xf8,
+0x6c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x6c,
+0xf8,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character E (0x45):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x66,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character F (0x46):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character G (0x47):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xce,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character H (0x48):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character I (0x49):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character J (0x4a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0xd8,
+0xd8,
+0x70,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character K (0x4b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |**** |
+ |**** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xcc,
+0xd8,
+0xf0,
+0xf0,
+0xd8,
+0xcc,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character L (0x4c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |**** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xf0,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x62,
+0x66,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character M (0x4d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |*** *** |
+ |*** *** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xee,
+0xee,
+0xfe,
+0xd6,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character N (0x4e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |*** ** |
+ |*** ** |
+ |**** ** |
+ |** **** |
+ |** *** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xe6,
+0xe6,
+0xf6,
+0xde,
+0xce,
+0xce,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character O (0x4f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character P (0x50):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Q (0x51):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ | ***** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0x7c,
+0x06,
+0x00,
+0x00,
+0x00,
+
+/* Character R (0x52):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x78,
+0x6c,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character S (0x53):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ | *** |
+ | *** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0x70,
+0x1c,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character T (0x54):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ****** |
+ | * ** * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7e,
+0x5a,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character U (0x55):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character V (0x56):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character W (0x57):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ |*** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0xee,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character X (0x58):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Y (0x59):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Z (0x5a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** ** |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** * |
+ |** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc6,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc2,
+0xc6,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character [ (0x5b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character \ (0x5c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |* |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x80,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x02,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ] (0x5d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ^ (0x5e):
+ ht=16, width=8
+ +--------+
+ | |
+ | * |
+ | *** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x10,
+0x38,
+0x6c,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character _ (0x5f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |********|
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xff,
+0x00,
+0x00,
+
+/* Character ` (0x60):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character a (0x61):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | **** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x78,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xdc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character b (0x62):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character c (0x63):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character d (0x64):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character e (0x65):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xfe,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character f (0x66):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x1c,
+0x36,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x78,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character g (0x67):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** *** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xce,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character h (0x68):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character i (0x69):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x00,
+0x38,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character j (0x6a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0xcc,
+0xcc,
+0x78,
+0x00,
+0x00,
+
+/* Character k (0x6b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x66,
+0x66,
+0x6c,
+0x78,
+0x6c,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character l (0x6c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x1c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character m (0x6d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0xfe,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character n (0x6e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character o (0x6f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character p (0x70):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+
+/* Character q (0x71):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7c,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+
+/* Character r (0x72):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x60,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character s (0x73):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ | ***** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0x7c,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character t (0x74):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x30,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x36,
+0x1c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character u (0x75):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character v (0x76):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character w (0x77):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character x (0x78):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character y (0x79):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character z (0x7a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x62,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character { (0x7b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x70,
+0x18,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character | (0x7c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character } (0x7d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x70,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x18,
+0x70,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ~ (0x7e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** ** |
+ |** *** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x76,
+0xdc,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character  (0x7f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | * |
+ | *** |
+ | *** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x10,
+0x38,
+0x38,
+0x6c,
+0x6c,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+};
+#endif
+
+#ifdef USE_FONT_8x13
+
+/* This is the same font as the above 8x16, but with the "empty" top
+ * and bottom edges removed. Two pixels at the bottom and one at the
+ * top.
+ * It is up to the font rendering engine to insert them based on the
+ * font style chosen. See the font table at the bottom of this file.
+ */
+char font8x13[] = {
+
+/* Character (0x20):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ! (0x21):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | **** |
+ | **** |
+ | **** |
+ | **** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x3c,
+0x3c,
+0x3c,
+0x3c,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character " (0x22):
+ ht=13, width=8
+ +--------+
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | * * |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x36,
+0x36,
+0x36,
+0x36,
+0x14,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character # (0x23):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x6c,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0x6c,
+0x00,
+0x00,
+
+/* Character $ (0x24):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** |
+ | **** |
+ | **** |
+ | ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x7c,
+0xc6,
+0xc0,
+0x78,
+0x3c,
+0x06,
+0xc6,
+0x7c,
+0x18,
+0x18,
+
+/* Character % (0x25):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** * |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x62,
+0x66,
+0x0c,
+0x18,
+0x30,
+0x66,
+0xc6,
+0x00,
+0x00,
+
+/* Character & (0x26):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** ** |
+ | *** |
+ | ** |
+ | *** ** |
+ | ****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x38,
+0x6c,
+0x38,
+0x30,
+0x76,
+0x7e,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+
+/* Character ' (0x27):
+ ht=13, width=8
+ +--------+
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ( (0x28):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+
+/* Character ) (0x29):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x30,
+0x18,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x30,
+0x00,
+0x00,
+
+/* Character * (0x2a):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ | *** |
+ |******* |
+ | *** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0x38,
+0xfe,
+0x38,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character + (0x2b):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ****** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x7e,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character , (0x2c):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+
+/* Character - (0x2d):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character . (0x2e):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character / (0x2f):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ |* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x02,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x80,
+0x00,
+0x00,
+
+/* Character 0 (0x30):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ |** **** |
+ |**** ** |
+ |*** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xce,
+0xde,
+0xf6,
+0xe6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character 1 (0x31):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ****** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x78,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x7e,
+0x00,
+0x00,
+
+/* Character 2 (0x32):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |******* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc6,
+0xfe,
+0x00,
+0x00,
+
+/* Character 3 (0x33):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ | ** |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0x06,
+0x06,
+0x3c,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character 4 (0x34):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | *** |
+ | **** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x0c,
+0x1c,
+0x3c,
+0x6c,
+0xcc,
+0xcc,
+0xfe,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+
+/* Character 5 (0x35):
+ ht=13, width=8
+ +--------+
+ | |
+ |******* |
+ |** |
+ |** |
+ |** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfe,
+0xc0,
+0xc0,
+0xc0,
+0xfc,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character 6 (0x36):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xfc,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character 7 (0x37):
+ ht=13, width=8
+ +--------+
+ | |
+ |******* |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfe,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x00,
+0x00,
+
+/* Character 8 (0x38):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character 9 (0x39):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7e,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character : (0x3a):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x00,
+
+/* Character ; (0x3b):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+
+/* Character < (0x3c):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+
+/* Character = (0x3d):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character > (0x3e):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0x00,
+0x00,
+
+/* Character ? (0x3f):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x0c,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character @ (0x40):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** **** |
+ |** **** |
+ |** **** |
+ |** *** |
+ |** |
+ | ****** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xde,
+0xde,
+0xde,
+0xdc,
+0xc0,
+0x7e,
+0x00,
+0x00,
+
+/* Character A (0x41):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character B (0x42):
+ ht=13, width=8
+ +--------+
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+
+/* Character C (0x43):
+ ht=13, width=8
+ +--------+
+ | |
+ | **** |
+ | ** ** |
+ |** * |
+ |** |
+ |** |
+ |** |
+ |** |
+ |** * |
+ | ** ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x3c,
+0x66,
+0xc2,
+0xc0,
+0xc0,
+0xc0,
+0xc0,
+0xc2,
+0x66,
+0x3c,
+0x00,
+0x00,
+
+/* Character D (0x44):
+ ht=13, width=8
+ +--------+
+ | |
+ |***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xf8,
+0x6c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x6c,
+0xf8,
+0x00,
+0x00,
+
+/* Character E (0x45):
+ ht=13, width=8
+ +--------+
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x66,
+0xfe,
+0x00,
+0x00,
+
+/* Character F (0x46):
+ ht=13, width=8
+ +--------+
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+
+/* Character G (0x47):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xce,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character H (0x48):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character I (0x49):
+ ht=13, width=8
+ +--------+
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+
+/* Character J (0x4a):
+ ht=13, width=8
+ +--------+
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | *** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0xd8,
+0xd8,
+0x70,
+0x00,
+0x00,
+
+/* Character K (0x4b):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |**** |
+ |**** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xcc,
+0xd8,
+0xf0,
+0xf0,
+0xd8,
+0xcc,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character L (0x4c):
+ ht=13, width=8
+ +--------+
+ | |
+ |**** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xf0,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x62,
+0x66,
+0xfe,
+0x00,
+0x00,
+
+/* Character M (0x4d):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |*** *** |
+ |*** *** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xee,
+0xee,
+0xfe,
+0xd6,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character N (0x4e):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |*** ** |
+ |*** ** |
+ |**** ** |
+ |** **** |
+ |** *** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xe6,
+0xe6,
+0xf6,
+0xde,
+0xce,
+0xce,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character O (0x4f):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character P (0x50):
+ ht=13, width=8
+ +--------+
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+
+/* Character Q (0x51):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ | ***** |
+ | ** |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0x7c,
+0x06,
+0x00,
+
+/* Character R (0x52):
+ ht=13, width=8
+ +--------+
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x78,
+0x6c,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+
+/* Character S (0x53):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ | *** |
+ | *** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0x70,
+0x1c,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character T (0x54):
+ ht=13, width=8
+ +--------+
+ | |
+ | ****** |
+ | * ** * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7e,
+0x5a,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+
+/* Character U (0x55):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character V (0x56):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+
+/* Character W (0x57):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ |*** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0xee,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character X (0x58):
+ ht=13, width=8
+ +--------+
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character Y (0x59):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+
+/* Character Z (0x5a):
+ ht=13, width=8
+ +--------+
+ | |
+ |******* |
+ |** ** |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** * |
+ |** ** |
+ |******* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xfe,
+0xc6,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc2,
+0xc6,
+0xfe,
+0x00,
+0x00,
+
+/* Character [ (0x5b):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x7c,
+0x00,
+0x00,
+
+/* Character \ (0x5c):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ |* |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | * |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x80,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x02,
+0x00,
+0x00,
+
+/* Character ] (0x5d):
+ ht=13, width=8
+ +--------+
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x7c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x7c,
+0x00,
+0x00,
+
+/* Character ^ (0x5e):
+ ht=13, width=8
+ +--------+
+ | * |
+ | *** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x10,
+0x38,
+0x6c,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character _ (0x5f):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |********|
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xff,
+
+/* Character ` (0x60):
+ ht=13, width=8
+ +--------+
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x18,
+0x18,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character a (0x61):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | **** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x78,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xdc,
+0x76,
+0x00,
+0x00,
+
+/* Character b (0x62):
+ ht=13, width=8
+ +--------+
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+
+/* Character c (0x63):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character d (0x64):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7e,
+0x00,
+0x00,
+
+/* Character e (0x65):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xfe,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character f (0x66):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x1c,
+0x36,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x78,
+0x00,
+0x00,
+
+/* Character g (0x67):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** *** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xce,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+
+/* Character h (0x68):
+ ht=13, width=8
+ +--------+
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+
+/* Character i (0x69):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x00,
+0x38,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+
+/* Character j (0x6a):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | **** |
+ +--------+ */
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0xcc,
+0xcc,
+0x78,
+
+/* Character k (0x6b):
+ ht=13, width=8
+ +--------+
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0xe0,
+0x60,
+0x60,
+0x66,
+0x66,
+0x6c,
+0x78,
+0x6c,
+0x66,
+0xe6,
+0x00,
+0x00,
+
+/* Character l (0x6c):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x1c,
+0x00,
+0x00,
+
+/* Character m (0x6d):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0xfe,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character n (0x6e):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x00,
+0x00,
+
+/* Character o (0x6f):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character p (0x70):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ |**** |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0xf0,
+
+/* Character q (0x71):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | **** |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7c,
+0x0c,
+0x0c,
+0x1e,
+
+/* Character r (0x72):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x60,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+
+/* Character s (0x73):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ | ***** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0x7c,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character t (0x74):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ | *** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x30,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x36,
+0x1c,
+0x00,
+0x00,
+
+/* Character u (0x75):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+
+/* Character v (0x76):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+
+/* Character w (0x77):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ | ** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0x6c,
+0x00,
+0x00,
+
+/* Character x (0x78):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0x00,
+0x00,
+
+/* Character y (0x79):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+
+/* Character z (0x7a):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ |******* |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x62,
+0xfe,
+0x00,
+0x00,
+
+/* Character { (0x7b):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x70,
+0x18,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x00,
+0x00,
+
+/* Character | (0x7c):
+ ht=13, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character } (0x7d):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x70,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x18,
+0x70,
+0x00,
+0x00,
+
+/* Character ~ (0x7e):
+ ht=13, width=8
+ +--------+
+ | |
+ | *** ** |
+ |** *** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x76,
+0xdc,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character  (0x7f):
+ ht=13, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | * |
+ | *** |
+ | *** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x10,
+0x38,
+0x38,
+0x6c,
+0x6c,
+0xfe,
+0x00,
+0x00,
+0x00,
+
+};
+#endif
+
+/* This table allows the font rendering engine (fbi_putchar() in fbi.c)
+ * to support some flexibility of spacing between and above/below
+ * characters.
+ */
+struct font font_styles[] = {
+ /* bitmap, width, height, above, below, between */
+#ifdef USE_FONT_8x16
+ { font8x16, 7, 16, 0, 0, 0 },
+ { font8x16, 8, 16, 0, 0, 0 },
+ { font8x16, 8, 16, 0, 0, 1 },
+ { font8x16, 8, 16, 0, 1, 0 },
+ { font8x16, 8, 16, 0, 1, 1 },
+ { font8x16, 8, 16, 1, 0, 0 },
+ { font8x16, 8, 16, 1, 0, 1 },
+ { font8x16, 8, 16, 1, 1, 0 },
+ { font8x16, 8, 16, 1, 1, 1 },
+#endif
+#ifdef USE_FONT_8x13
+ { font8x13, 7, 13, 0, 0, 0 },
+ { font8x13, 8, 13, 0, 0, 0 },
+ { font8x13, 8, 13, 0, 0, 1 },
+ { font8x13, 8, 13, 0, 1, 0 },
+ { font8x13, 8, 13, 0, 1, 1 },
+ { font8x13, 8, 13, 1, 0, 0 },
+ { font8x13, 8, 13, 1, 0, 1 },
+ { font8x13, 8, 13, 1, 1, 0 },
+ { font8x13, 8, 13, 1, 1, 1 },
+ { font8x13, 8, 13, 1, 2, 1 },
+#endif
+#ifdef USE_FONT_8x12
+ { font8x12, 8, 12, 0, 0, 0 },
+ { font8x12, 8, 12, 0, 0, 1 },
+ { font8x12, 8, 12, 0, 1, 0 },
+ { font8x12, 8, 12, 0, 1, 1 },
+ { font8x12, 8, 12, 1, 0, 0 },
+ { font8x12, 8, 12, 1, 0, 1 },
+ { font8x12, 8, 12, 1, 1, 0 },
+ { font8x12, 8, 12, 1, 1, 1 },
+#endif
+};
+
+int
+font_style_total(void)
+{
+ return(sizeof(font_styles)/sizeof(struct font));
+}
diff --git a/main/common/font.h b/main/common/font.h
new file mode 100755
index 0000000..c1fcd8f
--- /dev/null
+++ b/main/common/font.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * font.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+struct font {
+ char *bitmap; /* Pointer to font bitmap array. */
+ int width; /* Width of font in array. */
+ int height; /* Height of font in array. */
+ int above; /* Number of pixels of empty space above. */
+ int below; /* Number of pixels of empty space blow. */
+ int between; /* Number of pixels of separation between each char. */
+};
+
+extern char font8x12[];
+extern struct font font_styles[];
+extern int font_style_total(void);
+
+#define MAX_FONT_WIDTH 8
+#define MIN_FONT_WIDTH 8
+
+#define FONT_WHITE 0x00ffffff
+#define FONT_BLACK 0x00000000
+#define FONT_TRANSPARENT 0x01000000
+#define FONT_INVERT 0x02000000
+
+#define OPAQUE_BACKGROUND(x) ((x & FONT_TRANSPARENT) == 0)
diff --git a/main/common/gdb.c b/main/common/gdb.c
new file mode 100644
index 0000000..74b8b5e
--- /dev/null
+++ b/main/common/gdb.c
@@ -0,0 +1,686 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * gdb.c:
+ *
+ * The code in this file allows a gdb debugger on a host to connect to the
+ * monitor. It supports both serial and network (udp) connections.
+ * Note that this is only the cpu-independent portion of the GDB debug
+ * protocol. The following commands in gdb have been verified to work
+ * with this code:
+ *
+ * - target remote com1
+ * - target remote udp:135.222.140.68:1234
+ * - load and c
+ * - info registers
+ * - x/16x 0xff800000
+ * - print varname
+ *
+ *I'm sure other commands work, but these are the ones I've tested.
+ *
+ * This interface was written from scratch.
+ * References used were:
+ * Bill Gatliff's ESP article and a description of the GDB Remote
+ * Serial Protocol I found at:
+ * http://developer/apple.com/documentation/DeveloperTools/gdb/gdb/gdb_32.htm
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "endian.h"
+#include "cli.h"
+
+#if INCLUDE_GDB
+
+#include "gdbregs.c" /* CPU-specific register name table */
+
+#define REGTBL_SIZE (sizeof(gdb_regtbl)/sizeof(char *))
+
+#define GDBERR_NOHASH 1 /* no '#' in command */
+#define GDBERR_BADCSUM 2 /* bad checksum */
+#define GDBERR_GENERR 3 /* general confusion */
+#define GDBERR_BADXFMT 4 /* unexpected 'X' command format */
+#define GDBERR_RNUMOOR 5 /* register number out of range */
+#define GDBERR_NOSPACE 6 /* buffer not big enough for response */
+
+/* gdbIbuf[]:
+ * Input buffer used for storage of the incoming command from
+ * the gdb debugger.
+ */
+#if INCLUDE_ETHERNET
+static uchar gdbIbuf[512];
+#endif
+
+/* gdbRbuf[]:
+ * Response buffer used for the complete response destined
+ * for the gdb host.
+ */
+static uchar gdbRbuf[1024];
+static int gdbRlen;
+static void (*gdbContinueFptr)();
+
+/* gdbUdp:
+ * Set if the gdb interaction is via UDP, else zero.
+ * Obviously this code assumes there is no reentrancy to deal with.
+ */
+static int gdbUdp;
+
+/* gdbTrace():
+ * This is a function pointer that is loaded with either printf
+ * or Mtrace... Use printf if gdb is running via UDP; else use
+ * printf.
+ */
+static int (*gdbTrace)(char *, ...);
+
+/* gdb_response():
+ * Utility function used by the other response functions to format
+ * the complete response back to the gdb host. All interaction with
+ * the host is in ASCII. The response message is preceded by '+$'
+ * and and terminated with '#CC' where 'CC' is a checksum.
+ */
+int
+gdb_response(char *line)
+{
+ uchar csum, *resp;
+
+ csum = 0;
+ resp = gdbRbuf;
+ *resp++ = '$';
+ while(*line) {
+ csum += *line;
+ *resp++ = *line++;
+ }
+ resp += sprintf((char *)resp,"#%02x",csum);
+ *resp = 0;
+
+ /* If gdbUdp is clear, then we assume that the gdb host is tied
+ * to the target's serial port, so just use printf to send the
+ * response.
+ * If gdbUdp is set, then we assume the calling function will
+ * send the response (via ethernet).
+ */
+ if (!gdbUdp)
+ printf((char *)gdbRbuf);
+
+ gdbRlen = strlen((char *)gdbRbuf);
+
+ if (gdbRlen < 128)
+ gdbTrace("GDB_RSP: %s\n",gdbRbuf);
+ else
+ gdbTrace("GDB_RSP: BIG\n");
+
+ return(gdbRlen);
+}
+
+int
+gdb_ok(void)
+{
+ return(gdb_response("OK"));
+}
+
+int
+gdb_sig(int signal)
+{
+ char buf[8];
+
+ sprintf(buf,"S%02d",signal);
+ return(gdb_response(buf));
+}
+
+int
+gdb_err(int errno)
+{
+ char buf[8];
+
+ sprintf(buf,"E%02d",errno);
+ return(gdb_response(buf));
+}
+
+/* gdb_m():
+ * GDB memory read command...
+ * Incoming command format is...
+ *
+ * mADDR,LEN#CC
+ *
+ * where:
+ * 'm' is the "memory read" request
+ * 'ADDR' is the address from which the data is to be read
+ * 'LEN' is the number of bytes to be read
+ *
+ */
+int
+gdb_m(char *line)
+{
+ int len, i;
+ char *lp;
+ uchar *addr, *resp, buf[128];
+
+ addr = (uchar *)strtol(line+1,&lp,16);
+ len = (int)strtol(lp+1,0,16);
+ if (len) {
+ if (len*2 >= sizeof(buf)) {
+ gdb_err(GDBERR_NOSPACE);
+ }
+ else {
+ resp = buf;
+ for(i=0;i<len;i++,addr++)
+ resp += sprintf((char *)resp,"%02x",*addr);
+ gdb_response((char *)buf);
+ }
+ }
+ else
+ gdb_ok();
+ return(0);
+}
+
+/* gdb_M():
+ * GDB memory write command...
+ * Incoming command format is...
+ *
+ * MADDR,LEN:DATA#CC
+ *
+ * where:
+ * 'M' is the "memory read" request
+ * 'ADDR' is the address from which the data is to be read
+ * 'LEN' is the number of bytes to be read
+ * 'DATA' is the ascii data
+ *
+ * STATUS: This function has been tested with m68k-elf-gdb (xtools)
+ * and appears to work ok.
+ */
+int
+gdb_M(char *line)
+{
+ int len, i;
+ char *lp;
+ uchar *addr, buf[3];
+
+ addr = (uchar *)strtol(line+1,&lp,16);
+ len = (int)strtol(lp+1,&lp,16);
+ lp++;
+
+ buf[2] = 0;
+ for(i=0;i<len;i++) {
+ buf[0] = *lp++;
+ buf[1] = *lp++;
+ *addr++ = (uchar)strtol((char *)buf,0,16);
+ }
+ gdb_ok();
+ return(0);
+}
+
+/* gdb_X():
+ * Similar to gdb_M() except that the data is in binary.
+ * The characters '$', '#' and 0x7d are escaped using 0x7d.
+ */
+int
+gdb_X(char *line)
+{
+ int len, i;
+ char *lp;
+ uchar *addr;
+
+ addr = (uchar *)strtol(line+1,&lp,16);
+ len = (int)strtol(lp+1,&lp,16);
+ lp++;
+
+ for(i=0;i<len;i++) {
+ if ((*lp == 0x7d) &&
+ ((*(lp+1) == 0x03) || (*(lp+1) == 0x04) || (*(lp+1) == 0x5d))) {
+ *addr++ = *(lp+1) | 0x20;
+ lp += 2;
+ }
+ else
+ *addr++ = *lp++;
+ }
+
+ gdb_ok();
+ return(0);
+}
+
+/* gdb_q():
+ * Query. Not sure what this is for, but according to Gatliff's
+ * article, just do it...
+ */
+int
+gdb_q(char *line)
+{
+ line++;
+
+ if (strncmp(line,"Offsets",7) == 0)
+ return(gdb_response("Text=0;Data=0;Bss=0"));
+ else
+ return(gdb_ok());
+}
+
+/* gdb_g():
+ * Get all registers.
+ * GDB at the host expects to see a buffer of ASCII-coded hex values
+ * with each register being 8-bytes (forming one 32-bit value).
+ * The order of these registers is defined by the table included
+ * in the file gdbregs.c above.
+ */
+
+int
+gdb_g(char *line)
+{
+ int i;
+ ulong reg;
+ char *resp, buf[(REGTBL_SIZE * 8) + 1];
+
+ resp = buf;
+ for(i=0;i<REGTBL_SIZE;i++) {
+ if (gdb_regtbl[i] != 0)
+ getreg(gdb_regtbl[i],&reg);
+ else
+ reg = 0;
+ self_ecl(reg);
+ resp += sprintf(resp,"%08lx",reg);
+ }
+ return(gdb_response(buf));
+}
+
+/* gdb_P():
+ * Store to a register.
+ */
+int
+gdb_P(char *line)
+{
+ char *lp;
+ int rnum;
+ ulong rval;
+
+ line++;
+ rnum = strtol(line,&lp,16);
+ if (rnum >= REGTBL_SIZE) {
+ gdb_err(GDBERR_RNUMOOR);
+ return(-1);
+ }
+ lp++;
+ rval = strtol(lp,0,16);
+ self_ecl(rval);
+ putreg(gdb_regtbl[rnum],rval);
+
+ gdb_ok();
+ return(0);
+}
+
+/* gdb_c():
+ * This is the function that is called as a result of the 'c' (continue)
+ * command.
+ */
+int
+gdb_c(char *line)
+{
+ ulong addr;
+ void (*func)();
+
+ line++;
+ if (*line == '#')
+ getreg(CPU_PC_REG,&addr);
+ else
+ addr = strtol(line,0,16);
+
+ func = (void(*)())addr;
+ func();
+ return(0);
+}
+
+/* gdb_cmd():
+ * First function called out of the monitor's command interpreter. It
+ * does a basic syntax verification and then passes parameters to the
+ * appropriate handler above.
+ * Incoming syntax is
+ *
+ * $ CMD # CSUM (of CMD)
+ *
+ * where:
+ * $ is the ascii '$' character (0x24)
+ * # is the ascii '#' character (0x23)
+ * CMD is some command line consisting of a command and arguments
+ * CSUM is the checksum of the characters in CMD
+ *
+ * for example:
+ *
+ * $m4015bc,2#5a
+ *
+ * Returns...
+ * 0 if command is not processed;
+ * 1 if command is processed;
+ * -1 if command is processed but has an error;
+ *
+ * If this code detects an error, then send an error code back to GDB.
+ * According to the article, there are no defined error codes in GDB so
+ * we will use the following...
+ * 1 indicates a missing '#' at the end of the incoming cmd string.
+ * 2 indicates a bad checksum calculation.
+ * 3 indicates some command processing error.
+ * 4 indicates bad 'X' command parsing.
+ */
+int
+gdb_cmd(uchar *line)
+{
+ char *comma, *colon, *cp, *bp, buf[32];
+ int len, clen, err, i;
+ uchar mycsum, incsum;
+
+ gdbContinueFptr = (void(*)())0;
+
+ /* If the command is 'X', then we have to treat it "special" because
+ * it contains binary data...
+ */
+ if (line[1] == 'X') {
+ comma = strchr((char *)line,',');
+ colon = strchr((char *)line,':');
+ if ((comma) && (colon)) {
+ bp = buf;
+ cp = (char *)line;
+ while(cp <= colon)
+ *bp++ = *cp++;
+ *bp = 0;
+ gdbTrace("GDB_CMD: '%s'\n",buf);
+ }
+ else {
+ gdbTrace("GDB_CMD: 'X'\n");
+ gdb_err(GDBERR_BADXFMT); /* Unexpected 'X' command format */
+ }
+ }
+ else if (line[0] == 0x03) {
+ gdbTrace("GDB_CTRLC\n");
+ gdb_sig(2);
+ return(1);
+ }
+ else {
+ gdbTrace("GDB_CMD: '%s'\n",line);
+ len = strlen((char *)line);
+
+ if (line[len-3] != '#') {
+ gdb_err(GDBERR_NOHASH); /* Missing ending '#' */
+ return(-1);
+ }
+
+ clen = len - 3;
+ mycsum = 0;
+ for(i=1;i<clen;i++)
+ mycsum += line[i];
+
+ incsum = (uchar)strtol((char *)line+len-2,(char **)0,16);
+ if (mycsum != incsum) {
+ gdb_err(GDBERR_BADCSUM); /* Checksum failure */
+ return(-1);
+ }
+ }
+
+ err = 0;
+ line++;
+ switch(*line) {
+ case 'm': /* Memory read */
+ err = gdb_m((char *)line);
+ break;
+ case 'M': /* Memory write (Ascii-coded-hex) */
+ err = gdb_M((char *)line);
+ break;
+ case 'X': /* Memory write (Binary) */
+ err = gdb_X((char *)line);
+ break;
+ case 's': /* Step */
+ gdb_response("S05");
+ break;
+ case 'c': /* Continue */
+ gdb_c((char *)line);
+ break;
+ case '?': /* Last signal */
+ gdb_response("S05");
+ break;
+ case 'g': /* get all registers */
+ gdb_g((char *)line);
+ break;
+ case 'q': /* Query */
+ gdb_q((char *)line);
+ break;
+ case 'P': /* PRR=HHHHHHHH... reg*/
+ gdb_P((char *)line);
+ break;
+ case 'H': /* Thread */
+ gdb_ok();
+ break;
+ case 'k': /* Quit */
+ gdb_ok();
+ break;
+ default: /* Unknown... return empty response. */
+ gdb_response("");
+ break;
+ }
+ if (err) {
+ gdb_err(GDBERR_GENERR); /* Command processing error */
+ }
+ return(1);
+}
+
+/* Gdb():
+ * This is the command at the CLI that allows the monitor to connect
+ * to a gdb debugger via the serial port. It currently assumes that
+ * the console port is the same port as is being used for the gdb
+ * connection. Eventually this needs to be modified to provide an
+ * option for the gdb protocol to run on some serial port other than
+ * the console.
+ *
+ * The connection command in gdb to connect to via serial port (PC)
+ * is:
+ * target remote com1
+ */
+char *GdbHelp[] = {
+ "Enter gdb mode",
+ "(no options)",
+ 0,
+};
+
+int
+Gdb(int argc, char *argv)
+{
+ int state, quit;
+ uchar *lp, c;
+ static uchar line[1024];
+
+ printf("Entering GDB mode, to exit manually type: '$k#00'\n");
+
+ lp = (uchar *)0;
+ quit = 0;
+ state = 0;
+ gdbUdp = 0;
+ gdbTrace = Mtrace;
+ while(!quit) {
+ c = getchar();
+ switch(state) {
+ case 0: /* Wait for start of message */
+ if (c == '$') {
+ lp = line;
+ *lp++ = c;
+ state = 1;
+ }
+ break;
+ case 1:
+ *lp++ = c; /* This is the command character */
+ state = 2;
+ break;
+ case 2:
+ if (c == '#') {
+ state = 3;
+ *lp++ = c;
+ }
+ else {
+ *lp++ = c;
+ }
+ break;
+ case 3:
+ *lp++ = c;
+ state = 4;
+ break;
+ case 4:
+ *lp++ = c;
+ *lp = 0;
+ state = 0;
+ if (line[1] == 'k')
+ quit = 1;
+ gdb_cmd(line);
+ break;
+ default:
+ break;
+ }
+ }
+ putchar('\n');
+ return(CMD_SUCCESS);
+}
+
+#if INCLUDE_ETHERNET
+/* processGDB():
+ * This is the function that allows a remote gdb host to connect to
+ * the monitor with gdb at the udp level. The connection command in
+ * gdb to do this is:
+ *
+ * target remote udp:TARGET_IP:TARGET_PORT
+ */
+int
+processGDB(struct ether_header *ehdr,ushort size)
+{
+ char *gdbp;
+ struct ip *ihdr, *ti, *ri;
+ struct Udphdr *uhdr, *tu, *ru;
+ struct ether_header *te;
+
+ /* If SHOW_GDB is set (via ether -vg), then we dump the trace to
+ * the console; otherwise, we use mtrace.
+ */
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_GDB)
+ gdbTrace = printf;
+ else
+#endif
+ gdbTrace = Mtrace;
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
+ gdbp = (char *)(uhdr + 1);
+ size = ecs(uhdr->uh_ulen) - sizeof(struct Udphdr);
+
+ /* Check for ACK/NAK here:
+ */
+ if (size == 1) {
+ if ((*gdbp == '+') || (*gdbp == '-')) {
+ gdbTrace("GDB_%s\n",*gdbp == '+' ? "ACK" : "NAK");
+ return(0);
+ }
+ }
+
+ /* Copy the incoming udp payload (the gdb command) to gdbIbuf[]
+ * and NULL terminate it...
+ */
+ memcpy((char *)gdbIbuf,(char *)gdbp,size);
+ gdbIbuf[size] = 0;
+
+ /* Now that we've stored away the GDB command request, we
+ * initially respond with the GDB acknowledgement ('+')...
+ */
+ te = EtherCopy(ehdr);
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (ehdr + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ecs((1 + (sizeof(struct ip) + sizeof(struct Udphdr))));
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + 1));
+ gdbp = (char *)(tu+1);
+ *gdbp = '+';
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) +
+ sizeof(struct Udphdr) + 1);
+
+ /* Wrap the processing of the incoming packet with a set/clear
+ * of the gdbUdp flag so that the other gdb code can act
+ * accordingly.
+ */
+ gdbUdp = 1;
+ if (gdb_cmd(gdbIbuf) == 0) {
+ gdbUdp = 0;
+ return(0);
+ }
+ gdbUdp = 0;
+
+ /* Add 1 to the gdbRlen to include the NULL termination.
+ */
+ gdbRlen++;
+
+
+ /* The second respons is only done if gdb_cmd returns non-zero.
+ * It is the response to the gdb command issued by the debugger
+ * on the host.
+ */
+ te = EtherCopy(ehdr);
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (ehdr + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ecs((gdbRlen + (sizeof(struct ip) + sizeof(struct Udphdr))));
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr,
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + gdbRlen));
+ memcpy((char *)(tu+1),(char *)gdbRbuf,gdbRlen);
+
+ ipChksum(ti); /* Compute checksum of ip hdr */
+ udpChksum(ti); /* Compute UDP checksum */
+
+ sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) +
+ sizeof(struct Udphdr) + gdbRlen);
+
+ return(1);
+}
+#endif
+
+#endif
+
diff --git a/main/common/genlib.h b/main/common/genlib.h
new file mode 100644
index 0000000..c0338cd
--- /dev/null
+++ b/main/common/genlib.h
@@ -0,0 +1,269 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * genlib.h:
+ *
+ * Header file for functions in genlib.c (and some others).
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _GENLIB_H_
+#define _GENLIB_H_
+
+#include <stdarg.h>
+
+/* Some compilers consider sizeof() to be unsigned... */
+#define sizeof (int)sizeof
+
+extern int optind;
+extern char *optarg;
+
+extern int abs(int);
+extern int atoi(char *);
+extern int memcmp(char *, char *, int);
+extern int strcmp(char *, char *);
+extern int strcasecmp(char *, char *);
+extern int strncmp(char *, char *, int);
+extern int strlen(char *);
+extern int strspn(char *, char *);
+extern int strcspn(char *, char *);
+extern int getopt(int,char **,char *);
+extern int s_memcpy(char *, char *, int, int, int);
+extern int s_memset(unsigned char *,unsigned char,int,int,int);
+extern char *memccpy(char *, char *, int, int);
+extern char *memchr(char *, char, int);
+extern char *memcpy(char *, char *, int);
+extern void bcopy(char *, char *, int);
+extern char *memset(char *, char, int);
+extern char *strcat(char *, char *);
+extern char *strchr(char *, char);
+extern char *strstr(char *, char *);
+extern char *strcpy(char *, char *);
+extern char *strncat(char *, char *, int);
+extern char *strncpy(char *, char *, int);
+extern char *strpbrk(char *, char *);
+extern char *strrchr(char *, char);
+extern char *strtok(char *, char *);
+extern char *strtolower(char *string);
+extern char *strtoupper(char *string);
+extern long strtol(char *, char **, int);
+extern unsigned short swap2(unsigned short);
+extern unsigned long swap4(unsigned long);
+extern unsigned long strtoul(char *, char **, int);
+extern void getoptinit(void);
+extern void prstring(char *);
+extern void prlong(long);
+extern long lceil(long n, long to);
+extern unsigned long ulceil(unsigned long n, unsigned long to);
+
+/* Included here, but not in genlib.c: */
+extern int target_gotachar(void), gotachar(void);
+extern int target_getchar(void), getchar(void);
+extern int target_putchar(char), putchar(char);
+extern int target_console_empty(void);
+extern int AddrToSym(int,unsigned long,char *,unsigned long *);
+extern int printf(char *, ...);
+extern int sprintf(char *, char *, ...);
+extern int snprintf(char *, int, char *, ...);
+extern int vsnprintf(char *, int, char *, va_list);
+extern int cprintf(char *, ...);
+extern int getbytes(char *,int,int);
+extern int getbytes_t(char *,int,int);
+extern int putbytes(char *,int);
+extern int getUsrLvl(void);
+extern int setenv(char *,char *);
+extern int shell_sprintf(char *,char *fmt,...);
+extern int getline(char *,int,int);
+extern int getline_t(char *,int,int);
+extern int getline_p(char *,int,int,char *);
+extern int getfullline(char *buf,int max,int ledit,int timeout,\
+ char *prefill, int echo);
+extern int stkchk(char *);
+extern int inRange(char *,int);
+extern int More(void);
+extern int validPassword(char *,int);
+extern int newPasswordFile(void);
+extern int extValidPassword(char *,int);
+extern int setCmdUlvl(char *,int);
+extern int askuser(char *);
+extern int hitakey(void);
+extern int getreg(char *,unsigned long *);
+extern int putreg(char *,unsigned long);
+extern int putargv(int,char *);
+extern int addrtosector(unsigned char *,int *,int *,unsigned char **);
+extern int AppFlashWrite(unsigned char *,unsigned char *,long);
+extern int AppFlashErase(int);
+extern int flushDcache(char *,int);
+extern int invalidateIcache(char *,int);
+extern int pollConsole(char *);
+extern int sectortoaddr(int,int *,unsigned char **);
+extern int sectorProtect(char *,int);
+extern int FlashInit(void);
+extern int cacheInit(void);
+extern int pioget(char,int);
+extern int extendHeap(char *,int);
+extern int decompress(char *,int,char *);
+extern int RedirectionCheck(char *);
+extern int docommand(char *, int);
+extern int SymFileFd(int);
+extern int ShellVarInit(void);
+extern int showDate(int);
+extern int inUmonBssSpace(char *,char *);
+extern int passwordFileExists(void);
+extern int Mtrace(char *, ...);
+extern int monWatchDog(void);
+extern int ConsoleBaudSet(int);
+extern int ChangeConsoleBaudrate(int);
+extern int TextInRam(void);
+extern int uMonInRam(void);
+extern long portCmd(int, void *);
+extern unsigned short xcrc16(unsigned char *buffer,unsigned long nbytes);
+extern unsigned long crc32(unsigned char *,unsigned long);
+extern unsigned long intsoff(void);
+extern unsigned long getAppRamStart(void);
+extern unsigned long assign_handler(long, unsigned long, unsigned long);
+extern char *line_edit(char *);
+#ifndef MALLOC_DEBUG
+extern char *malloc(int);
+extern char *realloc(char *,int);
+#endif
+extern char *getenvp(void);
+extern char *getenv(char *);
+extern char *getpass(char *,char *,int,int);
+extern char *getsym(char *,char *,int);
+extern char *monVersion(void);
+extern char *monBuilt(void);
+extern char *ExceptionType2String(int);
+extern char *shellsym_chk(char,char *,int *,char *,int);
+extern void stkusage(void);
+extern void target_reset(void);
+extern void flush_console_out(void);
+extern void flush_console_in(void);
+extern void initCPUio(void);
+extern void historyinit(void);
+extern void AppWarmStart(unsigned long mask);
+extern void MtraceInit(char *,int);
+extern void monrestart(int);
+extern void historylog(char *);
+extern void free(void *);
+extern void puts(char *);
+extern void putstr(char *);
+extern void MonitorBuiltEnvSet(void);
+extern void writeprompt(void);
+extern void intsrestore(unsigned long);
+extern void prascii(unsigned char *,int);
+extern void cacheInitForTarget(void);
+extern void exceptionAutoRestart(int);
+extern void clrTmpMaxUsrLvl(int (*)(void));
+extern void *setTmpMaxUsrLvl(void);
+extern void rawon(void), rawoff(void);
+extern void monHeader(int);
+extern void mstatshowcom(void);
+extern void CommandLoop(void);
+extern void flushRegtbl(void);
+
+extern void showregs(void), reginit(void);
+extern void initUsrLvl(int);
+extern void warmstart(int);
+extern void coldstart(void);
+extern void InitRemoteIO(void);
+extern void appexit(int);
+extern void pioset(char,int);
+extern void pioclr(char,int);
+extern void getargv(int *argc, char ***argv);
+extern void init0(void), init1(void), init2(void), init3(void);
+extern void EnableBreakInterrupt(void);
+extern void DisableBreakInterrupt(void);
+extern void ctxMON(void), ctxAPP(void);
+extern void printMem(unsigned char *,int,int);
+extern void monDelay(int);
+extern void ticktock(void);
+extern void atinit(void);
+extern void umonBssInit(void);
+extern void ConsoleBaudEnvSet(void);
+extern void console_echo(int);
+extern void LowerFlashProtectWindow(void);
+#if INCLUDE_REDIRECT
+extern void RedirectCharacter(char);
+extern void RedirectionCmdDone(void);
+#else
+#define RedirectCharacter(c)
+#define RedirectionCmdDone()
+#endif
+
+extern double atof(const char *str);
+extern double strtod(const char *str, char **endptr);
+
+extern unsigned long MonStack[];
+extern const unsigned long crc32tab[];
+extern unsigned short xcrc16tab[];
+extern char *Mtracebuf;
+extern char ApplicationInfo[];
+extern unsigned long ExceptionAddr, LoopsPerMillisecond;
+extern unsigned long APPLICATION_RAMSTART, BOOTROM_BASE;
+extern int ConsoleDevice;
+extern int ConsoleBaudRate;
+extern int StateOfMonitor, AppExitStatus, ExceptionType;
+extern int bss_start, bss_end, boot_base;
+extern int (*remoterawon)(void), (*remoterawoff)(void);
+extern int (*remoteputchar)(int), (*remotegetchar)(void);
+extern int (*remotegotachar)(void);
+extern int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *,int);
+extern int (*extgetUsrLvl)(void);
+extern int (*moncomptr)(int,void *, void *, void *);
+
+#define STACK_PREINIT_VAL 0x63636363
+
+/* If the watchdog macro is defined, then we also define the
+ * WATCHDOG_ENABLED macro so that code can use #ifdef WATCHDOG_ENABLED
+ * or simply insert WATCHDOG_MACRO inline...
+ * This eliminates the need for the ifdef wrapper if no other code is
+ * included with the macro.
+ */
+#ifdef WATCHDOG_MACRO
+extern int (*remoteWatchDog)(void);
+#define WATCHDOG_ENABLED
+#else
+#define WATCHDOG_MACRO
+#endif
+
+#endif
+
+#ifndef HUGE_VAL
+#define HUGE_VAL (__builtin_huge_val());
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef struct {
+ int quot;
+ int rem;
+} div_t;
+
+typedef struct {
+ long int quot;
+ long int rem;
+} ldiv_t;
+
+extern ldiv_t ldiv(long,long);
+extern div_t div(int,int);
diff --git a/main/common/i2c.c b/main/common/i2c.c
new file mode 100644
index 0000000..3982fb0
--- /dev/null
+++ b/main/common/i2c.c
@@ -0,0 +1,159 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * i2c.c:
+ *
+ * This file contains all of the generic code to support a target
+ * with one or more I-Squared-C interface masters.
+ * It assumes that somewhere in target-specific space there are three
+ * i2c interface functions: i2cRead(), i2cWrite() and i2cCtrl().
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cli.h"
+#include "i2c.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+int i2cVerbose;
+
+char *I2cHelp[] = {
+ "I-Squared-C Interface Access",
+ "[options] {init | show | read addr len | write addr data}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -b burst",
+ " -i{##} interface",
+ " -w{data} pre-write data as part of read (uses repeated start)",
+ " -v verbose",
+#endif
+ 0,
+};
+
+int
+I2cCmd(int argc, char *argv[])
+{
+ char *next;
+ uchar buf[256];
+ int i, wtot, opt, interface, len, rslt, addr, burst, ret, rwctrl;
+
+ rslt = 0;
+ wtot = 0;
+ burst = 0;
+ rwctrl = 0;
+ interface = 0;
+ i2cVerbose = 0;
+ ret = CMD_SUCCESS;
+ while ((opt=getopt(argc,argv,"bi:vw:")) != -1) {
+ switch(opt) {
+ case 'i':
+ interface = atoi(optarg);
+ break;
+ case 'b':
+ burst = 1; /* Do multiple accesses within one START/STOP */
+ break;
+ case 'w': /* Pre-write in a read */
+ burst = 1;
+ rwctrl = REPEATED_START;
+ for(wtot=1;wtot<sizeof(buf);wtot++) {
+ buf[wtot] = (uchar)strtol(optarg,&next,0);
+ if (*next == ',')
+ optarg = next+1;
+ else
+ break;
+ }
+ buf[0] = wtot;
+ break;
+ case 'v':
+ i2cVerbose = 1;
+ break;
+ default:
+ return(CMD_FAILURE);
+ }
+ }
+
+ if (argc < (optind+1))
+ return(CMD_PARAM_ERROR);
+
+ if (strcmp(argv[optind],"read") == 0) {
+ if (argc != (optind+3))
+ return(CMD_PARAM_ERROR);
+ addr = strtol(argv[optind+1],0,0);
+ len = strtol(argv[optind+2],0,0);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ if (burst) {
+ addr |= rwctrl;
+ rslt = i2cRead(interface,addr,buf,len);
+ }
+ else {
+ for(i=0;i<len;i++) {
+ rslt = i2cRead(interface,addr,buf+i,1);
+ if (rslt < 0)
+ break;
+ }
+ }
+ if (rslt < 0) {
+ printf("i2cRead = %d\n",rslt);
+ ret = CMD_FAILURE;
+ }
+ else
+ printMem(buf,len,1);
+ }
+ else if (strcmp(argv[optind],"write") == 0) {
+ if (rwctrl == REPEATED_START) {
+ printf("-w applies to read only\n");
+ return(CMD_FAILURE);
+ }
+ if (argc < (optind+3))
+ return(CMD_PARAM_ERROR);
+ addr = strtol(argv[optind+1],0,0);
+ for(len=0,i=optind+2;i<argc;i++,len++)
+ buf[len] = (uchar)strtol(argv[i],0,0);
+
+ if (burst) {
+ rslt = i2cWrite(interface,addr,buf,len);
+ }
+ else {
+ for(i=0;i<len;i++) {
+ rslt = i2cWrite(interface,addr,buf+i,1);
+ if (rslt < 0)
+ break;
+ }
+ }
+ if (rslt < 0) {
+ printf("i2cWrite = %d\n",rslt);
+ ret = CMD_FAILURE;
+ }
+ }
+ else if (strcmp(argv[optind],"init") == 0) {
+ i2cCtrl(interface,I2CCTRL_INIT,0,0);
+ }
+ else if (strcmp(argv[optind],"show") == 0) {
+ i2cCtrl(interface,I2CCTRL_SHOW,0,0);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ i2cVerbose = 0;
+ return(ret);
+}
diff --git a/main/common/i2c.h b/main/common/i2c.h
new file mode 100644
index 0000000..e5f0f17
--- /dev/null
+++ b/main/common/i2c.h
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * i2c.h:
+ *
+ * Header for I-Squared-C code.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _I2C_H_
+#define _I2C_H_
+
+extern int i2cVerbose;
+
+/********************************************************************
+ *
+ * Commands used by i2cCtrl():
+ */
+#define I2CCTRL_INIT 1
+#define I2CCTRL_SHOW 2
+#define I2CCTRL_START 3 /* Send START condition */
+#define I2CCTRL_STOP 4 /* Send STOP condition */
+#define I2CCTRL_WADD 5 /* Send Write address */
+#define I2CCTRL_RADD 6 /* Send Read address */
+#define I2CCTRL_RDAT 7 /* Read data */
+#define I2CCTRL_WDAT 8 /* Write data */
+#define I2CCTRL_SACK 9 /* Send ACK */
+#define I2CCTRL_WACK 10 /* WaitFor ACK */
+
+/********************************************************************
+ *
+ * Upper bits of the bigaddr integer used for special case read/write
+ */
+#define REPEATED_START 0x40000000
+#define OMIT_STOP 0x20000000
+
+/********************************************************************
+ *
+ * Functions that must be provided from some target-specific code.
+ */
+
+
+/* i2cCtrl()
+ * Parameters:
+ * int interface-
+ * This parameter supports the case where the target hardware has more
+ * than one i2c controller. The interface number would correspond to
+ * one of potentially several different controllers.
+ * int cmd-
+ * Command to be carried out by the control function.
+ * ulong arg1-
+ * First command-specific argument.
+ * ulong arg2-
+ * Second command-specific argument.
+ */
+extern int i2cCtrl(int interface,int cmd,unsigned long arg1,unsigned long arg2);
+
+/* i2cRead()
+ * Parameters:
+ * int interface-
+ * See description under i2cCtrl.
+ * int bigaddr-
+ * The device address on the I2C bus. Referred to here as "big" because
+ * it is an "int" so it supports 10-bit addresses (if needed).
+ * uchar *data-
+ * Pointer to the data buffer into which the data is to be placed.
+ * int len-
+ * Number of bytes to be read from the I2C device. This must not be
+ * larger than the size of the data buffer.
+ * Return:
+ * int
+ * The function should return the number of bytes read. If everything
+ * went well, then the return value should equal the len parameter.
+ * Negative represents some failure.
+ */
+extern int i2cRead(int interface,int bigaddr,unsigned char *data,int len);
+
+/* i2cWrite()
+ * Parameters:
+ * int interface-
+ * See description under i2cCtrl.
+ * int bigaddr-
+ * See description under i2cRead.
+ * uchar *data-
+ * Buffer from which the data is to be taken and put into the specified
+ * I2C device.
+ * int len-
+ * Number of bytes to be written.
+ * Return:
+ * int
+ * The function should return the number of bytes written. If everything
+ * went well, then the return value should equal the len parameter.
+ * Negative represents some failure.
+ */
+extern int i2cWrite(int interface,int bigaddr,unsigned char *data,int len);
+
+/* i2cShow()
+ * Parameters:
+ * int interface-
+ * See description under i2cCtrl.
+ * Return:
+ * void
+ * The function should be part of target-specific code that simply
+ * prints out a list of the device names and their address on the
+ * I-Squared-C bus of the specfied interface.
+ */
+extern void i2cShow(int interface);
+
+#endif
diff --git a/main/common/icmp.c b/main/common/icmp.c
new file mode 100644
index 0000000..51b2c5a
--- /dev/null
+++ b/main/common/icmp.c
@@ -0,0 +1,646 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * icmp.c:
+ *
+ * Support some basic ICMP stuff.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+
+#if INCLUDE_ETHERNET
+#include "endian.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "timer.h"
+
+#if INCLUDE_ICMP
+
+/* To reduce uMon footprint size, INCLUDE_ICMPTIME can be set to 0 in
+ * config.h if necessary...
+ */
+#ifndef INCLUDE_ICMPTIME
+#define INCLUDE_ICMPTIME 1
+#endif
+
+#define MSECS_PER_HOUR 3600000
+#define MSECS_PER_MINUTE 60000
+#define MSECS_PER_SECOND 1000
+
+#define ICMP_TIME_ID 0x1111 /* made these up. */
+#define ICMP_ECHO_ID 0x2222
+#define ICMP_ECHO_DATASIZE 26
+
+#if INCLUDE_ICMPTIME
+static ulong ICMPTimeStamp;
+#endif
+
+static int CheckSrvrResolution;
+ushort ICMPEchoReplyId, ICMPSeqNoRcvd;
+int SendICMPRequest(uchar,uchar *,uchar *,ulong,ushort);
+
+int SendEchoResp(struct ether_header *);
+
+/* Destination unreachable codes: (3rd Edition Comer pg 129) */
+char *IcmpDestUnreachableCode[] = {
+ "Network unreachable",
+ "Host unreachable",
+ "Protocol unreachable",
+ "Port unreachable",
+ "Fragmentation needed and DF set",
+ "Source route failed",
+ "???",
+};
+
+char *IcmpHelp[] = {
+ "ICMP interface",
+ "-[c:d:f:rs:t:v:] {operation} [args]",
+#if INCLUDE_VERBOSEHELP
+ "Options...",
+ " -c {#} echo count",
+ " -s {#} size of icmp-echo packet",
+ " -t {#} timeout (msec) to wait for response (default=2000)",
+ " -v {var} load result in shellvar 'var'",
+#if INCLUDE_ICMPTIME
+ " -d {#} delta (hours) relative to GMT",
+ " -f {x|d} hex or decimal output (default is ascii)",
+ " -r check server resolution",
+ "Operations...",
+ " time {IP}",
+ " echo {IP}",
+ "Notes...",
+ " If '.ns' is appended to time, then time is non-standard.",
+ " The 'dfr' options are used by time, options 'cs' are used by echo.",
+#endif
+#endif
+ 0,
+};
+
+int
+Icmp(int argc,char *argv[])
+{
+ ushort seqno;
+ long size;
+ struct elapsed_tmr tmr;
+ int opt, count, timeout;
+ uchar binip[8], binenet[8];
+ char *varname, *operation, *ipadd;
+#if INCLUDE_ICMPTIME
+ uchar buf[32];
+ char *nonstandard = "", format='a';
+ int timestamp, hour, min, sec, gmt_delta=0;
+#endif
+
+ size = 0;
+ count = 1;
+ timeout = 2000;
+ varname = (char *)0;
+ CheckSrvrResolution = 0;
+
+ while ((opt=getopt(argc,argv,"c:d:f:rs:t:v:")) != -1) {
+ switch(opt) {
+ case 'c': /* count used by ping */
+ count = strtol(optarg,(char **)0,0);
+ break;
+#if INCLUDE_ICMPTIME
+ case 'd': /* difference between this time zone and Greenwich */
+ gmt_delta = strtol(optarg,(char **)0,0);
+ break;
+ case 'f':
+ format = *optarg;
+ break;
+ case 'r':
+ CheckSrvrResolution = 1;
+ break;
+#endif
+ case 's':
+ size = strtol(optarg,(char **)0,0);
+ break;
+ case 't':
+ timeout = strtol(optarg,(char **)0,0);
+ break;
+ case 'v':
+ varname = optarg;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc == optind)
+ return(CMD_PARAM_ERROR);
+
+ operation = argv[optind];
+ ipadd = argv[optind+1];
+
+ /* If time or echo, do the common up-front stuff here... */
+ if (!strcmp(operation,"time") || !strcmp(operation,"echo")) {
+ if (argc != optind + 2)
+ return(CMD_PARAM_ERROR);
+
+ /* Convert IP address to binary: */
+ if (IpToBin(ipadd,binip) < 0)
+ return(CMD_SUCCESS);
+ }
+
+#if INCLUDE_ICMPTIME
+ if (!strcmp(operation, "time")) {
+
+ /* Get the ethernet address for the IP: */
+ if (!ArpEther(binip,binenet,0)) {
+ printf("ARP failed for %s\n",ipadd);
+ return(CMD_FAILURE);
+ }
+
+ ICMPTimeStamp = INVALID_TIMESTAMP;
+ SendICMPRequest(ICMP_TIMEREQUEST,binip,binenet,0,0);
+
+ /* Limit the amount of time waiting for a response... */
+ startElapsedTimer(&tmr,timeout);
+ while(msecElapsed(&tmr)) {
+ pollethernet();
+ if (ICMPTimeStamp != INVALID_TIMESTAMP)
+ break;
+ }
+ if (ELAPSED_TIMEOUT(&tmr)) {
+ printf("No response\n");
+ return(CMD_FAILURE);
+ }
+
+ if (ICMPTimeStamp & NONSTANDARD_TIMESTAMP) {
+ ICMPTimeStamp &= ~NONSTANDARD_TIMESTAMP;
+ nonstandard = ".ns";
+ }
+
+ if (format == 'a') {
+ timestamp = ICMPTimeStamp + (gmt_delta*MSECS_PER_HOUR);
+ hour = timestamp/MSECS_PER_HOUR;
+ timestamp -= hour*MSECS_PER_HOUR;
+ min = timestamp/MSECS_PER_MINUTE;
+ timestamp -= min*MSECS_PER_MINUTE;
+ sec = timestamp/MSECS_PER_SECOND;
+ timestamp -= sec*MSECS_PER_SECOND;
+ sprintf((char *)buf,"%02d:%02d:%02d.%03d%s",hour,min,sec,timestamp,
+ nonstandard);
+ }
+ else if (format == 'x')
+ sprintf((char *)buf,"0x%lx%s",ICMPTimeStamp,nonstandard);
+ else if (format == 'd')
+ sprintf((char *)buf,"%ld%s",ICMPTimeStamp,nonstandard);
+ else
+ return(CMD_PARAM_ERROR);
+ if (varname)
+ setenv(varname,(char *)buf);
+ else if (!CheckSrvrResolution)
+ printf("%s\n",buf);
+ CheckSrvrResolution = 0;
+ }
+ else
+#endif
+ if (!strcmp(operation, "echo")) {
+ seqno = 0;
+ while (count-- > 0) {
+
+ /* Is this a self-ping? */
+ if (memcmp((char *)binip,(char *)BinIpAddr,4) == 0) {
+ printf("Yes, I am alive!\n");
+ break;
+ }
+ /* Get the ethernet address for the IP: */
+ if (!ArpEther(binip,binenet,0)) {
+ printf("ARP failed for %s\n",ipadd);
+ if (varname)
+ setenv(varname,"NOANSWER");
+ continue;
+ }
+
+ ICMPEchoReplyId = 0;
+ SendICMPRequest(ICMP_ECHOREQUEST,binip,binenet,size,seqno);
+
+ /* Limit the amount of time waiting for a response... */
+ startElapsedTimer(&tmr,timeout);
+ while(!msecElapsed(&tmr)) {
+ pollethernet();
+ if (ICMPEchoReplyId == ICMP_ECHO_ID)
+ break;
+ }
+
+ if (ELAPSED_TIMEOUT(&tmr)) {
+ printf("no answer from %s\n",ipadd);
+ if (varname)
+ setenv(varname,"NOANSWER");
+ }
+ else {
+ printf("%s is alive",ipadd);
+ if (count) {
+ printf(" icmp_seq=%d",ICMPSeqNoRcvd);
+ startElapsedTimer(&tmr,timeout);
+ while(!msecElapsed(&tmr))
+ pollethernet();
+ seqno++;
+ }
+ if (varname)
+ setenv(varname,"ALIVE");
+ printf("\n");
+ }
+ }
+ }
+ else
+ printf("Unrecognized ICMP op: %s\n",operation);
+ return(CMD_SUCCESS);
+}
+
+int
+processICMP(struct ether_header *ehdr,ushort size)
+{
+ struct ip *ipp;
+ struct icmp_hdr *icmpp;
+ int i;
+
+ ipp = (struct ip *)(ehdr + 1);
+
+ icmpp = (struct icmp_hdr *)((char *)ipp+IP_HLEN(ipp));
+ if (icmpp->type == ICMP_ECHOREQUEST) { /* 3rdEd Comer pg 127 */
+#if INCLUDE_RARPIPASSIGN
+ /* If we're here and our IP address is 0.0.0.0, then the
+ * incoming packet's destination MAC address must have matched
+ * ours, so we assume (kinda dangerous) that we should assign
+ * this IP address to ourself...
+ * This capability allows a board to come up with a MAC address
+ * assigned, and IP set to 0.0.0.0, then the host can do
+ * arp -a IPADD MAC
+ * ping IPADD
+ * to assing IPADD to this board.
+ */
+ if (DHCPState == DHCPSTATE_NOTUSED) {
+ if ((BinIpAddr[0] == 0) && (BinIpAddr[1] == 0) &&
+ (BinIpAddr[2] == 0) && (BinIpAddr[3] == 0)) {
+ memcpy((char *)BinIpAddr,(char *)&(ipp->ip_dst),4);
+ printf("RARP IP Assignment: %d.%d.%d.%d\n",
+ BinIpAddr[0], BinIpAddr[1],
+ BinIpAddr[2], BinIpAddr[3]);
+ shell_sprintf("IPADD","%d.%d.%d.%d",
+ BinIpAddr[0], BinIpAddr[1],
+ BinIpAddr[2], BinIpAddr[3]);
+ }
+ }
+#endif
+ SendEchoResp(ehdr);
+ return(0);
+ }
+ else if (icmpp->type == ICMP_ECHOREPLY) {
+ struct icmp_echo_hdr *icmpecho;
+
+ icmpecho = (struct icmp_echo_hdr *)icmpp;
+ ICMPEchoReplyId = ecs(icmpecho->id);
+ ICMPSeqNoRcvd = ecs(icmpecho->seq);
+ }
+ else if (icmpp->type == ICMP_DESTUNREACHABLE) { /* 3rdEd Comer pg 129 */
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_INCOMING) {
+ i = icmpp->code;
+ if ((i > 5) || (i < 0))
+ i = 6;
+ printf(" ICMP: %s (code=%d)\n",
+ IcmpDestUnreachableCode[i],icmpp->code);
+ }
+#endif
+ return(0);
+ }
+#if INCLUDE_ICMPTIME
+ else if (icmpp->type == ICMP_TIMEREPLY) {
+ struct icmp_time_hdr *icmptime;
+ ulong orig, recv, xmit;
+
+ icmptime = (struct icmp_time_hdr *)icmpp;
+ memcpy((char *)&orig,(char *)&icmptime->orig,4);
+ memcpy((char *)&recv,(char *)&icmptime->recv,4);
+ memcpy((char *)&xmit,(char *)&icmptime->xmit,4);
+
+ ICMPSeqNoRcvd = icmptime->seq;
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_INCOMING) {
+ printf(" ICMP_TIMEREPLY: orig=0x%lx,recv=0x%lx,xmit=0x%lx\n",
+ orig,recv,xmit);
+ }
+#endif
+ if (CheckSrvrResolution) {
+ static int ICMPTimeStampTbl[20];
+
+ if (icmptime->seq < 20) {
+ ICMPTimeStampTbl[icmptime->seq] = xmit;
+ SendICMPRequest(ICMP_TIMEREQUEST,(uchar *)&ipp->ip_src,
+ (uchar *)&ehdr->ether_shost,0,icmptime->seq+1);
+ } else {
+
+ printf("TS00: %d\n",ICMPTimeStampTbl[0]);
+ for(i=1;i<20;i++) {
+ printf("TS%02d: %d (dlta=%d)\n",i,
+ ICMPTimeStampTbl[i],
+ ICMPTimeStampTbl[i]-ICMPTimeStampTbl[i-1]);
+ }
+ ICMPTimeStamp = xmit;
+ }
+ }
+ else {
+ ICMPTimeStamp = xmit;
+ }
+ }
+#endif
+ else {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_INCOMING) {
+ printf(" ICMPTYPE=%d\n",icmpp->type);
+ }
+#endif
+ return(-1);
+ }
+ return(0);
+}
+
+/* SendEchoResp():
+ * Called in response to an ICMP ECHO REQUEST. Typically used as
+ * a response to a PING.
+ */
+int
+SendEchoResp(struct ether_header *re)
+{
+ int i, icmp_len, datalen, oddlen;
+ ulong t;
+ ushort *sp, ip_len;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct icmp_echo_hdr *ticmp, *ricmp;
+
+ ri = (struct ip *) (re + 1);
+ datalen = ecs(ri->ip_len) - ((ri->ip_vhl & 0x0f) * 4);
+
+ te = EtherCopy(re);
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ri->ip_len;
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_ICMP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ ticmp = (struct icmp_echo_hdr *) (ti + 1);
+ ricmp = (struct icmp_echo_hdr *) (ri + 1);
+ ticmp->type = ICMP_ECHOREPLY;
+ ticmp->code = 0;
+ ticmp->cksum = 0;
+ ticmp->id = ricmp->id;
+ ticmp->seq = ricmp->seq;
+ memcpy((char *)(ticmp+1),(char *)(ricmp+1),datalen-8);
+
+ ip_len = ecs(ti->ip_len);
+ if (ip_len & 1) { /* If size is odd, temporarily bump up ip_len by */
+ oddlen = 1; /* one and add append a null byte for csum. */
+ ((char *)ti)[ip_len] = 0;
+ ip_len++;
+ }
+ else
+ oddlen = 0;
+ icmp_len = (ip_len - sizeof(struct ip))/2;
+
+ ipChksum(ti); /* compute checksum of ip hdr: (3rd Edition Comer pg 100) */
+
+ /* compute checksum of icmp message: (3rd Edition Comer pg 126) */
+ ticmp->cksum = 0;
+ sp = (ushort *) ticmp;
+ for (i=0,t=0;i<icmp_len;i++,sp++)
+ t += ecs(*sp);
+ t = (t & 0xffff) + (t >> 16);
+ ticmp->cksum = ~t;
+
+ self_ecs(ticmp->cksum);
+
+ if (oddlen)
+ ip_len--;
+
+ sendBuffer(sizeof(struct ether_header) + ip_len);
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_OUTGOING)
+ printf(" Sent Echo Response\n");
+#endif
+ return(0);
+}
+
+/* SendICMPRequest():
+ * Currently supports ICMP_TIMEREQUEST and ICMP_ECHOREQUEST.
+ */
+int
+SendICMPRequest(uchar type,uchar *binip,uchar *binenet,
+ ulong tmpval,ushort seq)
+{
+ ushort *sp;
+ uchar *data;
+ struct ip *ti;
+ int i, icmp_len;
+ struct ether_header *te;
+ struct icmp_time_hdr *ticmp;
+ ulong origtime, datasize, csum;
+
+ datasize = ICMP_ECHO_DATASIZE;
+
+ /* Retrieve an ethernet buffer from the driver and populate the */
+ /* ethernet level of packet: */
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6);
+ memcpy((char *)&te->ether_dhost,(char *)binenet,6);
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it appropriately: */
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+#if INCLUDE_ICMPTIME
+ if (type == ICMP_TIMEREQUEST) {
+ origtime = tmpval;
+ ti->ip_len = sizeof(struct ip) + sizeof(struct icmp_time_hdr);
+ }
+ else
+#endif
+ {
+ if (tmpval != 0)
+ datasize = tmpval;
+ ti->ip_len = sizeof(struct ip) + sizeof(struct icmp_echo_hdr) +
+ datasize;
+ }
+
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_ICMP;
+ memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4);
+ memcpy((char *)&ti->ip_dst.s_addr,(char *)binip,4);
+
+ icmp_len = (ti->ip_len - sizeof(struct ip))/2;
+ self_ecs(ti->ip_len);
+ self_ecs(ti->ip_off);
+ self_ecs(ti->ip_id);
+
+ ipChksum(ti); /* Compute csum of ip hdr */
+
+ /* Move to the ICMP portion of the packet and populate it appropriately: */
+ ticmp = (struct icmp_time_hdr *)(ti+1);
+ ticmp->type = type;
+ ticmp->code = 0;
+ ticmp->seq = ecs(seq);
+#if INCLUDE_ICMPTIME
+ if (type == ICMP_TIMEREQUEST) {
+ ticmp->id = ICMP_TIME_ID;
+ memcpy((char *)&ticmp->orig,(char *)&origtime,4);
+ memset((char *)&ticmp->recv,0,4);
+ memset((char *)&ticmp->xmit,0,4);
+ } else
+#endif
+ {
+ ticmp->id = ICMP_ECHO_ID;
+
+ /* Add 'datasize' bytes of data... */
+ data = (uchar *)((struct icmp_echo_hdr *)ticmp+1);
+ for(i=0;i<datasize;i++)
+ data[i] = 'a'+i;
+
+ }
+
+ /* compute checksum of icmp message: (3rd Edition Comer pg 126) */
+ csum = 0;
+ ticmp->cksum = 0;
+ sp = (ushort *) ticmp;
+ for (i=0;i<icmp_len;i++,sp++)
+ csum += ecs(*sp);
+ csum = (csum & 0xffff) + (csum >> 16);
+ ticmp->cksum = ~csum;
+
+ self_ecs(ticmp->cksum);
+
+#if INCLUDE_ICMPTIME
+ if (type == ICMP_TIMEREQUEST) {
+ self_ecl(ticmp->orig);
+ self_ecl(ticmp->recv);
+ self_ecl(ticmp->xmit);
+ sendBuffer(ICMP_TIMERQSTSIZE);
+ }
+ else
+#endif
+ sendBuffer(ICMP_ECHORQSTSIZE+datasize);
+ return(0);
+}
+
+/* Send an ICMP Unreachable message. All ICMP Unreachable messages
+ * include the IP header and 64 bits of the datagram that could not be
+ * delivered.
+ *
+ * 're' is the pointer to the packet that was received in response to which
+ * the unreachable message is being sent. 'icmp_code' is the code of the
+ * ICMP message.
+ */
+int
+SendICMPUnreachable(struct ether_header *re,uchar icmp_code)
+{
+ int i, len;
+ ushort *sp, r_iphdr_len, ip_len;
+ ulong t;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct icmp_unreachable_hdr *ticmp;
+
+ /* If DONTSEND_ICMP_UNREACHABLE is set, then don't send out the
+ * message...
+ */
+ if (getenv("DONTSEND_ICMP_UNREACHABLE"))
+ return(0);
+
+ ri = (struct ip *) (re + 1);
+
+ /* Length of the received IP hdr */
+ r_iphdr_len = ((ri->ip_vhl & 0x0f)<<2);
+
+ te = EtherCopy(re);
+
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+ /* Length of the outgoing IP packet = IP header + ICMP header +
+ * IP header and 8 bytes of unreachable datagram
+ */
+ ip_len = (IP_HDR_LEN<<2)+sizeof(struct icmp_unreachable_hdr)+r_iphdr_len+8;
+ ti->ip_len = ecs(ip_len);
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_ICMP;
+
+ /* Note that we do memcpy instead of struct copy because the ip
+ * header is not not word-aligned. As a result, the source and dest
+ * addresses are not word aligned either. The compiler generates word
+ * copy instructions for struct copy and this causes address alignement
+ * exceptions.
+ */
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ ticmp = (struct icmp_unreachable_hdr *) (ti + 1);
+ ticmp->type = ICMP_DESTUNREACHABLE;
+ ticmp->code = icmp_code;
+ ticmp->cksum = 0;
+ ticmp->unused1=0;
+ ticmp->unused2=0;
+
+ /* Copy the IP header and 8 bytes of the received datagram */
+ memcpy((char *)(ticmp+1),(char *)ri,r_iphdr_len+8);
+
+ ipChksum(ti); /* compute checksum of ip hdr */
+
+ /* compute checksum of icmp message: (see Comer pg 91) */
+ len = (ip_len - sizeof(struct ip))/2;
+ ticmp->cksum = 0;
+ sp = (ushort *) ticmp;
+ for (i=0,t=0;i<len;i++,sp++)
+ t += ecs(*sp);
+ t = (t & 0xffff) + (t >> 16);
+ ticmp->cksum = ~t;
+ self_ecs(ticmp->cksum);
+
+ sendBuffer(sizeof(struct ether_header) + ip_len);
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_OUTGOING)
+ printf(" Sent ICMP Dest Unreachable message. Code='%s'.\n",
+ IcmpDestUnreachableCode[icmp_code]);
+#endif
+ return(0);
+}
+
+#endif /* INCLUDE_ICMP */
+#endif /* INCLUDE_ETHERNET */
diff --git a/main/common/if.c b/main/common/if.c
new file mode 100755
index 0000000..8e8c01b
--- /dev/null
+++ b/main/common/if.c
@@ -0,0 +1,812 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * if.c:
+ *
+ * This file started off as the file for the "if" command in the monitor,
+ * and has since grown into the file that contains the commands that only
+ * make sense if they are used in scripts; hence, a prerequisite to these
+ * commands is that TFS is included in the build.
+ * It also contains the script runner portion of TFS. The name of this
+ * file should have been changed to tfsscript.c!
+ *
+ * if:
+ * Supports the monitor's ability to do conditional branching within
+ * scripts executed through TFS.
+ *
+ * goto:
+ * Tag based jumping in a script.
+ *
+ * item:
+ * A simple way to process a list (similar to KSH's 'for' construct).
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "ether.h"
+#include "cli.h"
+#include <ctype.h>
+
+#if INCLUDE_TFSSCRIPT
+
+/* Subroutine variables:
+ * The definition of MAXGOSUBDEPTH (15) determines the maximum number
+ * of subroutines that can be nested within any one script invocation.
+ * ReturnToTellTbl[]
+ * Used by script runner to keep track of the location in the file that
+ * the subroutine is supposed to return to.
+ * ReturnToDepth
+ * The current subroutine nesting depth of the script runner.
+ */
+#define MAXGOSUBDEPTH 15
+static int ReturnToDepth;
+static long ReturnToTellTbl[MAXGOSUBDEPTH+1];
+static int CurrentScriptfdTbl[TFS_MAXOPEN+1];
+
+/* ScriptIsRunning:
+ * Non-zero if a script is active, else zero.
+ */
+static int ScriptIsRunning;
+
+/* ScriptGotoTag:
+ * Points to the string that is the most recent target of
+ * a goto or gosub command.
+ */
+static char *ScriptGotoTag;
+
+/* ScriptExitFlag:
+ * If non-zero, then the script must exit.
+ * The 'exit' command sets this flag based on options provided to exit.
+ */
+int ScriptExitFlag;
+
+/* ExecuteAfterNext:
+ * If the ScriptExitFlag has the EXECUTE_AFTER_EXIT flag set, then the content
+ * of this array is assumed to be the file that is to be executed
+ * automatically after the exit of the current script.
+ */
+char ExecuteAfterExit[TFSNAMESIZE+1];
+
+/*****************************************************************************/
+
+/* If:
+ * A simple test/action statement.
+ * Currently, the only action supported is "goto tag".
+ * Syntax:
+ * if ARG1 compar ARG2 {action} [else action]
+ * if -t TEST {action} [else action]
+ */
+char *IfHelp[] = {
+ "Conditional branching",
+ "-[t:v] [{arg1} {compar} {arg2}] {action} [else action]",
+#if INCLUDE_VERBOSEHELP
+ " Options:",
+ " -t{test} see below",
+ " -v verbose mode (print TRUE or FALSE result)",
+ " Notes:",
+ " * Numerical/logical/string compare:",
+ " seq sec sne sin gt lt le ge eq ne and or xor",
+ " * Action:",
+ " goto tag | gosub tag | exit | return",
+ " * Other tests (-t args):",
+ " gc, ngc, iscmp {filename}",
+#endif
+ 0,
+};
+
+int
+If(int argc, char *argv[])
+{
+ int opt, arg, true, if_else, offset, verbose;
+ void (*iffunc)(char *), (*elsefunc)(char *);
+ long var1, var2;
+ char *testtype, *arg1, *arg2, *iftag, *elsetag;
+
+ verbose = 0;
+ testtype = 0;
+ while((opt=getopt(argc,argv,"vt:")) != -1) {
+ switch(opt) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ testtype = optarg;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ elsetag = 0;
+ elsefunc = 0;
+ offset = true = if_else = 0;
+
+ /* First see if there is an 'else' present... */
+ for (arg=optind;arg<argc;arg++) {
+ if (!strcmp(argv[arg],"else")) {
+ if_else = 1;
+ break;
+ }
+ }
+
+ if (if_else) {
+ elsetag = argv[argc-1];
+ if (!strcmp(argv[argc-1],"exit")) {
+ offset = 2;
+ elsefunc = exitscript;
+ }
+ else if (!strcmp(argv[argc-1],"return")) {
+ offset = 2;
+ elsefunc = gosubret;
+ }
+ else if (!strcmp(argv[argc-2],"goto")) {
+ offset = 3;
+ elsefunc = gototag;
+ }
+ else if (!strcmp(argv[argc-2],"gosub")) {
+ offset = 3;
+ elsefunc = gosubtag;
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+
+ iftag = argv[argc-offset-1];
+ if (!strcmp(argv[argc-offset-1],"exit"))
+ iffunc = exitscript;
+ else if (!strcmp(argv[argc-offset-1],"return"))
+ iffunc = gosubret;
+ else if (!strcmp(argv[argc-offset-2],"goto"))
+ iffunc = gototag;
+ else if (!strcmp(argv[argc-offset-2],"gosub"))
+ iffunc = gosubtag;
+ else
+ return(CMD_PARAM_ERROR);
+
+ if (testtype) {
+ if (!strcmp(testtype,"gc")) {
+ if (gotachar())
+ true=1;
+ }
+ else if (!strcmp(testtype,"ngc")) {
+ if (!gotachar())
+ true=1;
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else {
+ arg1 = argv[optind];
+ testtype = argv[optind+1];
+ arg2 = argv[optind+2];
+
+ var1 = strtoul(arg1,(char **)0,0);
+ var2 = strtoul(arg2,(char **)0,0);
+
+ if (!strcmp(testtype,"gt")) {
+ if (var1 > var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"lt")) {
+ if (var1 < var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"le")) {
+ if (var1 <= var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"ge")) {
+ if (var1 >= var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"eq")) {
+ if (var1 == var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"ne")) {
+ if (var1 != var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"and")) {
+ if (var1 & var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"xor")) {
+ if (var1 ^ var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"or")) {
+ if (var1 | var2)
+ true = 1;
+ }
+ else if (!strcmp(testtype,"sec")) {
+ if (!strcasecmp(arg1,arg2))
+ true = 1;
+ }
+ else if (!strcmp(testtype,"seq")) {
+ if (!strcmp(arg1,arg2))
+ true = 1;
+ }
+ else if (!strcmp(testtype,"sin")) {
+ if (strstr(arg2,arg1))
+ true = 1;
+ }
+ else if (!strcmp(testtype,"sne")) {
+ if (strcmp(arg1,arg2))
+ true = 1;
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+
+ /* If the true flag is set, call the 'if' function.
+ * If the true flag is clear, and "else" was found on the command
+ * line, then call the 'else' function...
+ */
+ if (true) {
+ if (verbose)
+ printf("TRUE\n");
+ iffunc(iftag);
+ }
+ else {
+ if (verbose)
+ printf("FALSE\n");
+ if (if_else)
+ elsefunc(elsetag);
+ }
+
+ return(CMD_SUCCESS);
+}
+
+int
+InAScript(void)
+{
+ if (ScriptIsRunning)
+ return(1);
+ else {
+ printf("Invalid from outside a script\n");
+ return(0);
+ }
+}
+
+void
+exitscript(char *ignored)
+{
+ if (InAScript()) {
+ ScriptExitFlag = EXIT_SCRIPT;
+ }
+}
+
+
+char *ExitHelp[] = {
+ "Exit currently running script",
+ "-[ae:r]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -a exit all scripts (if nested)",
+ " -e {exe} automatically execute 'exe' after exit",
+ " -r remove script after exit",
+#endif
+ 0,
+};
+
+int
+Exit(int argc, char *argv[])
+{
+ int opt;
+ ScriptExitFlag = EXIT_SCRIPT;
+
+ while((opt=getopt(argc,argv,"ae:r")) != -1) {
+ switch(opt) {
+ case 'a':
+ ScriptExitFlag |= EXIT_ALL_SCRIPTS;
+ break;
+ case 'e':
+ if (strlen(optarg) >= sizeof(ExecuteAfterExit))
+ return(CMD_PARAM_ERROR);
+ ScriptExitFlag |= EXECUTE_AFTER_EXIT;
+ strcpy(ExecuteAfterExit,optarg);
+ break;
+ case 'r':
+ ScriptExitFlag |= REMOVE_SCRIPT;
+ break;
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
+char *GotoHelp[] = {
+ "Branch to file tag",
+ "{tagname}",
+ 0,
+};
+
+int
+Goto(int argc, char *argv[])
+{
+ if (argc != 2)
+ return(CMD_PARAM_ERROR);
+ gototag(argv[1]);
+ return(CMD_SUCCESS);
+}
+
+
+char *GosubHelp[] = {
+ "Call a subroutine",
+ "{tagname}",
+ 0,
+};
+
+int
+Gosub(int argc, char *argv[])
+{
+ if (argc != 2)
+ return(CMD_PARAM_ERROR);
+ gosubtag(argv[1]);
+ return(CMD_SUCCESS);
+}
+
+char *ReturnHelp[] = {
+ "Return from subroutine",
+ "",
+ 0,
+};
+
+int
+Return(int argc, char *argv[])
+{
+ if (argc != 1)
+ return(CMD_PARAM_ERROR);
+ gosubret(0);
+ return(CMD_SUCCESS);
+}
+
+/* Item:
+ * This is a simple replacement for the KSH "for" construct...
+ * It allows the user to build a list of strings and retrieve one at a time.
+ * Basically, the items can be thought of as a table. The value of idx
+ * (starting with 1) is used to index into the list of items and place
+ * that item in the shell variable "var".
+ * Syntax:
+ * item {idx} {var} {item1} {item2} {item3} ....
+ */
+char *ItemHelp[] = {
+ "Extract an item from a list",
+ "{idx} {stor_var} [item1] [item2] ...",
+#if INCLUDE_VERBOSEHELP
+ "Note: idx=1 retrieves item1",
+#endif
+ 0,
+};
+
+int
+Item(int argc, char *argv[])
+{
+ int idx;
+ char *varname;
+
+ if (argc < 3)
+ return(CMD_PARAM_ERROR);
+
+ idx = atoi(argv[1]);
+ varname = argv[2];
+
+ if ((idx < 1) || (idx > (argc-3))) {
+ setenv(varname,0);
+ return(CMD_SUCCESS);
+ }
+
+ idx += 2;
+ setenv(varname,argv[idx]);
+ return(CMD_SUCCESS);
+}
+
+/* Read():
+ * Simple interactive shell variable entry.
+ * Syntax:
+ * read [options] [var1] [var2] [...]
+ * Options:
+ * -twww timeout after 'www' milliseconds (approximate) of
+ * waiting for input.
+ *
+ */
+
+char *ReadHelp[] = {
+ "Interactive shellvar entry",
+#if INCLUDE_VERBOSEHELP
+ "-[fnp:t:T:] [var1] [var2] ... ",
+ " -f flush console input",
+ " -n no echo during read",
+ " -p *** prefill string",
+ " -t ### msec timeout per char",
+ " -T ### msec timeout cumulative",
+ "Notes:",
+ " This command waits for console input terminated by ENTER.",
+ " Input tokens are whitespace delimited.",
+ "Examples:",
+ " * read name # wait forever",
+ " If user responds with ENTER, shell var 'name' is cleared;",
+ " else it is loaded with the first input token.",
+ " * read -t2000 name # timeout after 2 seconds",
+ " If timeout, shell var 'name' is untouched; else if timeout",
+ " doesn't occur, but user only types ENTER 'var' is cleared;",
+ " else 'var' will contain token.",
+#endif
+ 0,
+};
+
+int
+Read(int argc,char *argv[])
+{
+ int i, reached_eol, opt, waitfor, noecho;
+ char *prefill, buf[64], *space, *bp;
+
+ prefill = 0;
+ waitfor = noecho = 0;
+ while((opt=getopt(argc,argv,"fnp:t:T:")) != -1) {
+ switch(opt) {
+ case 'f':
+ flush_console_in();
+ return(CMD_SUCCESS);
+ case 'n':
+ noecho = 1;
+ break;
+ case 'p':
+ prefill = optarg;
+ break;
+ case 't':
+ waitfor = strtol(optarg,(char **)0,0);
+ break;
+ case 'T':
+ waitfor = strtol(optarg,(char **)0,0);
+ waitfor = -waitfor;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+#if INCLUDE_MONCMD
+ /* Since this command blocks waiting for user input on the console,
+ * check to see if we are running under the context of MONCMD, and,
+ * if yes, return CMD_FAILURE to avoid a lockup...
+ */
+ if (IPMonCmdActive) {
+ printf("Invalid under moncmd context.\n");
+ return(CMD_FAILURE);
+ }
+#endif
+
+ /* If -t, then restart the timeout for each character.
+ * If -T, then the timeout accumulates over all characters.
+ * If a timeout does occur, then do nothing to the shell variables
+ * that may be specified as arguments. This allows the script
+ * writer to distinguish between a timeout, and an empty line...
+ * Timeout has no affect, empty line will NULL out the variable.
+ */
+ if (getfullline(buf,sizeof(buf)-1,0,waitfor,prefill,noecho?0:1) == -1)
+ return(CMD_SUCCESS);
+
+ /* If there were no args after the option, then there is no need to
+ * consider populating a shell variable, so just return here.
+ */
+ if (argc == optind) {
+ return(CMD_SUCCESS);
+ }
+
+ bp = buf;
+ reached_eol = 0;
+ for(i=optind;i<argc;i++) {
+ space=strpbrk(bp," \t");
+ if (space) {
+ *space = 0;
+ setenv(argv[i],bp);
+ bp = space+1;
+ }
+ else {
+ if ((reached_eol) || (*bp == 0)) {
+ setenv(argv[i],0);
+ }
+ else {
+ setenv(argv[i],bp);
+ reached_eol = 1;
+ }
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
+int
+currentScriptfd(void)
+{
+ return(CurrentScriptfdTbl[ScriptIsRunning]);
+}
+
+/* gototag():
+ * Used with tfsscript to allow a command to adjust the pointer into the
+ * script that is currently being executed. It simply populates the
+ * "ScriptGotoTag" pointer with the tag that should be branched to next.
+ */
+void
+gototag(char *tag)
+{
+ if (InAScript()) {
+ if (ScriptGotoTag)
+ free(ScriptGotoTag);
+ ScriptGotoTag = malloc(strlen(tag)+8);
+ sprintf(ScriptGotoTag,"# %s",tag);
+ }
+}
+
+/* gosubtag():
+ * Similar in basic use to gototag(), except that we keep a copy of the
+ * current position in the active script file so that it can be returned
+ * to later.
+ */
+void
+gosubtag(char *tag)
+{
+ if (InAScript()) {
+ if (ReturnToDepth >= MAXGOSUBDEPTH) {
+ printf("Max return-to depth reached\n");
+ return;
+ }
+ ReturnToTellTbl[ReturnToDepth++] = tfstell(currentScriptfd());
+ gototag(tag);
+ }
+}
+
+void
+gosubret(char *ignored)
+{
+ int offset, err;
+
+ if (InAScript()) {
+ err = 0;
+
+ if (ReturnToDepth <= 0) {
+ printf("Nothing to return to\n");
+ err = 1;
+ }
+ else {
+ ReturnToDepth--;
+ offset = tfsseek(currentScriptfd(),
+ ReturnToTellTbl[ReturnToDepth],TFS_BEGIN);
+ if (offset <= 0) {
+ err = 1;
+ printf("return error: %s\n",tfserrmsg(offset));
+ }
+ }
+ if (err)
+ printf("Possible gosub/return imbalance.\n");
+ }
+}
+
+/* tfsscript():
+ * Treat the file as a list of commands that should be executed
+ * as monitor commands. Step through each line and execute it.
+ * The tfsDocommand() function pointer is used so that the application
+ * can assign a different command interpreter to the script capbilities
+ * of the monitor. To really take advantage of this, the command interpreter
+ * that is reassigned, should allow monitor commands to run if the command
+ * does not exist in the application's command list.
+ *
+ * Scripts can call other scripts that call other scripts (etc...) and
+ * that works fine because tfsscript() will just use more stack space but
+ * it eventually returns through the same function call tree. A script can
+ * also call a COFF, ELF or AOUT file and expect it to return as long as
+ * the executable returns through the same point into which it was started
+ * (the entrypoint). If the executable uses mon_appexit() to terminate,
+ * then the calling script will not regain control.
+ */
+
+int
+tfsscript(TFILE *fp,int verbose)
+{
+ char lcpy[CMDLINESIZE], *sv;
+ int tfd, lnsize, lno, verbosity, ignoreerror, cmdstat;
+
+ tfd = tfsopen(fp->name,TFS_RDONLY,0);
+ if (tfd < 0)
+ return(tfd);
+
+ lno = 0;
+
+ /* If ScriptIsRunning is zero, then we know that this is the top-level
+ * script, so we can initialize state here...
+ */
+ if (ScriptIsRunning == 0)
+ ReturnToDepth = 0;
+
+ CurrentScriptfdTbl[++ScriptIsRunning] = tfd;
+
+ while(1) {
+ lno++;
+ lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE);
+ if (lnsize == 0) /* end of file? */
+ break;
+ if (lnsize < 0) {
+ printf("tfsscript(): %s\n",tfserrmsg(lnsize));
+ break;
+ }
+ if ((lcpy[0] == '\r') || (lcpy[0] == '\n')) /* empty line? */
+ continue;
+
+ lcpy[lnsize-1] = 0; /* Remove the newline */
+
+ /* Just in case the goto tag was set outside a script, */
+ /* clear it now. */
+ if (ScriptGotoTag) {
+ free(ScriptGotoTag);
+ ScriptGotoTag = (char *)0;
+ }
+
+ ScriptExitFlag = 0;
+
+ /* Execute the command line.
+ * If the shell variable "SCRIPTVERBOSE" is set, then enable
+ * verbosity for this command; else use what was passed in
+ * the parameter list of the function. Note that the variable
+ * is tested for each command so that verbosity can be enabled
+ * or disabled within a script.
+ * If the command returns a status that indicates that there was
+ * some parameter error, then exit the script.
+ */
+ sv = getenv("SCRIPTVERBOSE");
+ if (sv)
+ verbosity = atoi(sv);
+ else
+ verbosity = verbose;
+
+ if ((lcpy[0] == '-') || (getenv("SCRIPT_IGNORE_ERROR")))
+ ignoreerror = 1;
+ else
+ ignoreerror = 0;
+
+ if (verbosity)
+ printf("[%02d]: %s\n",lno,lcpy);
+
+ cmdstat = tfsDocommand(lcpy[0] == '-' ? lcpy+1 : lcpy, 0);
+
+ if (cmdstat != CMD_SUCCESS) {
+ setenv("CMDSTAT","FAIL");
+ if (ignoreerror == 0) {
+ printf("Terminating script '%s' at line %d\n",
+ TFS_NAME(fp),lno);
+ ScriptExitFlag = EXIT_SCRIPT;
+ break;
+ }
+ }
+ else {
+ setenv("CMDSTAT","PASS");
+ }
+
+ /* Check for exit flag. If set, then in addition to terminating the
+ * script, clear the return depth here so that the "missing return"
+ * warning is not printed. This is done because there is likely
+ * to be a subroutine with an exit in it and this should not
+ * cause a warning.
+ */
+ if (ScriptExitFlag) {
+ ReturnToDepth = 0;
+ break;
+ }
+
+ /* If ScriptGotoTag is set, then attempt to reposition the line
+ * pointer to the line that contains the tag.
+ */
+ if (ScriptGotoTag) {
+ int tlen;
+
+ tlen = strlen(ScriptGotoTag);
+ lno = 0;
+ tfsseek(tfd,0,TFS_BEGIN);
+ while(1) {
+ lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE);
+ if (lnsize == 0) {
+ printf("Tag '%s' not found\n",ScriptGotoTag+2);
+ free(ScriptGotoTag);
+ ScriptGotoTag = (char *)0;
+ tfsclose(tfd,0);
+ return(TFS_OKAY);
+ }
+ lno++;
+ if (!strncmp(lcpy,ScriptGotoTag,tlen) &&
+ (isspace(lcpy[tlen]) || (lcpy[tlen] == ':'))) {
+ free(ScriptGotoTag);
+ ScriptGotoTag = (char *)0;
+ break;
+ }
+ }
+ }
+ /* After each line, poll ethernet interface. */
+ pollethernet();
+ }
+ tfsclose(tfd,0);
+ if (ScriptExitFlag & REMOVE_SCRIPT)
+ tfsunlink(fp->name);
+ if (ScriptIsRunning > 0) {
+ ScriptIsRunning--;
+ if ((ScriptIsRunning == 0) && (ReturnToDepth != 0)) {
+ printf("Error: script is done, but return-to-depth != 0\n");
+ printf("(possible gosub/return imbalance)\n");
+ }
+ }
+ else {
+ printf("Script run-depth error\n");
+ }
+
+ /* If the EXECUTE_AFTER_EXIT flag is set (by exit -e), then automatically
+ * start up the file specified in ExecuteAfterExit[]...
+ */
+ if (ScriptExitFlag & EXECUTE_AFTER_EXIT) {
+ char *argv[2];
+
+ argv[0] = ExecuteAfterExit;
+ argv[1] = 0;
+ ScriptExitFlag = 0;
+ tfsrun(argv,0);
+ }
+
+ /* Upon completion of a script, clear the ScriptExitFlag variable so
+ * that it is not accidentally applied to another script that may have
+ * called this script.
+ */
+ if ((ScriptExitFlag & EXIT_ALL_SCRIPTS) != EXIT_ALL_SCRIPTS)
+ ScriptExitFlag = 0;
+ return(TFS_OKAY);
+}
+
+/* tfsscriptname():
+ * Return the currently running script name; else return an empty string.
+ */
+char *
+tfsscriptname(void)
+{
+ struct tfsdat *slot;
+
+ if (ScriptIsRunning) {
+ slot = &tfsSlots[CurrentScriptfdTbl[ScriptIsRunning]];
+ if (slot->offset != (ulong)-1)
+ return(slot->hdr.name);
+ }
+ return("");
+}
+
+#else /* INCLUDE_TFSSCRIPT */
+
+int
+tfsscript(TFILE *fp,int verbose)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+char *
+tfsscriptname(void)
+{
+ return(0);
+}
+
+#endif
diff --git a/main/common/igmp.c b/main/common/igmp.c
new file mode 100644
index 0000000..213d1cb
--- /dev/null
+++ b/main/common/igmp.c
@@ -0,0 +1,200 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * igmp.c:
+ *
+ * Support some basic IGMP stuff.
+ * I wrote this code as an exercise for getting to know basic IGMP.
+ * This code doesn't do much. It will successfully send a JOIN or LEAVE
+ * but the monitor is not prepared to deal with multicast, so it doesn't
+ * add any real functionality except for the ability to observe IGMP.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_IGMP
+#include "endian.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "cli.h"
+
+int SendIGMP(int type,uchar *groupip);
+
+char *IgmpHelp[] = {
+ "IGMP interface",
+#if INCLUDE_VERBOSEHELP
+ "{operation} [args]",
+ "Operations...",
+ " join {IP}",
+ " leave {IP}",
+#endif
+ 0,
+};
+
+int
+Igmp(int argc,char *argv[])
+{
+ int opt, verbose = 0;
+ uchar binip[8];
+ char *operation, *ipadd;
+
+ while ((opt=getopt(argc,argv,"v")) != -1) {
+ switch(opt) {
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc != optind + 2)
+ return(CMD_PARAM_ERROR);
+
+ operation = argv[optind];
+ ipadd = argv[optind+1];
+
+ /* Convert IP address to binary: */
+ if (IpToBin(ipadd,binip) < 0)
+ return(CMD_SUCCESS);
+
+ /* If time or echo, do the common up-front stuff here... */
+ if (!strcmp(operation,"join")) {
+ SendIGMP(IGMPTYPE_JOIN,binip);
+ }
+ else if (!strcmp(operation,"leave")) {
+ SendIGMP(IGMPTYPE_LEAVE,binip);
+ }
+ else {
+ printf("Unrecognized IGMP op: %s\n",operation);
+ return(CMD_FAILURE);
+ }
+ return(CMD_SUCCESS);
+}
+
+int
+SendIGMP(int type,uchar *groupip)
+{
+ int i;
+ ushort *sp;
+ struct ip *ti;
+ struct Igmphdr *tigmp;
+ struct ether_header *te;
+ ulong csum, *router_alert_opt;
+
+ /* Retrieve an ethernet buffer from the driver and populate the */
+ /* ethernet level of packet: */
+ te = (struct ether_header *) getXmitBuffer();
+
+ /* Source MAC is this target's MAC address...
+ */
+ memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6);
+ /* Destination MAC is multicast, so it is derived from the
+ * group IP address...
+ * The upper 24 bits are 0x01005e.
+ * For JOIN, the lower 24 bits are masked with the groupIP and 0x7fffff.
+ * For LEAVE, the message is sent to the All_Routers_Multicast_Group
+ * (224.0.0.2), so the lower three bytes are 0,0,2.
+ */
+ te->ether_dhost.ether_addr_octet[0] = 0x01;
+ te->ether_dhost.ether_addr_octet[1] = 0x00;
+ te->ether_dhost.ether_addr_octet[2] = 0x5e;
+
+ if (type == IGMPTYPE_LEAVE) {
+ te->ether_dhost.ether_addr_octet[3] = 0x00;
+ te->ether_dhost.ether_addr_octet[4] = 0x00;
+ te->ether_dhost.ether_addr_octet[5] = 0x02;
+ }
+ else {
+ te->ether_dhost.ether_addr_octet[3] = groupip[1] & 0x7f;
+ te->ether_dhost.ether_addr_octet[4] = groupip[2];
+ te->ether_dhost.ether_addr_octet[5] = groupip[3];
+ }
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it appropriately: */
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = ((IP_VER<<4) | ((sizeof(struct ip)+sizeof(ulong)) >> 2));
+ ti->ip_tos = 0;
+ ti->ip_len = sizeof(struct ip) + sizeof(ulong) + sizeof(struct Igmphdr);
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = 1;
+ ti->ip_p = IP_IGMP;
+ memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4);
+ if (type == IGMPTYPE_LEAVE)
+ ti->ip_dst.s_addr = ALL_MULTICAST_ROUTERS;
+ else
+ memcpy((char *)&ti->ip_dst.s_addr,(char *)groupip,4);
+
+ self_ecs(ti->ip_len);
+ self_ecs(ti->ip_off);
+ self_ecs(ti->ip_id);
+
+ router_alert_opt = (ulong *)(ti+1);
+ *router_alert_opt = 0x94040000; /* see RFC2113 */
+
+ ipChksum(ti); /* Compute csum of ip hdr */
+
+ /* Move to the IGMP portion of the packet and populate it appropriately: */
+ tigmp = (struct Igmphdr *)(router_alert_opt+1);
+ tigmp->type = type;
+ tigmp->mrt = 0;
+ tigmp->csum = 0;
+ memcpy((char *)&tigmp->group,(char *)groupip,4);
+
+ /* Calculate checksum of IGMP portion of the header.
+ * This uses the same method as is used with ipChksum()...
+ */
+ sp = (ushort *)tigmp;
+ csum = 0;
+ for (i=0;i<4;i++,sp++) {
+ csum += *sp;
+ if (csum & 0x80000000)
+ csum = (csum & 0xffff) + (csum >> 16);
+ }
+ while(csum >> 16)
+ csum = (csum & 0xffff) + (csum >> 16);
+ tigmp->csum = ~csum;
+
+ sendBuffer(IGMP_JOINRQSTSIZE);
+ return(0);
+}
+
+int
+MacIsMulticast(uchar *mac)
+{
+ if (*mac != 0x01)
+ return(0);
+ mac++;
+ if (*mac != 0x00)
+ return(0);
+ mac++;
+ if (*mac != 0x5e)
+ return(0);
+ mac++;
+ if (*mac & 0x80)
+ return(0);
+ return(1);
+}
+
+#endif
diff --git a/main/common/inc_check.h b/main/common/inc_check.h
new file mode 100644
index 0000000..a17a62a
--- /dev/null
+++ b/main/common/inc_check.h
@@ -0,0 +1,412 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * inc_check.h:
+ *
+ * DESCRIPTION HERE
+ *
+ *
+ * This is an include file used to verify that all of the monitor macros
+ * are defined. There is also some attempt to verify that macro conflicts
+ * do not exist (for example, the flash file system cannot exist if the
+ * flash driver is not included); however, there are probably holes in this
+ * check.
+ *
+ * Following is a brief description of what each macro includes if set to
+ * non-zero...
+ *
+ * INCLUDE_MEMCMDS:
+ * Memory display, modification and test commands. The included as a
+ * result of setting this macro is primarily found in memcmds.c.
+ * INCLUDE_EDIT:
+ * An ascii file editor. This is an on-board file editor that provides
+ * the system with the ability to edit files in TFS. Refer to edit.c
+ * for details of this functionality. This obviously assumes that TFS
+ * and the FLASH drivers are also enabled.
+ * INCLUDE_DISASSEMBLER:
+ * This pulls in a disassembler.
+ * INCLUDE_UNPACK:
+ * INCLUDE_UNZIP:
+ * These two macros define one of two different mechanisms for
+ * decompression of executables in TFS. UNPACK is huffman and UNZIP
+ * is the public domain zlib stuff. Huffman is a small addition to the
+ * monitor size but only provides about 15% compression. The zlib stuff
+ * is a bit larger and needs more RAM for malloc() but it does a MUCH
+ * better job of compression. I've seen as high as 75% of the file size
+ * compressed. It is illegal to set both of these macros.
+ * INCLUDE_ETHERNET:
+ * This pulls in the basic ethernet drivers with ARP, and some of the
+ * lowest level ethernet interface code.
+ * INCLUDE_TFTP:
+ * This pulls in a TFTP client and server (obviously assumes ETHERNET
+ * is also pulled in).
+ * INCLUDE_DHCPBOOT:
+ * This pulls in a DHCP/BOOTP client (also assumes ETHERNET
+ * is also pulled in).
+ * INCLUDE_TFS:
+ * INCLUDE_TFSAPI:
+ * INCLUDE_TFSAUTODEFRAG:
+ * INCLUDE_TFSSYMTBL:
+ * INCLUDE_TFSSCRIPT:
+ * INCLUDE_TFSCLI:
+ * The above TFS macros allow the monitor to be built with varying degrees
+ * of FFS capability depending on the needs of the system. INCLUDE_TFS
+ * is required by all others and is the minimum TFS hookup. It provides
+ * the minimum set of TFS facilities such as autoboot, use of a monrc file
+ * for startup config, and defragmentation. TFSAPI pulls in the TFS
+ * code that allows an application to hook into TFS's capabilities in
+ * code-space. TFSCLI pulls in the TFS command at the command line
+ * interface. TFSSAFEDEFRAG pulls in the power-safe defragmenation
+ * (otherwise a simpler, less robust mechanism is used).
+ * TFSSYMTBL pulls in the symbol-table functionality and TFSSCRIPT
+ * pulls in the CLI commands that are normally associated with scripts.
+ * INCLUDE_XMODEM:
+ * Pull in Xmodem.
+ * INCLUDE_LINEEDIT:
+ * Pull in a command line editor and history facility.
+ * INCLUDE_EE:
+ * Pull in an expression evaluator for the CLI.
+ * Note that this is not included with the public distribution.
+ * INCLUDE_FLASH:
+ * Pull in the flash drivers.
+ * INCLUDE_CRYPT:
+ * Pull in UNIX crypt() instead of a simpler encryption scheme I wrote.
+ * Note that this is not included with the public distribution.
+ * INCLUDE_GDB:
+ * Pull in the "gdb" command. This is an incomplete facility that
+ * will eventually allow the monitor to hook up to a gdb debugger.
+ * INCLUDE_STRACE:
+ * Pull in the "strack trace" command.
+ * INCLUDE_CAST:
+ * Pull in the "cast" command for complex structure display at the
+ * CLI.
+ * INCLUDE_REDIRECT:
+ * This pulls in the code that allows the monitor's CLI to redirect
+ * command output to a TFS file.
+ * INCLUDE_QUICKMEMCPY:
+ * This pulls in some faster memcpy stuff in genlib.c.
+ * INCLUDE_PROFILER:
+ * This pulls in some code and a CLI command that provides an
+ * application with some task and function level profiling.
+ * INCLUDE_BBC:
+ * This pulls in some code and a CLI command that provides an
+ * application with a basic ability to organize basic block coverage
+ * verification.
+ * INCLUDE_MEMTRACE:
+ * This pulls in a simple memory trace capability. It's a simple
+ * printf()-like function with data logged to RAM instead of a UART.
+ * INCLUDE_STOREMAC:
+ * This pulls in a function that forces the user to establish the MAC
+ * in the etheradd space allocated in reset.s. It needs INCLUDE_FLASH
+ * because flash writes are done. If not enabled the MAC address can
+ * still be stored in etheradd using the "ether mac" command.
+ * INCLUDE_SHELLVARS:
+ * This pulls in the monitor's ability to deal with shell variables.
+ * This includes the "set" command on the CLI, plus a lot of other
+ * subsections of the monitor depend on shell variables.
+ * This facility should only be disabled when there is a desperate
+ * need to shink the monitor's footprint.
+ * INCLUDE_MALLOC:
+ * This pulls in the monitor's malloc. This includes the "heap"
+ * command on the CLI, plus a few other factilies in the monitor
+ * assume malloc is included; so without it, they won't work either.
+ * This facility should only be disabled when there is a desperate
+ * need to shink the monitor's footprint.
+ * INCLUDE_HWTMR:
+ * If set, then the target port must supply a function called
+ * target_timer() which returns a 32-bit value representing a
+ * a hardware-resident clock whose rate is defined by the value
+ * specified by TIMER_TICKS_PER_MSEC.
+ * INCLUDE_VERBOSEHELP:
+ * If set, then full help text is built in; else only the usage
+ * and abstract is included.
+ * INCLUDE_PORTCMD:
+ * If set, then the mon_portcmd(int cmd, void *arg) API can be
+ * used to build port-specific API extensions.
+ * INCLUDE_USRLVL:
+ * If set, then the code that incorporates user levels is included
+ * in the build.
+ * INCLUDE_STRUCT:
+ * If set, then the struct command is included in the build. This
+ * requires that TFS be included also.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _INC_CHECK_H
+#define _INC_CHECK_H
+
+/***********************************************************************
+ * Verify that the basic set of INCLUDE macros have been defined:
+ */
+
+#ifndef INCLUDE_ICMP
+#error "INCLUDE_ICMP must be defined in config.h."
+#endif
+
+#ifndef INCLUDE_USRLVL
+#error "INCLUDE_USRLVL must be defined in config.h."
+#endif
+
+#ifndef INCLUDE_PORTCMD
+#error "INCLUDE_PORTCMD must be defined in config.h."
+#endif
+
+#ifndef INCLUDE_HWTMR
+#error "INCLUDE_HWTMR must be defined in config.h."
+#endif
+
+#ifndef INCLUDE_VERBOSEHELP
+#error "INCLUDE_VERBOSEHELP must be defined in config.h."
+#endif
+
+#ifndef INCLUDE_MEMTRACE
+#error "INCLUDE_MEMTRACE must be defined in config.h."
+#endif
+
+#ifdef INCLUDE_TFSSAFEDEFRAG
+#error "INCLUDE_TFSSAFEDEFRAG no longer needed."
+#endif
+
+#ifndef INCLUDE_MEMCMDS
+#error "INCLUDE_MEMCMDS must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_EDIT
+#error "INCLUDE_EDIT must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_DISASSEMBLER
+#error "INCLUDE_DISASSEMBLER must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_UNZIP
+#error "INCLUDE_UNZIP must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_ETHERNET
+#error "INCLUDE_ETHERNET must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFTP
+#error "INCLUDE_TFTP must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_DHCPBOOT
+#error "INCLUDE_DHCPBOOT must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFS
+#error "INCLUDE_TFS must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFSCLI
+#error "INCLUDE_TFSCLI must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFSAPI
+#error "INCLUDE_TFSAPI must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFSSCRIPT
+#error "INCLUDE_TFSSCRIPT must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_TFSSYMTBL
+#error "INCLUDE_TFSSYMTBL must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_XMODEM
+#error "INCLUDE_XMODEM must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_LINEEDIT
+#error "INCLUDE_LINEEDIT must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_EE
+#error "INCLUDE_EE must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_FLASH
+#error "INCLUDE_FLASH must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_STRACE
+#error "INCLUDE_STRACE must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_CAST
+#error "INCLUDE_CAST must be defined in config.h"
+#endif
+
+#ifdef INCLUDE_SHELLVAR
+#error "INCLUDE_SHELLVAR definition no longer needed in config.h"
+#endif
+
+//#ifdef INCLUDE_MALLOC
+//#error "INCLUDE_MALLOC definition no longer needed in config.h"
+//#endif
+
+#ifndef INCLUDE_REDIRECT
+#error "INCLUDE_REDIRECT must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_QUICKMEMCPY
+#error "INCLUDE_QUICKMEMCPY must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_PROFILER
+#error "INCLUDE_PROFILER must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_BBC
+#error "INCLUDE_BBC must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_STOREMAC
+#error "INCLUDE_STOREMAC must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_MALLOC
+#error "INCLUDE_MALLOC must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_SHELLVARS
+#error "INCLUDE_SHELLVARS must be defined in config.h"
+#endif
+
+#ifndef INCLUDE_STRUCT
+#error "INCLUDE_STRUCT must be defined in config.h"
+#endif
+
+
+/***********************************************************************
+ * The storemac facility needs flash to be enabled.
+ */
+#if INCLUDE_STOREMAC
+#if !INCLUDE_FLASH
+#error "Can't include STOREMAC without FLASH"
+#endif
+#endif
+
+/***********************************************************************
+ * The hardware timer facility needs to know the tick rate.
+ */
+#if INCLUDE_HWTMR
+#ifndef TIMER_TICKS_PER_MSEC
+#error "Can't set INCLUDE_HWTMR without TIMER_TICKS_PER_MSEC."
+#endif
+#endif
+
+/***********************************************************************
+ * Certain pieces of the monitor cannot be enabled without basic TFS:
+ */
+#if !INCLUDE_TFS
+#if INCLUDE_REDIRECT
+#error "Can't include REDIRECT without TFS"
+#endif
+#if INCLUDE_PROFILER
+#error "Can't include PROFILER without TFS"
+#endif
+#if INCLUDE_USRLVL
+#error "Can't include USRLVL without TFS"
+#endif
+#if INCLUDE_STRUCT
+#error "Can't include STRUCT without TFS"
+#endif
+#endif
+
+/***********************************************************************
+ * Certain pieces of the monitor cannot be enabled without TFS API:
+ */
+
+#if !INCLUDE_TFSAPI
+
+#if INCLUDE_EDIT
+#error "Can't include EDIT without TFSAPI"
+#endif
+#if INCLUDE_STRACE
+#error "Can't include STRACE without TFSAPI"
+#endif
+#if INCLUDE_TFSSYMTBL
+#error "Can't include TFSSYMTBL without TFSAPI"
+#endif
+
+#endif
+
+/***********************************************************************
+ * Certain pieces of the monitor cannot be enabled without ETHERNET:
+ */
+#if !INCLUDE_ETHERNET
+
+#if INCLUDE_TFTP
+#error "Can't include TFTP without ETHERNET"
+#endif
+#if INCLUDE_DHCPBOOT
+#error "Can't include DHCPBOOT without ETHERNET"
+#endif
+#if INCLUDE_SYSLOG
+#error "Can't include SYSLOG without ETHERNET"
+#endif
+#if INCLUDE_ICMP
+#error "Can't include ICMP without ETHERNET"
+#endif
+
+#endif
+
+/***********************************************************************
+ * Just history...
+ */
+#define DONT_INCLUDE_OLDSTYLE_FLAGCHECK
+
+/***********************************************************************
+ * Check for things removed as of 1.0...
+ */
+#ifdef INCLUDE_UNPACK
+#error "INCLUDE_UNPACK is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_DEBUG
+#error "INCLUDE_DEBUG is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_PIO
+#error "INCLUDE_PIO is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_EXCTEST
+#error "INCLUDE_EXCTEST is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_IDEV
+#error "INCLUDE_IDEV is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_CRYPT
+#error "INCLUDE_CRYPT is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_TFSAUTODEFRAG
+#error "INCLUDE_TFSAUTODEFRAG is unused as of uMon 1.0"
+#endif
+#ifdef FLASH_LOCK_SUPPORTED
+#error "FLASH_LOCK_SUPPORT is unused as of uMon 1.0"
+#endif
+#ifdef INCLUDE_ARGV
+#error "INCLUDE_ARGV is unused as of uMon 1.0"
+#endif
+
+
+#endif
diff --git a/main/common/jffs2.c b/main/common/jffs2.c
new file mode 100644
index 0000000..50f0422
--- /dev/null
+++ b/main/common/jffs2.c
@@ -0,0 +1,2336 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * jffs2.c
+ *
+ * Reads JFFS2-formatted NOR flash.
+ *
+ * Initial version written by Ed Sutter, with contributions later made
+ * by Bill Gatliff (bgat@billgatliff.com).
+ *
+ */
+
+#include "config.h"
+
+#if INCLUDE_JFFS2
+
+#include "stddefs.h"
+#include "assert.h"
+#include "genlib.h"
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "time.h"
+#include "flash.h"
+
+#if INCLUDE_JFFS2ZLIB
+#include "jz_zlib.h"
+#endif
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+
+/* override JFFS2_DEFAULT_BASE in target's config.h when necessary! */
+#ifndef JFFS2_DEFAULT_BASE
+#define JFFS2_DEFAULT_BASE 0
+#endif
+
+#define JFFS2_MAXPATH 256
+
+#define JFFS2_MODE_MASK 00170000
+#define JFFS2_MODE_REG 0100000
+#define JFFS2_MODE_LNK 0120000
+#define JFFS2_MODE_BLK 0060000
+#define JFFS2_MODE_DIR 0040000
+#define JFFS2_MODE_CHR 0020000
+#define JFFS2_MODE_FIFO 0010000
+
+#define DT_REG (JFFS2_MODE_REG >> 12)
+#define DT_LNK (JFFS2_MODE_LNK >> 12)
+#define DT_BLK (JFFS2_MODE_BLK >> 12)
+#define DT_DIR (JFFS2_MODE_DIR >> 12)
+#define DT_CHR (JFFS2_MODE_CHR >> 12)
+#define DT_FIFO (JFFS2_MODE_FIFO >> 12)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+
+#define is_reg(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_REG)
+#define is_lnk(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_LNK)
+#define is_blk(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_BLK)
+#define is_dir(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_DIR)
+#define is_chr(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_CHR)
+#define is_fifo(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_FIFO)
+
+#define JFFS2_MAGIC 0x1985
+
+#define JFFS2_COMPAT_MASK 0xc000
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODE_ACCURATE 0x2000
+
+#define JFFS2_NODETYPE_MASK 7
+#define JFFS2_NODETYPE_DIRENT 1
+#define JFFS2_NODETYPE_INODE 2
+#define JFFS2_NODETYPE_CLEANMARKER 3
+#define JFFS2_NODETYPE_PADDING 4
+
+/* this is a "fake" type, not part of jffs2 proper */
+#define JFFS2_NODETYPE_CLEANREGION 8
+
+#define JFFS2_OBSOLETE_FLAG 1
+#define JFFS2_UNUSED_FLAG 2
+
+#define JFFS2_COMPR_NONE 0 /* no compression */
+#define JFFS2_COMPR_ZERO 1 /* data is all zeroes */
+#define JFFS2_COMPR_RTIME 2
+#define JFFS2_COMPR_RUBINMIPS 3
+#define JFFS2_COMPR_COPY 4
+#define JFFS2_COMPR_DYNRUBIN 5
+#define JFFS2_COMPR_ZLIB 6
+
+#define JFFS2_FNAME_STR "JFFS2FNAME"
+#define JFFS2_FTOT_STR "JFFS2FTOT"
+#define JFFS2_FSIZE_STR "JFFS2FSIZE"
+
+/* TODO: find a better way to deal with char vs. jint8 */
+typedef unsigned char jint8;
+typedef unsigned short jint16;
+typedef unsigned int jint32;
+
+struct jffs2_unknown_node {
+ jint16 magic;
+ jint16 nodetype;
+ jint32 totlen;
+ jint32 hdr_crc;
+};
+
+struct jffs2_raw_dirent {
+ jint16 magic;
+ jint16 nodetype;
+ jint32 totlen;
+ jint32 hdr_crc;
+ jint32 pino;
+ jint32 version;
+ jint32 ino;
+ jint32 mctime;
+ jint8 nsize;
+ jint8 type;
+ jint8 unused[2];
+ jint32 node_crc;
+ jint32 name_crc;
+ jint8 name[0];
+};
+
+struct jffs2_raw_inode {
+ jint16 magic;
+ jint16 nodetype;
+ jint32 totlen;
+ jint32 hdr_crc;
+ jint32 ino;
+ jint32 version;
+ jint32 mode;
+ jint16 uid;
+ jint16 gid;
+ jint32 isize;
+ jint32 atime;
+ jint32 mtime;
+ jint32 ctime;
+ jint32 offset;
+ jint32 csize;
+ jint32 dsize;
+ jint8 compr;
+ jint8 usercompr;
+ jint16 flags;
+ jint32 data_crc;
+ jint32 node_crc;
+ jint8 data[0];
+};
+
+struct jffs2_cleanregion_node {
+ jint16 magic;
+ jint16 nodetype;
+ jint32 totlen;
+ jint32 physaddr;
+};
+
+struct jffs2_umoninfo {
+ jint8 quiet;
+ jint32 direntsize;
+ char direntname[JFFS2_MAXPATH+1];
+};
+
+/*
+ * The crc32 function used in this jffs2 command is from MTD utils.
+ *
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+static const jint32 jffs2_crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+static jint32
+jffs2crc32(jint32 val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+
+ while (--len >= 0)
+ val = jffs2_crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+
+ return val;
+}
+
+static char *
+compr2str(jint8 compr)
+{
+ switch(compr) {
+ case JFFS2_COMPR_NONE:
+ return "none";
+ case JFFS2_COMPR_ZERO:
+ return "zero";
+ case JFFS2_COMPR_RTIME:
+ return "rtime";
+ case JFFS2_COMPR_RUBINMIPS:
+ return "rubinmips";
+ case JFFS2_COMPR_COPY:
+ return "copy";
+ case JFFS2_COMPR_DYNRUBIN:
+ return "dynrubin";
+ case JFFS2_COMPR_ZLIB:
+ return "zlib";
+ default:
+ return "???";
+ }
+}
+
+static void
+showUnknown(int nodenum, struct jffs2_unknown_node *u)
+{
+ printf("Node %3d (%04x=UNKNOWN, size=%ld) 0x%08lx...\n",
+ nodenum, u->nodetype, u->totlen, (long)u);
+ printf(" type: 0x%04x\n",u->nodetype);
+}
+
+static void
+showPadding(int nodenum, struct jffs2_raw_inode *i)
+{
+ printf("Node %3d (PADDING, size=%ld) @ 0x%08lx...\n",
+ nodenum, i->totlen, (long)i);
+}
+
+static void
+showCleanmarker(int nodenum,struct jffs2_raw_inode *i)
+{
+ printf("Node %3d (CLEANMARKER, size=%ld) @ 0x%08lx...\n",
+ nodenum,i->totlen, (long)i);
+}
+
+static void
+showInode(int nodenum,struct jffs2_raw_inode *i)
+{
+ printf("Node %3d (%04x=INODE, size=%ld) @ 0x%08lx",
+ nodenum, i->nodetype, i->totlen, (long)i);
+ if (i->dsize)
+ printf(" (data at 0x%08lx)",&i->data);
+ printf("...\n");
+ printf(" ino: 0x%06lx, mode: 0x%06lx, version: 0x%06lx\n",
+ i->ino,i->mode,i->version);
+ printf(" isize: 0x%06lx, csize: 0x%06lx, dsize: 0x%06lx\n",
+ i->isize, i->csize, i->dsize);
+ printf(" offset: 0x%06lx, compr: %8s, ucompr: %s\n",
+ i->offset,compr2str(i->compr),compr2str(i->usercompr));
+}
+
+static void
+showDirent(int nodenum, struct jffs2_raw_dirent *d)
+{
+ jint8 i;
+
+ printf("Node %3d (%04x=DIRENT <\"",nodenum,d->nodetype);
+ for(i=0;i<d->nsize;i++)
+ putchar(d->name[i]);
+ printf("\">, size=%ld)",d->totlen);
+ printf(" @ 0x%06lx",(long)d);
+ if (d->ino == 0)
+ printf(" (deleted)");
+ if ((d->nodetype & JFFS2_NODE_ACCURATE) == 0)
+ printf(" (obsolete)");
+ printf("...\n");
+ printf(" ino: 0x%06lx, pino: 0x%06lx, version: 0x%06lx\n",
+ d->ino, d->pino, d->version);
+ printf(" nsize: 0x%06lx, type: 0x%06lx\n",
+ d->nsize, d->type);
+}
+
+static void
+showCleanregion(int nodenum, struct jffs2_cleanregion_node *c)
+{
+ printf("Node %3d (%04x=CLEANREGION)...\n",
+ nodenum, c->nodetype);
+ printf(" physaddr: 0x%06lx, size: %d\n",
+ c->physaddr, c->totlen);
+}
+
+
+/* jzlibcpy():
+ * A variation on "memcpy", but using JFFS2's zlib decompression...
+ */
+static int
+jzlibcpy(char *src, char *dest, ulong srclen, ulong destlen)
+{
+#if INCLUDE_JFFS2ZLIB
+ z_stream strm;
+ int ret;
+
+ if ((strm.workspace = malloc(zlib_inflate_workspacesize())) == 0)
+ return(-1);
+
+ if (Z_OK != zlib_inflateInit(&strm)) {
+ free(strm.workspace);
+ return -1;
+ }
+
+ strm.next_in = (unsigned char *)src;
+ strm.avail_in = srclen;
+ strm.total_in = 0;
+
+ strm.next_out = (unsigned char *)dest;
+ strm.avail_out = destlen;
+ strm.total_out = 0;
+
+ while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK);
+
+ zlib_inflateEnd(&strm);
+ free(strm.workspace);
+ return(strm.total_out);
+#else
+ printf("INCLUDE_JFFS2ZLIB not set in config.h, can't decompress\n");
+ return -1;
+#endif
+}
+
+
+static int
+is_accurate_node(struct jffs2_unknown_node *u)
+{
+ return ((u->magic == JFFS2_MAGIC)
+ && (u->nodetype & JFFS2_NODE_ACCURATE)) ? 1 : 0;
+}
+
+static int
+is_cleanmarker(struct jffs2_unknown_node *u)
+{
+ jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK;
+ return nodetype == JFFS2_NODETYPE_CLEANMARKER ? 1 : 0;
+}
+
+static int
+is_padding(struct jffs2_unknown_node *u)
+{
+ jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK;
+ return nodetype == JFFS2_NODETYPE_PADDING ? 1 : 0;
+}
+
+static int
+is_inode(struct jffs2_unknown_node *u)
+{
+ jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK;
+ return nodetype == JFFS2_NODETYPE_INODE ? 1 : 0;
+}
+
+static int
+is_dirent(struct jffs2_unknown_node *u)
+{
+ jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK;
+ return nodetype == JFFS2_NODETYPE_DIRENT ? 1 : 0;
+}
+
+static int
+is_deleted_dirent(struct jffs2_unknown_node *u)
+{
+ struct jffs2_raw_dirent *d;
+
+ if (is_dirent(u)) {
+ d = (struct jffs2_raw_dirent *)u;
+ if (d->ino == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+is_cleanregion(struct jffs2_unknown_node *u)
+{
+ return u->nodetype == JFFS2_NODETYPE_CLEANREGION ? 1 : 0;
+}
+
+static struct jffs2_unknown_node *
+allocCleanRegion(jint32 base, jint32 size)
+{
+ struct jffs2_cleanregion_node *c;
+
+ c = (struct jffs2_cleanregion_node*)malloc(sizeof(*c));
+ if (c) {
+ memset((void*)c, 0, sizeof(*c));
+ c->nodetype = JFFS2_NODETYPE_CLEANREGION;
+ c->physaddr = base;
+ c->totlen = size;
+ }
+ else
+ printf("%s: malloc() failed\n", __func__);
+ return (struct jffs2_unknown_node*)c;
+}
+
+static jint32
+calcHdrCrc(struct jffs2_unknown_node *u)
+{
+ return jffs2crc32(0, (void*)u,
+ sizeof(*u) - sizeof(u->hdr_crc));
+}
+
+static jint32
+calcInodeCrc(struct jffs2_raw_inode *i)
+{
+ return jffs2crc32(0, (void*)i,
+ sizeof(*i) - sizeof(i->node_crc)
+ - sizeof(i->data_crc));
+}
+
+static jint32
+calcDirentCrc(struct jffs2_raw_dirent *d)
+{
+ return jffs2crc32(0, (void*)d,
+ sizeof(*d) - sizeof(d->node_crc)
+ - sizeof(d->name_crc));
+}
+
+static jint32
+calcDataCrc(void *data, int len)
+{
+ return jffs2crc32(0, data, len);
+}
+
+static int jffs2_verify_crc = 0;
+
+static struct jffs2_unknown_node *
+findRawNode(ulong jaddr, ulong jlen,
+ ulong *newjaddr, ulong *newjlen)
+{
+ struct jffs2_unknown_node *u;
+ jint32 crc;
+ ulong size = 0;
+ long adj;
+
+ while (jlen && !gotachar()) {
+
+ adj = ulceil(jaddr, 4) - jaddr;
+ jaddr += adj;
+ jlen -= adj;
+
+ u = (struct jffs2_unknown_node *)jaddr;
+
+ if (is_accurate_node(u)) {
+
+ if (jffs2_verify_crc) {
+
+ crc = calcHdrCrc(u);
+ if (crc != u->hdr_crc)
+ printf("hdr_crc @ 0x%x: "
+ "calculated 0x%x read 0x%x (ignored)\n",
+ u, crc, u->hdr_crc);
+
+ if (is_dirent(u)) {
+ struct jffs2_raw_dirent *d;
+
+ d = (struct jffs2_raw_dirent*)u;
+ crc = calcDirentCrc(d);
+ if (crc != d->node_crc)
+ printf("dirent node_crc @ 0x%x: "
+ "calculated 0x%x read 0x%x (ignored)\n",
+ d, crc, d->node_crc);
+
+ crc = calcDataCrc(d->name, d->nsize);
+ if (crc != d->name_crc)
+ printf("dirent name_crc @ 0x%x: "
+ "calculated 0x%x read 0x%x (ignored)\n",
+ d, crc, d->name_crc);
+ }
+
+ else if (is_inode(u)) {
+ struct jffs2_raw_inode *i;
+
+ i = (struct jffs2_raw_inode*)u;
+ crc = calcInodeCrc(i);
+ if (crc != i->node_crc)
+ printf("inode node_crc @ 0x%x: "
+ "calculated 0x%x read 0x%x (ignored)\n",
+ i, crc, i->node_crc);
+
+ crc = calcDataCrc(i->data,
+ (i->compr != JFFS2_COMPR_NONE) ?
+ i->csize : i->dsize);
+ if (crc != i->data_crc)
+ printf("inode data_crc @ 0x%x: "
+ "calculated 0x%x read 0x%x (ignored)\n",
+ i, crc, i->data_crc);
+ }
+ }
+
+ if (newjaddr) *newjaddr = jaddr;
+ if (newjlen) *newjlen = jlen;
+ return u;
+ }
+
+ else {
+ /* manufacture a node representing unused memory */
+
+ /* TODO: more-carefully verify that this memory is truly
+ "unused", e.g. make sure there is a valid cleanmarker at the
+ beginning of the flash block, we don't span the end of a
+ flash section, etc. */
+
+ /* TODO: it would be much faster to use a binary search for ff's
+ in the current flash sector, rather than a linear search for
+ them */
+
+ for (size = 0; jlen && !gotachar()
+ && *(ulong*)jaddr == 0xffffffffUL;
+ size += 4) {
+ jaddr += 4;
+ jlen -= 4;
+ }
+
+ if (size > sizeof(struct jffs2_raw_inode)) {
+ if (newjaddr) *newjaddr = jaddr - size;
+ if (newjlen) *newjlen = jlen + size;
+ return allocCleanRegion((ulong)u, size);
+ }
+
+ if (jlen) {
+ jaddr += 4;
+ jlen -= 4;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+struct jffs2_unknown_node_list {
+ struct jffs2_unknown_node_list *next;
+ struct jffs2_unknown_node_list *prev;
+ ulong nodenum;
+ struct jffs2_unknown_node *u;
+};
+
+static int
+is_empty_list (struct jffs2_unknown_node_list *l)
+{
+ if ((l == NULL) || (l->next == NULL)
+ || (l->next->next == NULL)) return 1;
+ return 0;
+}
+
+static struct jffs2_unknown_node_list *
+allocListNode(ulong nodenum, struct jffs2_unknown_node *u)
+{
+ struct jffs2_unknown_node_list *cu;
+
+ cu = (struct jffs2_unknown_node_list*)malloc(sizeof(*cu));
+ if (cu) {
+ cu->next = NULL;
+ cu->prev = NULL;
+ cu->u = u;
+ cu->nodenum = nodenum;
+ }
+ else {
+ /* TODO: report/handle allocation failure */
+ printf("allocListNode: malloc() failed\n");
+ }
+ return cu;
+}
+
+static struct jffs2_unknown_node_list *
+removeNodeFromList(struct jffs2_unknown_node_list *u)
+{
+ if (u->prev != NULL)
+ u->prev->next = u->next;
+ if (u->next != NULL)
+ u->next->prev = u->prev;
+ return u;
+}
+
+static int
+delListNode(struct jffs2_unknown_node_list *u)
+{
+ removeNodeFromList(u);
+ if (u->u != NULL && is_cleanregion(u->u))
+ free(u->u);
+ free(u);
+ return 0;
+}
+
+static struct jffs2_unknown_node_list *
+initNodeList(struct jffs2_unknown_node_list **a)
+{
+ /* create "sentinel" nodes */
+ *a = allocListNode(-1, NULL);
+ if (*a == NULL) return NULL;
+ (*a)->next = allocListNode(-1, NULL);
+ if ((*a)->next == NULL) return NULL;
+ (*a)->next->prev = *a;
+
+ return *a;
+}
+
+static struct jffs2_unknown_node_list *
+discardNodeList(struct jffs2_unknown_node_list *list)
+{
+ if (list == NULL)
+ return NULL;
+ while (list->prev != NULL)
+ list = list->prev;
+ while (list->next != NULL)
+ delListNode(list->next);
+ delListNode(list);
+ return NULL;
+}
+
+
+
+
+static struct jffs2_unknown_node_list *
+insertListNodeAfter(struct jffs2_unknown_node_list *after,
+ struct jffs2_unknown_node_list *n)
+{
+ n->prev = after;
+ n->next = after->next;
+ after->next->prev = n;
+ after->next = n;
+
+ return n;
+}
+
+static int
+scanMedium(ulong jaddr, ulong jlen,
+ struct jffs2_unknown_node_list *list,
+ void (*progress)(int percent))
+{
+ struct jffs2_unknown_node *u;
+ struct jffs2_unknown_node_list *n;
+ ulong nodetot = 0UL;
+ ulong jlen_orig = jlen;
+
+ if (progress) {
+ printf("scanning JFFS2 medium "
+ "at 0x%x, %d bytes...\n",
+ jaddr, jlen);
+ progress(0);
+ }
+
+ while (!gotachar()
+ && jlen
+ && (u = findRawNode(jaddr, jlen, &jaddr, &jlen))) {
+
+ if (progress)
+ progress(((unsigned long long)(jlen_orig - jlen) * 100)
+ / jlen_orig);
+
+ if (is_inode(u)
+ || is_dirent(u)
+ || is_deleted_dirent(u)
+ || is_cleanmarker(u)
+ || is_cleanregion(u)) {
+
+ n = allocListNode(nodetot++, u);
+ if (n != NULL)
+ insertListNodeAfter(list, n);
+ else {
+ printf("%s: allocListNode returned NULL (fatal)\n",
+ __func__);
+ return -1;
+ }
+ }
+ else printf("%s: unrecognized nodetype %x (ignored)\n",
+ __func__, u->nodetype & JFFS2_NODETYPE_MASK);
+
+ jlen -= u->totlen;
+ jaddr += u->totlen;
+ }
+
+ return nodetot;
+}
+
+static int
+formatMedium (ulong jaddr, ulong jlen,
+ void (*progress)(int percent))
+{
+ int ret;
+ int start, end, sect, size;
+ uchar *addr;
+ struct jffs2_unknown_node cm = {
+ .magic = JFFS2_MAGIC,
+ .nodetype = (JFFS2_NODETYPE_CLEANMARKER
+ | JFFS2_FEATURE_RWCOMPAT_DELETE
+ | JFFS2_NODE_ACCURATE),
+ .totlen = sizeof(struct jffs2_unknown_node),
+ };
+
+ if (!jlen) return -1;
+
+ cm.hdr_crc = calcHdrCrc(&cm);
+
+ if (addrtosector((uchar*)jaddr, &start,
+ NULL, NULL)) {
+ printf("%s: invalid starting address %x (error, abort)\n",
+ __func__, jaddr);
+ return -1;
+ }
+
+ if (addrtosector((uchar*)(jaddr + jlen - 1), &end,
+ NULL, NULL)) {
+ printf("%s: invalid ending address %x (error, abort)\n",
+ __func__, jaddr + jlen - 1);
+ return -1;
+ }
+
+ ret = sectortoaddr(start, NULL, (uchar**)(&addr));
+ if (ret || ((ulong)addr != jaddr)) {
+ printf("%s: must start at a sector boundary (abort)\n",
+ __func__);
+ return -1;
+ }
+
+ ret = sectortoaddr(end, &size, (uchar**)(&addr));
+ if (ret || ((ulong)(addr + size) != (jaddr + jlen))) {
+ printf("%s: must end at a sector boundary (abort)\n",
+ __func__);
+ return -1;
+ }
+
+ printf("formatting JFFS2 medium "
+ "at 0x%x, %d sectors, %d bytes...\n",
+ jaddr, end - start, jlen);
+
+ for (sect = start; sect < end; sect++) {
+
+ if (progress)
+ progress(((sect - start) * 100) / (end - start));
+
+ if ((ret = AppFlashErase(sect)) != 1) {
+ printf("%s: error %d from AppFlashErase, "
+ "sector %d (abort)\n",
+ __func__, ret, sect);
+ return -1;
+ }
+
+ if ((ret = sectortoaddr(sect, &size, (uchar**)(&addr))) != 0) {
+ printf("%s: error %d from sectortoaddr(%d, NULL, &addr) (abort)\n",
+ __func__, ret, sect);
+ return -1;
+ }
+
+ if (size < sizeof(cm)) {
+ printf("%s: size of sector %d "
+ "is smaller than a CLEANMARKER (abort)\n",
+ __func__, sect);
+ return -1;
+ }
+
+ if ((ret = AppFlashWrite(addr, (void*)&cm, cm.totlen)) != 0) {
+ printf("%s: error %d from AppFlashWrite, sector %d (abort)\n",
+ __func__, ret, sect);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+showNode(ulong nodenum, struct jffs2_unknown_node *u)
+{
+ if (is_inode(u))
+ showInode(nodenum, (struct jffs2_raw_inode*)u);
+ else if (is_dirent(u) || is_deleted_dirent(u))
+ showDirent(nodenum, (struct jffs2_raw_dirent*)u);
+ else if (is_cleanmarker(u))
+ showCleanmarker(nodenum, (struct jffs2_raw_inode*)u);
+ else if (is_cleanregion(u))
+ showCleanregion(nodenum, (struct jffs2_cleanregion_node*)u);
+ else if (is_padding(u))
+ showPadding(nodenum, (struct jffs2_raw_inode*)u);
+ else showUnknown(nodenum, u);
+ return 0;
+}
+
+static struct jffs2_unknown_node_list *
+findNodeOfType(struct jffs2_unknown_node_list *list,
+ jint16 nodetype)
+{
+ while (list != NULL && !gotachar()) {
+ if (list->u != NULL
+ && ((nodetype == JFFS2_NODETYPE_MASK)
+ || ((list->u->nodetype & JFFS2_NODETYPE_MASK) == nodetype)))
+ return list;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+static struct jffs2_unknown_node_list *
+findCleanRegion(struct jffs2_unknown_node_list *list,
+ ulong minsize)
+{
+ while (list != NULL && !gotachar()) {
+ if (list->u != NULL
+ && is_cleanregion(list->u)) {
+
+ if (list->u->totlen >= minsize)
+ return list;
+ }
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * Finds an inode entry in <list> where u->ino == <ino>.
+ *
+ * Returns NULL if no inode of the requested number is found. Otherwise:
+ *
+ * <version> == -1: the highest-version entry in the list is returned
+ * <version> != -1: the specified entry in the list is returned
+ *
+ * For ownership and mode information, you want the latest inode
+ * entry. The only time a specific entry is interesting is when
+ * replaying the entire inode log to reconstruct its data or other
+ * history.
+ */
+static struct jffs2_unknown_node_list *
+findInode(struct jffs2_unknown_node_list *list,
+ jint32 ino, jint32 version)
+{
+ struct jffs2_raw_inode *i;
+ struct jffs2_unknown_node_list *ulatest = NULL;
+
+ while (list != NULL && !gotachar()
+ && (list = findNodeOfType(list, JFFS2_NODETYPE_INODE)) != NULL) {
+
+ i = (struct jffs2_raw_inode*)list->u;
+ if (i->ino == ino) {
+ if (version != -1 && version == i->version)
+ return list;
+ else if (version == -1) {
+ if (ulatest == NULL)
+ ulatest = list;
+ else if (i->version > ((struct jffs2_raw_inode*)(ulatest->u))->version)
+ ulatest = list;
+ }
+ }
+
+ list = list->next;
+ }
+
+ if (version == -1 && ulatest != NULL)
+ return ulatest;
+
+ return NULL;
+}
+
+/*
+ * Searches <list> for a dirent that matches <pino>, <ino>, and/or
+ * <name>. Returns a pointer to the first matching dirent node found
+ * in <list>, including deleted dirent nodes, or NULL if a matching
+ * dirent cannot be found.
+ */
+static struct jffs2_unknown_node_list *
+findNextMatchingDirent(struct jffs2_unknown_node_list *list,
+ jint32 pino, jint32 ino, char *name)
+{
+ struct jffs2_raw_dirent *d;
+
+ while (!gotachar()
+ && (list = findNodeOfType(list, JFFS2_NODETYPE_DIRENT)) != NULL) {
+
+ d = (struct jffs2_raw_dirent*)list->u;
+
+ if ((pino == -1 || (pino == d->pino))
+ && (ino == -1 || (ino == d->ino))) {
+
+ if ((name == NULL)
+ || ((strlen(name) == d->nsize)
+ && !memcmp((char*)name, (char*)(d->name), d->nsize)))
+ return list;
+ }
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * Finds the highest-version, non-deleted dirent that matches the
+ * supplied parameters, or NULL if the highest-version dirent is a
+ * deleted one
+ */
+static struct jffs2_unknown_node_list *
+findMatchingDirent(struct jffs2_unknown_node_list *list,
+ jint32 pino, jint32 ino, char *name)
+{
+ struct jffs2_unknown_node_list *u, *uret;
+ struct jffs2_raw_dirent *d, *dret;
+
+ for (uret = NULL, u = list; u != NULL
+ && ((u = findNextMatchingDirent(u, pino, ino, name)) != NULL);
+ u = u->next) {
+
+ if (uret == NULL) {
+ uret = u;
+ continue;
+ }
+
+ dret = (struct jffs2_raw_dirent*)uret->u;
+ d = (struct jffs2_raw_dirent*)u->u;
+
+ if (d->version > dret->version)
+ uret = u;
+ }
+
+ if (uret == NULL)
+ return NULL;
+
+ if (is_deleted_dirent(uret->u))
+ return NULL;
+
+ return uret;
+}
+
+static struct jffs2_unknown_node_list *
+findNodeOfTypeRange(struct jffs2_unknown_node_list *list,
+ jint16 nodetype,
+ char *pino,
+ char *ino)
+{
+ struct jffs2_raw_dirent *d;
+ struct jffs2_raw_inode *i;
+
+ while (!gotachar()
+ && (list = findNodeOfType(list, nodetype)) != NULL) {
+
+ if (is_dirent(list->u)) {
+ d = (struct jffs2_raw_dirent*)(list->u);
+ if ((pino == NULL || inRange(pino, d->pino))
+ && (ino == NULL || inRange(ino, d->ino)))
+ return list;
+ }
+
+ else if (is_inode(list->u)) {
+ i = (struct jffs2_raw_inode*)(list->u);
+ if (ino == NULL || inRange(ino, i->ino))
+ return list;
+ }
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+static void
+showInodeType(int type)
+{
+ if (is_reg(type)) printf("-");
+ else if (is_dir(type)) printf("d");
+ else if (is_lnk(type)) printf("l");
+ else if (is_blk(type)) printf("b");
+ else if (is_chr(type)) printf("c");
+ else if (is_fifo(type)) printf("p");
+ else printf("?");
+}
+
+static void
+showInodePerm(int perm)
+{
+ printf("%s", perm & S_IRUSR ? "r" : "-");
+ printf("%s", perm & S_IWUSR ? "w" : "-");
+ printf("%s", perm & S_IXUSR ? "x" : "-");
+
+ printf("%s", perm & S_IRGRP ? "r" : "-");
+ printf("%s", perm & S_IWGRP ? "w" : "-");
+ printf("%s", perm & S_IXGRP ? "x" : "-");
+
+ printf("%s", perm & S_IROTH ? "r" : "-");
+ printf("%s", perm & S_IWOTH ? "w" : "-");
+ printf("%s", perm & S_IXOTH ? "x" : "-");
+}
+
+static int
+showInodeMeta(struct jffs2_raw_inode *i)
+{
+ char buf[80];
+ struct tm t;
+
+ showInodeType(i->mode);
+ showInodePerm(i->mode);
+ gmtime_r(i->atime, &t);
+ asctime_r(&t, buf);
+
+ printf(" %4d %4d %6d %s ",
+ i->uid, i->gid, i->isize, buf);
+ return 0;
+}
+
+static int
+showNodesOfType(struct jffs2_unknown_node_list *list,
+ jint16 nodetype)
+{
+ int count = 0;
+
+ while ((list = findNodeOfType(list, nodetype)) != NULL
+ && !gotachar()) {
+ showNode(list->nodenum, list->u);
+ count++;
+ list = list->next;
+ }
+ return count;
+}
+
+static int
+showNodesOfTypeRange(struct jffs2_unknown_node_list *list,
+ jint16 nodetype,
+ char *pino,
+ char *ino)
+{
+ int count = 0;
+
+ while (list && !gotachar()) {
+ list = findNodeOfTypeRange(list, nodetype, pino, ino);
+ if (list != NULL && list->u != NULL) {
+ showNode(list->nodenum, list->u);
+ count++;
+ }
+ if (list != NULL)
+ list = list->next;
+ }
+ return count;
+}
+
+static struct jffs2_unknown_node_list *
+findNodeOfNumRange(struct jffs2_unknown_node_list *list,
+ char *nodenum)
+{
+ while (!gotachar() && list) {
+
+ if (list->u && inRange(nodenum, list->nodenum))
+ return list;
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+static int
+showNodesOfNumRange(struct jffs2_unknown_node_list *list,
+ char *range)
+{
+ int nodetot = 0;
+
+ while (list && (list = findNodeOfNumRange(list, range))) {
+ nodetot++;
+ showNode(list->nodenum, list->u);
+ list = list->next;
+ }
+
+ return nodetot;
+}
+
+static struct jffs2_unknown_node_list *
+findDirentByPath(struct jffs2_unknown_node_list *list,
+ char *path)
+{
+#define JFFS2_ROOT_PINO 1
+#define JFFS2_PATH_SEPARATOR "/"
+
+ char subpath[JFFS2_MAXPATH + 1];
+ int pathlen;
+ jint32 pino = JFFS2_ROOT_PINO;
+ struct jffs2_unknown_node_list *u = NULL;
+ struct jffs2_raw_dirent *d;
+
+ if (strlen(path) > JFFS2_MAXPATH
+ || (path == NULL))
+ return NULL;
+
+ while (*path) {
+
+ path += strspn(path, JFFS2_PATH_SEPARATOR);
+ pathlen = strcspn(path, JFFS2_PATH_SEPARATOR);
+ strncpy(subpath, path, pathlen);
+ subpath[pathlen] = 0;
+ path += pathlen;
+
+ u = findMatchingDirent(list, pino, -1, subpath);
+ if (u == NULL)
+ return NULL;
+
+ d = (struct jffs2_raw_dirent *)u->u;
+ pino = d->ino;
+ }
+
+ if (is_deleted_dirent(u->u))
+ return NULL;
+ return u;
+}
+
+static int
+listDirent(struct jffs2_unknown_node_list *list,
+ struct jffs2_unknown_node_list *u,
+ struct jffs2_umoninfo *umip)
+{
+ struct jffs2_raw_dirent *d;
+ struct jffs2_raw_inode *i;
+
+ d = (struct jffs2_raw_dirent*)u->u;
+
+ u = findInode(list, d->ino, -1);
+ if (u == NULL)
+ return 0;
+
+ i = (struct jffs2_raw_inode*)u->u;
+ if (!umip->quiet)
+ showInodeMeta(i);
+
+ memset(umip->direntname, 0, sizeof(umip->direntname));
+ memcpy(umip->direntname, (void*)d->name, d->nsize);
+ umip->direntsize = i->isize;
+
+ if (is_dir(i->mode))
+ umip->direntname[d->nsize] = '/';
+
+ if (!umip->quiet)
+ printf("%s\n", umip->direntname);
+
+ return 1;
+}
+
+static int
+listDirentByPath(struct jffs2_unknown_node_list *list,
+ char *path, struct jffs2_umoninfo *umip)
+{
+ struct jffs2_unknown_node_list *u = NULL;
+ struct jffs2_unknown_node_list *n;
+ struct jffs2_raw_dirent *d = NULL;
+ struct jffs2_raw_inode *i;
+ jint32 pino = JFFS2_ROOT_PINO;
+ int ret = 0;
+
+ /* TODO: wildcards? */
+
+ if (path != NULL && strlen(path) != 0
+ && strcspn(path, JFFS2_PATH_SEPARATOR) != 0) {
+
+ u = findDirentByPath(list, path);
+ if (u == NULL)
+ goto not_found;
+
+ d = (struct jffs2_raw_dirent*)u->u;
+ n = findInode(list, d->ino, -1);
+ if (n == NULL)
+ goto not_found;
+
+ i = (struct jffs2_raw_inode*)n->u;
+ if (!is_dir(i->mode))
+ return listDirent(list, u, umip);
+ else pino = d->ino;
+ }
+
+ for (u = list; u != NULL
+ && (u = findMatchingDirent(u, pino, -1, NULL)) != NULL;
+ u = u->next) {
+ ret += listDirent(list, u, umip);
+ }
+
+ return ret;
+
+ not_found:
+ if (!umip->quiet)
+ printf("%s: no such file or directory\n", path);
+ return 0;
+
+}
+
+
+static int
+readRawInode(struct jffs2_raw_inode *i,
+ jint32 offset /* ... into start of inode */,
+ jint32 len /* ... of bytes to take from inode */,
+ void (*callback)(void *args, int offset, void *buf, int size),
+ void *callback_args)
+{
+ static void *temp = NULL;
+
+ /* TODO: we could allocate a 4K buffer here, read into that, and
+ then pass that buffer to the callback (instead of having the
+ callback read from flash directly); this would allow us to put
+ jffs2 into something other than bulk NOR flash
+
+ (is there a uMON flash-reading function that handles
+ device-specific i/o details?)
+ */
+ switch (i->compr) {
+
+ case JFFS2_COMPR_NONE:
+ callback(callback_args, i->offset + offset,
+ (void*)(i->data + offset), len);
+ break;
+
+ case JFFS2_COMPR_ZERO:
+ callback(callback_args, i->offset + offset, 0, len);
+ break;
+
+ case JFFS2_COMPR_ZLIB:
+ if (temp == NULL && ((temp = malloc(4096)) == NULL)) {
+ printf("%s: cannot alloc tempspace (aborted)\n",
+ __func__);
+ return -1;
+ }
+
+ if (i->dsize > 4096) {
+ printf("%s: inode dsize > 4K (aborted)\n", __func__);
+ return -1;
+ }
+
+ if (jzlibcpy((void*)(i->data), temp, i->csize, i->dsize) < 0)
+ return -1;
+ callback(callback_args, i->offset + offset, temp + offset, len);
+ break;
+
+ case JFFS2_COMPR_RTIME:
+ case JFFS2_COMPR_RUBINMIPS:
+ case JFFS2_COMPR_DYNRUBIN:
+ printf("%s: unsupported compression algorithm (fragment ignored)\n",
+ compr2str(i->compr));
+ break;
+ }
+
+ return len;
+}
+
+/*
+ * Finds a region in <list> a.k.a. "fragment" that overlaps inode <i>,
+ * and populates that fragment with the contents of the inode. If the
+ * fragment is fully covered by the contents of the inode, then the
+ * fragment is removed from <list>; otherwise, the fragment list node
+ * is modified or bisected to record bytes that are still missing.
+ *
+ * Returns the number of bytes written, or 0 to indicate there were no
+ * fragments that overlapped the inode, or a negative number for
+ * error.
+ *
+ * You'll need to call this function with the same inode until it
+ * returns zero or an error, since we return at the first occurence of
+ * a valid fragment. Depending on the sequence of inodes, one or more
+ * fragments could be covered by the same inode and/or it might take
+ * multiple inodes to completely fill a fragment. That's just how
+ * jffs2 and other log-structured filesystems work.
+ */
+static int
+readFrag(struct jffs2_unknown_node_list *list,
+ struct jffs2_raw_inode *i,
+ void (*callback)(void *args, int offset, void *buf, int size),
+ void *callback_args)
+{
+ jint32 fstart, istart, fend, iend;
+ struct jffs2_cleanregion_node *frag;
+ struct jffs2_unknown_node *newfrag;
+
+ for ( ; list->next != NULL; list = list->next) {
+
+ /* we "shouldn't" have to do this, but since we're emptying the
+ list entirely the list pointer is always aimed at the sentinel
+ node; skip it if we find it, and use the ->next == NULL case to
+ spot the end of the list (contrary to the rest of the code in
+ this compilation unit) */
+ if (list->u == NULL) continue;
+
+ frag = (struct jffs2_cleanregion_node*)list->u;
+
+ fstart = frag->physaddr;
+ istart = i->offset;
+ fend = frag->physaddr + frag->totlen;
+ iend = i->offset + i->dsize;
+
+ if (fend <= istart || iend <= fstart)
+ continue;
+
+ if (fstart >= istart && fend <= iend) {
+ delListNode(list);
+ return readRawInode(i, fstart - istart, fend - fstart,
+ callback, callback_args);
+ }
+
+ if (fstart <= istart && fend <= iend) {
+ frag->totlen = istart - fstart;
+ return readRawInode(i, 0, fend - istart,
+ callback, callback_args);
+ }
+
+ if (fstart >= istart && fend >= iend) {
+ frag->physaddr = iend;
+ frag->totlen = fend - iend;
+ return readRawInode(i, fstart - istart, iend - fstart,
+ callback, callback_args);
+ }
+
+ frag->totlen = iend - fend;
+ newfrag = allocCleanRegion(iend, fend - iend);
+ insertListNodeAfter(list, allocListNode(0, newfrag));
+
+ return readRawInode(i, 0, i->dsize, callback, callback_args);
+ }
+
+ return 0;
+}
+
+
+static int
+readInode(struct jffs2_unknown_node_list *list,
+ jint32 ino,
+ void (*callback)(void *callback_args,
+ int offset, void *buf, int size),
+ void *callback_args)
+{
+ struct jffs2_unknown_node_list *frags;
+ struct jffs2_unknown_node_list *u;
+ struct jffs2_unknown_node *fr;
+ struct jffs2_unknown_node_list *f;
+ struct jffs2_raw_inode *i;
+ int ret;
+ int len = 0;
+
+ if ((u = findInode(list, ino, -1)) == NULL) {
+ printf("%d: no such inode\n", ino);
+ return -1;
+ }
+
+ i = (struct jffs2_raw_inode*)u->u;
+ if (i->isize == 0)
+ return 0;
+
+ if (initNodeList(&frags) == NULL) {
+ printf("%s: initNodeList() returned NULL (aborted)\n",
+ __func__);
+ return -1;
+ }
+
+ if ((fr = allocCleanRegion(0, i->isize)) == NULL)
+ goto fail_alloc_initial_region;
+ if ((f = allocListNode(0, fr)) == NULL)
+ goto fail_alloc_initial_node;
+ insertListNodeAfter(frags, f);
+
+ /*
+ * Note: The convention in most of this compilation unit is for list
+ * pointers to point to the first valid list member. However, in
+ * the case of the fragment list we know the caller is going to be
+ * removing nodes, including the first valid list member. Thus,
+ * we'll keep the list pointer on the sentinel node since that one
+ * never goes away. (The readFrag() iterator knows about this, and
+ * changes its list walking logic accordingly).
+ */
+
+ do {
+ i = (struct jffs2_raw_inode*)u->u;
+ do {
+ ret = readFrag(frags, i, callback, callback_args);
+ if (ret >= 0) len += ret;
+ } while (ret > 0);
+
+ u = findInode(list, ino, i->version - 1);
+ } while (!is_empty_list(frags) && u != NULL);
+
+ if (!is_empty_list(frags))
+ printf("%s: warning, nonempty fragment list "
+ "(missing inode?) (ignored)\n");
+
+ while(frags->next)
+ delListNode(frags->next);
+ delListNode(frags);
+
+ return len;
+
+ fail_alloc_initial_node:
+ free(fr);
+ printf("%s: allocListNode() returned NULL (aborted)\n",
+ __func__);
+ return 0;
+ fail_alloc_initial_region:
+ printf("%s: allocCleanRegion() returned NULL (aborted)\n",
+ __func__);
+ return 0;
+}
+
+static int
+readDirent(struct jffs2_unknown_node_list *list, char *path,
+ void (*callback)(void *args,
+ int offset, void *buf, int size),
+ void *callback_args)
+{
+ struct jffs2_unknown_node_list *u;
+ struct jffs2_raw_dirent *d;
+ struct jffs2_raw_inode *i;
+
+ u = findDirentByPath(list, path);
+ if (u == NULL)
+ goto no_such_file;
+
+ d = (struct jffs2_raw_dirent *)u->u;
+ u = findInode(list, d->ino, -1);
+ if (u == NULL)
+ goto no_such_inode;
+
+ i = (struct jffs2_raw_inode*)u->u;
+ if (!is_reg(i->mode))
+ goto not_a_file;
+
+ return readInode(list, d->ino, callback, callback_args);
+
+ no_such_file:
+ printf("%s: no such file or directory\n", path);
+ return -1;
+
+ no_such_inode:
+ printf("%d: no such inode\n", d->ino);
+ return -1;
+
+ not_a_file:
+ printf("%s: is %s\n", path,
+ is_dir(i->mode) ? "a directory" : "not a file");
+ return -1;
+}
+
+static struct jffs2_unknown_node *
+commitRawNode(struct jffs2_unknown_node_list *list,
+ struct jffs2_unknown_node *u)
+{
+ struct jffs2_unknown_node_list *c;
+ unsigned long adjtotlen;
+ int ret;
+
+ /* everything is 32-bit aligned in jffs2-land, so you always need a
+ region slightly larger than the data itself to accomodate the
+ address and length rounding we may apply later on */
+ c = findCleanRegion(list, u->totlen + 4);
+ if (c != NULL) {
+
+ struct jffs2_cleanregion_node *f = (struct jffs2_cleanregion_node*)c->u;
+
+ ret = AppFlashWrite((void*)(f->physaddr), (void*)u, u->totlen);
+ if (ret != 0)
+ printf("%s: AppFlashWrite returned %d (ignored)\n", __func__, ret);
+
+ ret = f->physaddr;
+
+ /* cleanregions must always begin on a 32-bit boundary */
+ adjtotlen = ulceil(u->totlen, 4);
+ f->totlen -= adjtotlen;
+ f->physaddr += adjtotlen;
+
+ return (struct jffs2_unknown_node*)ret;
+ }
+
+ return NULL;
+}
+
+static struct jffs2_raw_dirent *
+allocDirentNode (char *name)
+{
+ struct jffs2_raw_dirent *d;
+ int namelen = 0;
+
+ if (name != NULL)
+ namelen = strlen(name);
+
+ d = (struct jffs2_raw_dirent*)malloc(sizeof(*d) + namelen);
+ if (d == NULL) {
+ printf("%s: malloc() returned NULL (aborted)\n", __func__);
+ return NULL;
+ }
+
+ memset((void*)d, 0, sizeof(*d));
+
+ d->magic = JFFS2_MAGIC;
+ d->nodetype = JFFS2_NODETYPE_DIRENT
+ | JFFS2_NODE_ACCURATE
+ | JFFS2_FEATURE_ROCOMPAT
+ | JFFS2_FEATURE_RWCOMPAT_COPY;
+ memcpy((void*)d->name, name, d->nsize = namelen);
+ d->totlen = sizeof(*d) + d->nsize;
+
+ return d;
+}
+
+static void
+freeDirentNode(struct jffs2_raw_dirent *d)
+{
+ free(d);
+}
+
+
+static jint32
+nextPinoVersion(struct jffs2_unknown_node_list *list, jint32 pino)
+{
+ jint32 version = 0;
+
+ while(list) {
+ if (list->u && is_dirent(list->u)) {
+ struct jffs2_raw_dirent *d = (struct jffs2_raw_dirent*)list->u;
+
+ if (d->pino == pino && d->version > version)
+ version = d->version;
+ }
+ list = list->next;
+ }
+
+ return version + 1;
+}
+
+static struct jffs2_unknown_node_list *
+commitDirent(struct jffs2_unknown_node_list *list, ulong nodenum,
+ char *name, jint8 type, jint32 pino, jint32 ino,
+ jint32 version)
+{
+ struct jffs2_raw_dirent *d;
+ struct jffs2_unknown_node *dc;
+ struct jffs2_unknown_node_list *n;
+
+ d = allocDirentNode(name);
+ if (d == NULL)
+ return NULL;
+
+ d->type = type;
+ d->version = version;
+ d->pino = pino;
+ d->ino = ino;
+
+ d->hdr_crc = calcHdrCrc((struct jffs2_unknown_node *)d);
+ d->node_crc = calcDirentCrc(d);
+ d->name_crc = calcDataCrc(d->name, d->nsize);
+
+ dc = commitRawNode(list, (struct jffs2_unknown_node*)d);
+ freeDirentNode(d);
+
+ if (dc == NULL) /* TODO: error handling? */
+ return NULL;
+
+ if ((n = allocListNode(nodenum, dc)) != NULL)
+ return insertListNodeAfter(list, n);
+
+ return NULL;
+}
+
+static struct jffs2_unknown_node_list *
+moveDirent(struct jffs2_unknown_node_list *list,
+ int nodetot, char *oldpath, char *newpath)
+{
+ struct jffs2_unknown_node_list *u, *ui, *uold, *unew;
+ struct jffs2_raw_dirent *d = NULL;
+ struct jffs2_raw_inode *i;
+ jint32 pino;
+ jint32 nextver;
+
+ char newname[JFFS2_MAXPATH + 1];
+
+ uold = findDirentByPath(list, oldpath);
+ if (uold == NULL)
+ goto no_such;
+ d = (struct jffs2_raw_dirent*)uold->u;
+
+ unew = findDirentByPath(list, newpath);
+ if (unew != NULL) {
+ struct jffs2_raw_dirent *dnew;
+
+ dnew = (struct jffs2_raw_dirent*)unew->u;
+ ui = findInode(list, dnew->ino, -1);
+ i = (struct jffs2_raw_inode*)ui->u;
+ if (!is_dir(i->mode))
+ goto in_the_way;
+
+ pino = dnew->ino;
+ strncpy(newname, (void*)d->name, d->nsize);
+ newname[d->nsize] = 0;
+ }
+ else {
+ strcpy(newname, newpath);
+ pino = JFFS2_ROOT_PINO;
+ }
+
+ nextver = nextPinoVersion(list, pino);
+ u = commitDirent(list, nodetot++, newname,
+ d->type, pino, d->ino, nextver++);
+ /* TODO: error handling? */
+ u = commitDirent(list, nodetot++, oldpath,
+ d->type, d->pino, 0, nextver);
+ return u;
+
+ no_such:
+ printf("%s: no such file or directory\n", oldpath);
+ return NULL;
+
+ in_the_way:
+ /* (yes, we could delete this ourselves...) */
+ printf("%s already exists\n", newpath);
+ return NULL;
+}
+
+static struct jffs2_unknown_node_list *
+deleteDirent(struct jffs2_unknown_node_list *list,
+ int nodetot, char *path)
+{
+ struct jffs2_unknown_node_list *u, *ui;
+ struct jffs2_raw_dirent *d;
+ struct jffs2_raw_inode *i;
+ jint32 nextver;
+ char name[JFFS2_MAXPATH + 1];
+
+ u = findDirentByPath(list, path);
+ if (u == NULL)
+ goto no_such;
+ d = (struct jffs2_raw_dirent*)u->u;
+
+ ui = findInode(list, d->ino, -1);
+ i = (struct jffs2_raw_inode*)ui->u;
+ if (is_dir(i->mode)) {
+ /* TODO: make sure directory is empty */
+ printf("%s: is a directory (abort)\n", path);
+ return NULL;
+ }
+
+ strncpy(name, (void*)d->name, d->nsize);
+ name[d->nsize] = 0;
+
+ nextver = nextPinoVersion(list, d->pino);
+ u = commitDirent(list, nodetot++, name,
+ d->type, d->pino, 0, nextver);
+
+ return u;
+
+ no_such:
+ printf("%s: no such file or directory\n", path);
+ return NULL;
+}
+
+#define JFFS2_DEFAULT_UID 0
+#define JFFS2_DEFAULT_GID 0
+
+static struct jffs2_raw_inode *
+allocInode(jint32 ino, jint32 dsize)
+{
+ struct jffs2_raw_inode *i;
+
+ i = (struct jffs2_raw_inode*)malloc(sizeof(*i) + dsize);
+ if (i == NULL) {
+ printf("%s: malloc() returned NULL (aborted)\n", __func__);
+ return NULL;
+ }
+
+ memset((void*)i, 0, sizeof(*i) + dsize);
+
+ i->magic = JFFS2_MAGIC;
+ i->ino = ino;
+ i->nodetype = JFFS2_NODETYPE_INODE
+ | JFFS2_NODE_ACCURATE
+ | JFFS2_FEATURE_ROCOMPAT
+ | JFFS2_FEATURE_RWCOMPAT_COPY;
+ i->compr = JFFS2_COMPR_NONE;
+ i->dsize = i->csize = dsize;
+ i->totlen = sizeof(*i) + dsize;
+
+ return i;
+}
+
+static void
+freeInode(struct jffs2_raw_inode *i)
+{
+ free(i);
+}
+
+static jint32
+getUnusedIno(struct jffs2_unknown_node_list *list)
+{
+ /* by definition, the root pino is always taken... */
+ jint32 ino = JFFS2_ROOT_PINO + 1;
+
+ while (!gotachar()
+ && (list = findNodeOfType(list, JFFS2_NODETYPE_INODE)) != NULL) {
+ struct jffs2_raw_inode *i = (struct jffs2_raw_inode*)list->u;
+ if (i->ino > ino)
+ ino = i->ino + 1;
+ list = list->next;
+ }
+
+ if (gotachar())
+ return -1;
+ return ino;
+}
+
+
+
+/* TODO: deleteDirectory() a.k.a. rmdir */
+
+static struct jffs2_unknown_node_list *
+appendInode(struct jffs2_unknown_node_list *list,
+ int nodenum,
+ char *path,
+ void *data,
+ int len)
+{
+ struct jffs2_unknown_node_list *n;
+ struct jffs2_raw_inode *iprev, *inew;
+ struct jffs2_raw_dirent *d;
+ struct jffs2_unknown_node *ic;
+
+ /* TODO: break append up into smaller nodes, if there isn't a single
+ region large enough */
+
+ /* TODO: don't deal with large appends yet (nodes are not permitted
+ to exceed 4K in size per jffs2) */
+ if (len >= 4096) {
+ printf("inode extension by >= 4K not supported (yet)\n");
+ return NULL;
+ }
+
+ n = findDirentByPath(list, path);
+ if (n == NULL)
+ goto not_found;
+ d = (struct jffs2_raw_dirent*)n->u;
+
+ n = findInode(list, d->ino, -1);
+ if (n == NULL)
+ goto not_found;
+ iprev = (struct jffs2_raw_inode*)n->u;
+
+ inew = allocInode(iprev->ino, len);
+ if (inew == NULL)
+ return NULL;
+
+ inew->ino = iprev->ino;
+ inew->version = iprev->version + 1;
+ inew->mode = iprev->mode;
+ inew->uid = iprev->uid;
+ inew->gid = iprev->gid;
+ inew->atime = iprev->atime;
+ inew->mtime = iprev->mtime;
+ inew->ctime = iprev->ctime;
+
+ inew->offset = inew->isize;
+ inew->isize += len;
+ inew->compr = JFFS2_COMPR_NONE;
+ inew->usercompr = 0;
+ memcpy((void*)inew->data, data, len);
+
+ inew->hdr_crc = calcHdrCrc((struct jffs2_unknown_node*)inew);
+ inew->node_crc = calcInodeCrc(inew);
+ inew->data_crc = calcDataCrc(inew->data, inew->dsize);
+
+ ic = commitRawNode(list, (struct jffs2_unknown_node*)inew);
+ freeInode(inew);
+
+ if (ic == NULL) /* TODO: error handling? */
+ return NULL;
+
+ if ((n = allocListNode(nodenum++, ic)) != NULL)
+ return insertListNodeAfter(list, n);
+
+ return NULL;
+
+ not_found:
+ printf("%s: no such file or directory\n", path);
+ return NULL;
+}
+
+static struct jffs2_unknown_node_list *
+createInode(struct jffs2_unknown_node_list *list,
+ int nodenum,
+ jint32 mode,
+ char *path)
+{
+ struct jffs2_unknown_node_list *n;
+ struct jffs2_raw_inode *i;
+ struct jffs2_unknown_node *ic;
+ char *ppath = path;
+ jint32 pino = 1;
+ jint32 ino;
+ jint8 type;
+ char name[JFFS2_MAXPATH + 1];
+
+ n = findDirentByPath(list, path);
+ if (n != NULL)
+ goto already_exists;
+
+ while (*ppath && strstr(ppath, JFFS2_PATH_SEPARATOR) != NULL)
+ ppath++;
+
+ if (ppath != path) {
+ struct jffs2_raw_dirent *d;
+ strncpy(name, path, ppath - path - 1);
+ name[ppath - path - 1] = 0;
+
+ n = findDirentByPath(list, name);
+ if (n == NULL)
+ goto not_found;
+ d = (struct jffs2_raw_dirent*)n->u;
+ pino = d->ino;
+ }
+
+ ino = getUnusedIno(list);
+ if (ino == -1)
+ return NULL;
+
+ i = allocInode(ino, 0);
+ if (i == NULL)
+ return NULL;
+
+ i->mode = mode;
+ i->uid = JFFS2_DEFAULT_UID;
+ i->gid = JFFS2_DEFAULT_GID;
+ i->version = 1;
+
+ i->hdr_crc = calcHdrCrc((struct jffs2_unknown_node*)i);
+ i->node_crc = calcInodeCrc(i);
+ i->data_crc = 0;
+
+ ic = commitRawNode(list, (struct jffs2_unknown_node*)i);
+ freeInode(i);
+
+ if (ic == NULL) /* TODO: error handling? */
+ return NULL;
+
+ if ((n = allocListNode(nodenum++, ic)) == NULL
+ || insertListNodeAfter(list, n) == NULL)
+ return NULL;
+
+ if (is_lnk(mode)) type = DT_LNK;
+ else if (is_blk(mode)) type = DT_BLK;
+ else if (is_dir(mode)) type = DT_DIR;
+ else if (is_chr(mode)) type = DT_CHR;
+ else if (is_fifo(mode)) type = DT_FIFO;
+ else type = DT_REG;
+
+ i = (struct jffs2_raw_inode*)ic;
+
+ return commitDirent(list, nodenum, ppath, type,
+ pino, i->ino, nextPinoVersion(list, pino));
+
+ already_exists:
+ printf("%s: file exists\n", path);
+ return NULL;
+
+ not_found:
+ printf("%s: no such file or directory\n", name);
+ return NULL;
+}
+
+struct jffs2_callback_args {
+ void *dest;
+};
+
+static void
+callback_to_memory (void *vargs, int offset,
+ void *src, int size)
+{
+ struct jffs2_callback_args *args = vargs;
+ if (src == NULL)
+ memset(args->dest + offset, 0, size);
+ else
+ memcpy(args->dest + offset, src, size);
+}
+
+static void
+callback_to_console (void *vargs, int offset,
+ void *src, int size)
+{
+ char *cp = src;
+
+ if (src == NULL)
+ return;
+
+ for (cp = src; size > 0; size--)
+ putchar(*cp++);
+}
+
+char *Jffs2Help[] = {
+ "Read and write JFFS2-formatted flash space",
+ "[b:cs:] {operation} [args]...",
+#if INCLUDE_VERBOSEHELP
+ "",
+ "Options:",
+ " -b {addr} base address of JFFS2 space (note 1)",
+ " -c check CRCs of all nodes (note 2)",
+ " -s {size} size of JFFS2 space {note 4}",
+ " -q quiet operation",
+ "",
+ "Operations:",
+ " add {fname} {address} {bytes}",
+ " append {bytes} bytes at {address} to file {fname} (note 3)",
+ " cat {fname} dump contents of ASCII file {fname} to console",
+ " cp {fname} {to_fname}",
+ " copy a file {fname} to {to_fname}",
+ " get {fname} {to_addr}",
+ " dump contents of file {fname} to {to_addr}",
+ " ls [path] list files and/or dirs of the specified [path]",
+ " mkdir {path} create a directory named {path}",
+ " mv {path} {to_path}",
+ " relocate a file/directory from {path} to {to_path}",
+ " rm {fname} delete file named {fname}",
+ " mkfs [{{addr} {size}}]",
+ " build an empty JFFS2 filesystem (notes 1,4)",
+ "",
+ "Additional operations:",
+ " dump display all nodes",
+ " dirent display all dirent nodes",
+ " inode display all inode nodes",
+ " ino [rng] display nodes with specified ino field",
+ " node [rng] display nodes of specified numerical range",
+ " pino [rng] display nodes with specified pino field",
+ " rescan discard current node list, if any, then scan",
+ " scan scan filesystem image only",
+
+#if 0
+ " zinf {src} {dest} {srclen} {destlen}",
+ " inflate using JFFS2's zlib",
+#endif
+ "",
+ "Notes:",
+ " 1. Base address defaults to $JFFS2BASE or zero, if not specified",
+ " 2. Defaults to off",
+ " 3. If {fname} does not exist, it is created",
+ " 4. Size defaults to $JFFS2SIZE or zero, if not specified",
+#endif
+ 0
+};
+
+static void
+progress_callback(int percent)
+{
+ static int prev_percent;
+
+ if (prev_percent == percent)
+ return;
+
+ prev_percent = percent;
+ printf("\r%3d%%\r",
+ percent > 100 ? 100 : percent);
+}
+
+int
+Jffs2Cmd(int argc, char *argv[])
+{
+ ulong jaddr, jsize;
+ struct jffs2_unknown_node *u;
+ int opt;
+ char *env, *cmd, *fname, *range;
+ int bytes, nodes;
+ void (*progress)(int percent) = progress_callback;
+
+ static int nodetot = 0;
+ static struct jffs2_unknown_node_list *nodeList = NULL;
+
+ jint32 jffs2_base = JFFS2_DEFAULT_BASE;
+ jint32 jffs2_size = 0;
+
+ assert(sizeof(jint32) == 4);
+ assert(sizeof(jint16) == 2);
+ assert(sizeof(jint8) == 1);
+
+ jffs2_verify_crc = 0;
+
+ if ((env = getenv("JFFS2BASE")))
+ jffs2_base = (jint32)strtoul(env,0,0);
+
+ if ((env = getenv("JFFS2SIZE")))
+ jffs2_size = (jint32)strtoul(env,0,0);
+
+ while ((opt=getopt(argc,argv,"b:cs:q")) != -1) {
+ switch(opt) {
+ case 'b':
+ jffs2_base = (jint32)strtoul(optarg,0,0);
+ break;
+ case 'c':
+ jffs2_verify_crc = 1;
+ break;
+ case 's':
+ jffs2_size = (jint32)strtoul(optarg,0,0);
+ break;
+ case 'q':
+ progress = NULL;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind + 1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (strcmp(cmd, "mkfs") == 0) {
+ if (argc <= optind + 1)
+ jaddr = jffs2_base;
+ else
+ jaddr = strtoul(argv[optind + 1], 0, 0);
+ if (argc <= optind + 2)
+ jsize = jffs2_size;
+ else
+ jsize = strtoul(argv[optind + 2], 0, 0);
+
+ nodeList = discardNodeList(nodeList);
+
+ /* TODO: progress feedback needs to be optional? */
+ return formatMedium(jaddr, jsize, progress) ?
+ CMD_FAILURE : CMD_SUCCESS;
+ }
+
+ if (strcmp(cmd, "rescan") == 0)
+ nodeList = discardNodeList(nodeList);
+
+ /* commands below this point require a scanMedium() */
+
+ if (nodeList == NULL) {
+ initNodeList(&nodeList);
+ if (nodeList != NULL) {
+ nodetot = scanMedium(jffs2_base, jffs2_size, nodeList, progress);
+ while (nodeList->prev)
+ nodeList = nodeList->prev;
+ }
+ }
+
+ if (strcmp(cmd, "scan") == 0
+ || strcmp(cmd, "rescan") == 0)
+ return CMD_SUCCESS;
+
+ jaddr = jffs2_base;
+ u = (struct jffs2_unknown_node *)jaddr;
+
+ if (strcmp(cmd,"dump") == 0) {
+ printf("JFFS2 base: 0x%lx\n",jffs2_base);
+ printf("JFFS2 size: 0x%lx\n",jffs2_size);
+ nodes = showNodesOfNumRange(nodeList, "all");
+ printf("%d nodes\n", nodes);
+ return CMD_SUCCESS;
+ }
+ else if (strcmp(cmd,"node") == 0) {
+ if (argc == optind + 1)
+ range = "all";
+ else
+ range = argv[optind + 1];
+ nodes = showNodesOfNumRange(nodeList, range);
+ return CMD_SUCCESS;
+ }
+
+ /* if you want a range of dirents or inodes, you need to specify the
+ ino and/or pino; don't use "dirent" or "inode" */
+ else if (strcmp(cmd,"dirent") == 0) {
+ nodes = showNodesOfType(nodeList, JFFS2_NODETYPE_DIRENT);
+ printf("%d nodes\n", nodes);
+ }
+ else if (strcmp(cmd,"inode") == 0) {
+ nodes = showNodesOfType(nodeList, JFFS2_NODETYPE_INODE);
+ printf("%d nodes\n", nodes);
+ }
+
+ /* TODO: this can be reimplemented just like "ino"? */
+ else if (strcmp(cmd,"pino") == 0) {
+ jint32 pino;
+ struct jffs2_unknown_node_list *u = nodeList;
+
+ if (argc != optind+2)
+ return CMD_PARAM_ERROR;
+
+ pino = strtol(argv[optind+1],0,0);
+
+ do {
+ u = findNextMatchingDirent(u, pino, -1, NULL);
+ if (u != NULL && u->u != NULL) {
+ showNode(u->nodenum, u->u);
+ u = u->next;
+ }
+ } while (u != NULL && u->u != NULL);
+ }
+
+ else if (strcmp(cmd,"ino") == 0) {
+
+ if (argc == optind+1)
+ range = "all";
+ else
+ range = argv[optind+1];
+
+ nodes = showNodesOfTypeRange(nodeList,
+ JFFS2_NODETYPE_DIRENT, NULL, range);
+ nodes += showNodesOfTypeRange(nodeList,
+ JFFS2_NODETYPE_INODE, NULL, range);
+ printf("%d nodes\n", nodes);
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd,"cp") == 0) {
+ printf("TODO: jffs2 cp {fname} {to_fname}\n"
+ "(it's harder than it sounds!)\n");
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd,"get") == 0) {
+ struct jffs2_callback_args args;
+
+ if (argc == (optind + 3))
+ args.dest = (void*)strtoul(argv[optind + 2], 0, 0);
+ else
+ return CMD_PARAM_ERROR;
+
+ setenv(JFFS2_FSIZE_STR,0);
+ fname = argv[optind + 1];
+ bytes = readDirent(nodeList, fname, callback_to_memory, &args);
+ if (bytes >= 0)
+ shell_sprintf(JFFS2_FSIZE_STR,"%d",bytes);
+ printf("%d bytes\n", bytes);
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd,"cat") == 0) {
+ if (argc != optind + 2)
+ return CMD_PARAM_ERROR;
+
+ setenv(JFFS2_FSIZE_STR,0);
+ fname = argv[optind + 1];
+ bytes = readDirent(nodeList, fname, callback_to_console, NULL);
+ if (bytes >= 0)
+ shell_sprintf(JFFS2_FSIZE_STR,"%d",bytes);
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd, "mkdir") == 0) {
+ if (argc != optind + 2)
+ return CMD_PARAM_ERROR;
+
+ createInode(nodeList, nodetot++,
+ JFFS2_MODE_DIR
+ | S_IRUGO | S_IXOTH | S_IXGRP | S_IRWXU,
+ argv[optind + 1]);
+
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd, "chmod") == 0) {
+ printf("TODO: implement chmod\n");
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd, "add") == 0) {
+ if (argc != (optind + 4))
+ return CMD_PARAM_ERROR;
+
+ char *path;
+ long addr, len;
+
+ path = argv[optind + 1];
+ addr = strtol(argv[optind + 2], 0, 0);
+ len = strtol(argv[optind + 3], 0, 0);
+
+ if (findDirentByPath(nodeList, path) == NULL)
+ createInode(nodeList, nodetot++,
+ JFFS2_MODE_REG | S_IRUGO | S_IWUSR,
+ path);
+
+ appendInode(nodeList, nodetot++, path, (void*)addr, len);
+ return CMD_SUCCESS;
+ }
+
+ else if (strcmp(cmd, "mv") == 0 && (argc == (optind + 3))) {
+ char *oldname, *newname;
+
+ oldname = argv[optind + 1];
+ newname = argv[optind + 2];
+
+ moveDirent(nodeList, nodetot, oldname, newname);
+ return CMD_SUCCESS;
+ }
+
+ else if(strcmp(cmd, "rm") == 0 && (argc == (optind + 2))) {
+ deleteDirent(nodeList, nodetot, argv[optind + 1]);
+ return CMD_SUCCESS;
+ }
+
+ else if ((strcmp(cmd, "ls") == 0) || (strcmp(cmd, "qry") == 0)) {
+ int ftot;
+ char *path;
+ struct jffs2_umoninfo ju;
+
+ /* If the sub-command is "qry", then we do essentially the same
+ * thing as "ls" except quietly (just populate the shell variables).
+ */
+ if (cmd[0] == 'q')
+ ju.quiet = 1;
+ else
+ ju.quiet = 0;
+
+ ju.direntsize = -1;
+ ju.direntname[0] = 0;
+ setenv(JFFS2_FNAME_STR,0);
+ setenv(JFFS2_FSIZE_STR,0);
+
+ if (argc == optind + 2)
+ path = argv[optind + 1];
+ else
+ path = NULL;
+ ftot = listDirentByPath(nodeList, path, &ju);
+ if ((ftot > 0) && (!ju.quiet))
+ printf(" Total: %d\n",ftot);
+
+ shell_sprintf(JFFS2_FTOT_STR,"%d",ftot);
+
+ if (ju.direntsize > 0) {
+ shell_sprintf(JFFS2_FSIZE_STR,"%d",ju.direntsize);
+ setenv(JFFS2_FNAME_STR,ju.direntname);
+ }
+
+ return CMD_SUCCESS;
+ }
+
+ printf("jffs2 cmd <%s> not found\n",cmd);
+ return CMD_FAILURE;
+}
+
+#endif
diff --git a/main/common/ledit_vi.c b/main/common/ledit_vi.c
new file mode 100644
index 0000000..68f7d01
--- /dev/null
+++ b/main/common/ledit_vi.c
@@ -0,0 +1,737 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * lineedit.c:
+ *
+ * This code supports the monitor's command line editing capability and
+ * command history log. The command line editing is a subset of KSH's
+ * vi-mode editing.
+ *
+ * This code includes a few suggestions/fixed from Martin Carroll.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#if INCLUDE_LINEEDIT
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+
+#define HMAX 16
+#define ESC 0x1B
+#define CTLC 0x03
+#define BACKSPACE 0x08
+#define CMD 100
+#define EDIT 101
+#define EDIT1 102
+#define INSERT 103
+#define NEXT 104
+#define PREV 105
+#define NEITHER 106
+
+#define EDITFILELINE 1
+#define EDITCMDLINE 2
+
+static int stridx; /* store index */
+static int shwidx; /* show index */
+static int srchidx; /* search index */
+static int lastsize; /* size of last command */
+static char curChar; /* latest input character */
+static char *curPos; /* current position on command line */
+static char *startOfLine; /* start of command line */
+static int lineLen; /* length of line */
+static int lMode; /* present mode of entry */
+static char cmdhistory[HMAX+1][CMDLINESIZE];/* array for command history */
+
+static void ledit(), lcmd(), showprev(), ldelete(), linsert(), lerase();
+static void gotobegin(), gotoend(), backup(), shownext(), linsertbs();
+static void delete_to_end(), delete_something();
+static void historysearch(void), ledit1(void);
+static char *lineeditor();
+
+/* line_edit() & file_line_edit():
+ * These two functions are simply front-ends to the lineeditor()
+ * function. The line_edit() function is called by the command line
+ * interface and file_line_edit() is called by the flash file editor
+ * to provide a convenient single line editor when modifying a file.
+ */
+
+char *
+line_edit(char *line_to_edit)
+{
+ return(lineeditor(line_to_edit,EDITCMDLINE));
+}
+
+char *
+file_line_edit(char *line_to_edit)
+{
+ return(lineeditor(line_to_edit,EDITFILELINE));
+}
+
+/* lineeditor():
+ * This function is fed a pointer to a command line.
+ * It sets up a command line editor for that particular line.
+ * The line is modified in place so, if successful, the function
+ * returns the same pointer but with its contents modified based
+ * on the editor commands executed.
+ * If failure, the function returns (char *)0.
+ */
+static char *
+lineeditor(char *line_to_edit,int type)
+{
+ lMode = CMD;
+ startOfLine = line_to_edit;
+ curPos = line_to_edit;
+ while(*curPos != ESC)
+ curPos++;
+ *curPos = 0; /* Remove the escape character from the line */
+ lineLen = (ulong)curPos - (ulong)startOfLine;
+ if (lineLen > 0) {
+ curPos--;
+ putstr(" \b\b");
+ }
+ else
+ putstr(" \b");
+ lastsize = 0;
+ shwidx = stridx;
+ srchidx = stridx;
+ while(1) {
+ curChar = getchar();
+ switch(curChar) {
+ case ESC:
+ if (lMode != CMD) {
+ lMode = CMD;
+ continue;
+ }
+ else {
+ putchar('\n');
+ return((char *)0);
+ }
+ case '\r':
+ case '\n':
+ putchar('\n');
+ if (lineLen == 0)
+ return((char *)0);
+ *(char *)(startOfLine + lineLen) = '\0';
+ return(startOfLine);
+ case CTLC:
+ putchar('\n');
+ *startOfLine = 0;
+ lineLen = 0;
+ return((char *)0);
+ }
+ switch(lMode) {
+ case CMD:
+ lcmd(type);
+ if (lMode == NEITHER)
+ return((char *)0);
+ break;
+ case INSERT:
+ linsert();
+ break;
+ case EDIT1:
+ ledit1();
+ break;
+ case EDIT:
+ ledit();
+ break;
+ }
+ if (lineLen >= (CMDLINESIZE - 2)) {
+ printf("line overflow\n");
+ return((char *)0);
+ }
+ }
+}
+
+static void
+ledit(void)
+{
+ int len;
+
+ if (curChar == '\b')
+ curPos--;
+ else
+ *curPos++ = curChar;
+
+ len = (curPos - startOfLine); /* line may get longer than original */
+ if (len > lineLen)
+ lineLen = len;
+
+ putchar(curChar);
+ switch(lMode) {
+ case EDIT1:
+ lMode = CMD;
+ break;
+ }
+}
+
+static void
+ledit1(void)
+{
+ *curPos = curChar;
+ putchar(curChar);
+ putchar('\b');
+ lMode = CMD;
+}
+
+static void
+lcmd(int type)
+{
+ switch(curChar) {
+ case '0':
+ gotobegin();
+ return;
+ case '$':
+ gotoend();
+ return;
+ case 'A':
+ gotoend();
+ putchar(*curPos++);
+ lMode = INSERT;
+ return;
+ case 'a':
+ if (curPos != startOfLine)
+ putchar(*curPos++);
+ lMode = INSERT;
+ return;
+ case 'i':
+ lMode = INSERT;
+ return;
+ case 'D':
+ delete_to_end();
+ return;
+ case 'd':
+ delete_something();
+ return;
+ case 'c':
+ delete_something();
+ lMode = INSERT;
+ return;
+ case 'x':
+ ldelete();
+ return;
+ case ' ':
+ case 'l':
+ if (curPos < startOfLine+lineLen-1) {
+ putchar(*curPos);
+ curPos++;
+ }
+ return;
+ case '\b':
+ case 'h':
+ if (curPos > startOfLine) {
+ putchar('\b');
+ curPos--;
+ }
+ return;
+ case 'r':
+ lMode = EDIT1;
+ return;
+ case 'R':
+ lMode = EDIT;
+ return;
+ }
+
+ /* The remaining commands should only be processed if we are editing
+ * a command line. For editing a line in a file, the commands that
+ * relate to command line history are not applicable and should be
+ * blocked.
+ */
+ if (type == EDITCMDLINE) {
+ switch(curChar) {
+ case '/':
+ putchar('/');
+ historysearch();
+ return;
+ case '+':
+ case 'j':
+ shownext();
+ return;
+ case '-':
+ case 'k':
+ showprev();
+ return;
+ }
+ }
+
+ /* Beep to indicate an error. */
+ putchar(0x07);
+}
+
+static void
+linsert()
+{
+ char string[CMDLINESIZE];
+
+ if (curChar == BACKSPACE) {
+ linsertbs();
+ return;
+ }
+ if (!isprint(curChar))
+ return;
+ putchar(curChar);
+ putstr(curPos);
+ backup((int)strlen(curPos));
+ strncpy(string,curPos,CMDLINESIZE-1);
+ *curPos++ = curChar;
+ strcpy(curPos,string);
+ lineLen++;
+}
+
+/* linsertbs():
+ * Handle the backspace when in 'INSERT' mode.
+ */
+
+static void
+linsertbs()
+{
+ char *eol, *now;
+ int cnt;
+
+ if (curPos == startOfLine)
+ return;
+ backup(1);
+ curPos--;
+ cnt = 0;
+ eol = startOfLine + lineLen - 1;
+ now = curPos;
+ while(curPos <= eol) {
+ *curPos = *(curPos+1);
+ curPos++;
+ cnt++;
+ }
+ putbytes(now,cnt-1);
+ putchar(' ');
+ backup((int)cnt);
+ curPos = now;
+ lineLen--;
+}
+
+static void
+delete_something()
+{
+ char *eol, *now, C, *new;
+ int cnt;
+
+ C = getchar();
+ if (C == 'w') { /* word */
+ now = curPos;
+ eol = startOfLine + lineLen -1;
+ while (curPos <= eol) {
+ if (*curPos == ' ')
+ break;
+ curPos++;
+ }
+ if (curPos < eol) {
+ new = curPos;
+ strcpy(now,new);
+ cnt = strlen(now);
+ putbytes(now,cnt);
+ curPos = now + cnt;
+ while(curPos <= eol) {
+ putchar(' ');
+ curPos++;
+ cnt++;
+ }
+ backup(cnt);
+ }
+ else {
+ curPos = now;
+ delete_to_end();
+ return;
+ }
+ curPos = now;
+ lineLen = strlen(startOfLine);
+ }
+ else if (C == 'f') { /* find */
+ C = getchar();
+ now = curPos;
+ eol = startOfLine + lineLen -1;
+ while (curPos <= eol) {
+ if (*curPos == C)
+ break;
+ curPos++;
+ }
+ if (curPos < eol) {
+ new = curPos+1;
+ strcpy(now,new);
+ cnt = strlen(now);
+ putbytes(now,cnt);
+ curPos = now + cnt;
+ while(curPos <= eol) {
+ putchar(' ');
+ curPos++;
+ cnt++;
+ }
+ backup(cnt);
+ }
+ else {
+ curPos = now;
+ delete_to_end();
+ return;
+ }
+ curPos = now;
+ lineLen = strlen(startOfLine);
+ }
+}
+
+static void
+delete_to_end()
+{
+ char *eol, *now, *sol;
+
+ eol = startOfLine + lineLen;
+ now = curPos;
+ if (curPos == eol)
+ return;
+ while(curPos < eol) {
+ putchar(' ');
+ curPos++;
+ }
+ if (now == startOfLine)
+ sol = now+1;
+ else
+ sol = now;
+ while(curPos >= sol) {
+ putchar('\b');
+ curPos--;
+ }
+ lineLen = now - startOfLine;
+ if (lineLen == 0) {
+ curPos = startOfLine;
+ *curPos = 0;
+ }
+ else
+ *(curPos+1) = '\0';
+}
+
+static void
+ldelete()
+{
+ char *eol, *now;
+ int cnt;
+
+ if (lineLen == 0)
+ return;
+ cnt = 0;
+ eol = startOfLine + lineLen - 1;
+ now = curPos;
+ if (curPos != eol) {
+ while(curPos <= eol) {
+ *curPos = *(curPos+1);
+ curPos++;
+ cnt++;
+ }
+ putbytes(now,cnt-1);
+ putchar(' ');
+ backup((int)cnt);
+ }
+ else {
+ putstr(" \b\b");
+ *eol = '\0';
+ now--;
+ }
+ curPos = now;
+ lineLen--;
+ if (lineLen == 0)
+ curPos = startOfLine;
+}
+
+/* showdone():
+ * Used as common completion code for the showprev() and
+ * shownext() functions below.
+ */
+static void
+showdone(int idx)
+{
+ if (idx == HMAX) {
+ printf("History buffer empty.\007\n");
+ lMode = NEITHER;
+ return;
+ }
+
+ backup((int)(curPos - startOfLine));
+ lineLen = strlen(cmdhistory[shwidx]);
+ putbytes(cmdhistory[shwidx],lineLen);
+ lerase((int)(lastsize-lineLen));
+ backup((int)(lineLen));
+ strcpy(startOfLine,cmdhistory[shwidx]);
+ curPos = startOfLine;
+ lastsize = lineLen;
+}
+
+/* showprev() & shownext():
+ * Show previous or next command in history list based on
+ * the current position in the list being established by
+ * the shwidx variable.
+ */
+static void
+showprev()
+{
+ int i;
+
+ if (shwidx == 0)
+ shwidx = HMAX-1;
+ else
+ shwidx--;
+
+ for(i=0;i<HMAX;i++) {
+ if (*cmdhistory[shwidx])
+ break;
+ if (shwidx == 0)
+ shwidx = HMAX-1;
+ else
+ shwidx--;
+ }
+ showdone(i);
+}
+
+
+static void
+shownext()
+{
+ int i;
+
+ if (shwidx == HMAX-1)
+ shwidx = 0;
+ else
+ shwidx++;
+
+ for(i=0;i<HMAX;i++) {
+ if (*cmdhistory[shwidx])
+ break;
+ if (shwidx == HMAX)
+ shwidx = 0;
+ else
+ shwidx++;
+ }
+ showdone(i);
+}
+
+static void
+backup(count)
+int count;
+{
+ char string[CMDLINESIZE];
+ int i;
+
+ if (count <= 0)
+ return;
+ *string = '\0';
+ for(i=0;i<count;i++)
+ strcat(string,"\b");
+ putbytes(string,count);
+}
+
+static void
+lerase(int count)
+{
+ char string[CMDLINESIZE];
+ int i;
+
+ if (count <= 0)
+ return;
+ *string = '\0';
+ for(i=0;i<count;i++)
+ strcat(string," ");
+ for(i=0;i<count;i++)
+ strcat(string,"\b");
+ putbytes(string,count*2);
+}
+
+static void
+gotoend()
+{
+ char string[CMDLINESIZE], *eol;
+ int i;
+
+ eol = startOfLine + lineLen -1;
+ for (i=0;i<CMDLINESIZE-1;i++) {
+ if (curPos == eol)
+ break;
+ string[i] = *curPos++;
+ }
+ if (i)
+ putbytes(string,i);
+}
+
+static void
+gotobegin()
+{
+ char string[CMDLINESIZE];
+ int i;
+
+ i = 0;
+ while(curPos != startOfLine) {
+ string[i++] = '\b';
+ curPos--;
+ }
+ putbytes(string,i);
+}
+
+/* History():
+ * Command used at the CLI to allow the user to dump the content
+ * of the history buffer.
+ */
+char * HistoryHelp[] = {
+ "Display command history",
+ "",
+ 0,
+};
+
+int
+History(int argc,char *argv[])
+{
+ int i;
+
+ for(i=stridx;i<HMAX;i++) {
+ if (cmdhistory[i][0])
+ printf("%s\n",cmdhistory[i]);
+ }
+ if (stridx) {
+ for(i=0;i<stridx;i++) {
+ if (cmdhistory[i][0])
+ printf("%s\n",cmdhistory[i]);
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
+/* historyinit():
+ * Initialize the command history...
+ */
+void
+historyinit()
+{
+ int i;
+
+ shwidx = stridx = 0;
+ for (i=0;i<HMAX;i++)
+ cmdhistory[i][0] = 0;
+}
+
+/* historylog():
+ * This function is called by the CLI retrieval code to store away
+ * the command in the CLI history list, a circular queue
+ * (size HMAX) of most recent commands.
+ */
+void
+historylog(char *cmdline)
+{
+ int idx;
+
+ if (strlen(cmdline) >= CMDLINESIZE)
+ return;
+
+ if (stridx == 0)
+ idx = HMAX-1;
+ else
+ idx = stridx -1;
+
+ /* don't store if this command is same as last command */
+ if (strcmp(cmdhistory[idx],cmdline) == 0)
+ return;
+
+ if (stridx == HMAX)
+ stridx = 0;
+
+ strcpy(cmdhistory[stridx++],cmdline);
+}
+
+
+static void
+historysearch(void)
+{
+ static char string[100];
+ char *s, *ptr, *last, C;
+ int size, len, count;
+
+ lerase((int)lastsize);
+ s = string;
+ size = 0;
+ while(1) {
+ C = getchar();
+ if (C == '\b') {
+ if (size == 0)
+ continue;
+ putstr("\b \b");
+ s--;
+ size--;
+ continue;
+ }
+ if ((C == '\r') || (C == '\n'))
+ break;
+ putchar(C);
+ size++;
+ *s++ = C;
+ }
+ backup((int)(size+1));
+ if (size != 0)
+ *s = '\0';
+ else
+ size = strlen(string);
+
+ count = 0;
+
+ while(1) {
+ ptr = cmdhistory[srchidx];
+ len = strlen(ptr);
+ last = ptr + len - size + 1;
+ while(ptr < last) {
+ if (strncmp(ptr,string,size) == 0)
+ goto gotmatch;
+ ptr++;
+ }
+ if (srchidx == 0)
+ srchidx = HMAX-1;
+ else
+ srchidx--;
+ if (++count == HMAX) {
+ backup((int)(curPos - startOfLine));
+ lineLen = 0;
+ lerase((int)(size+1));
+ backup((int)(lineLen));
+ *startOfLine = '\0';
+ curPos = startOfLine;
+ lastsize = lineLen;
+ return;
+ }
+ }
+gotmatch:
+ backup((int)(curPos - startOfLine));
+ lineLen = strlen(cmdhistory[srchidx]);
+ putbytes(cmdhistory[srchidx],lineLen);
+ lerase((int)(lastsize-lineLen));
+ backup((int)(lineLen));
+ strcpy(startOfLine,cmdhistory[srchidx]);
+ curPos = startOfLine;
+ lastsize = lineLen;
+ if (srchidx == 0)
+ srchidx = HMAX-1;
+ else
+ srchidx--;
+ return;
+}
+
+#endif
+
diff --git a/main/common/ledit_vt100.c b/main/common/ledit_vt100.c
new file mode 100644
index 0000000..0f5c50e
--- /dev/null
+++ b/main/common/ledit_vt100.c
@@ -0,0 +1,462 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * ledit_vt.c:
+ *
+ * This is an alternative to lineedit.c. For those unfamiliar with the
+ * KSH VI-like editing, this is certainly a more intuitive mechanism
+ * for CLI edit. It uses the VT100 terminal arrow keys for basic
+ * line and history traversal...
+ *
+ * - UP/DOWN move through the CLI history.
+ * - RIGHT/LEFT move through the current line.
+ * - DEL deletes character that cursor is on top of.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#if INCLUDE_LINEEDIT
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+
+#define GOT_NUTTIN 0
+#define GOT_ESCAPE 1
+#define GOT_BRACKET 2
+
+#define HMAX 16
+#define ESC 0x1B
+#define CTLC 0x03
+#define BACKSPACE 0x08
+
+#define OPEN_BRACKET '['
+#define VT100_DEL 0x7f
+#define VT100_UP 'A'
+#define VT100_DOWN 'B'
+#define VT100_RIGHT 'C'
+#define VT100_LEFT 'D'
+
+#define EDITFILELINE 1
+#define EDITCMDLINE 2
+
+static int stridx; /* store index */
+static int shwidx; /* show index */
+static int srchidx; /* search index */
+static int lastsize; /* size of last command */
+static char curChar; /* latest input character */
+static char *curPos; /* current position on command line */
+static char *startOfLine; /* start of command line */
+static int lineLen; /* length of line */
+static char cmdhistory[HMAX+1][CMDLINESIZE];/* array for command history */
+
+static void shownext(void), showprev(void), ldelete(void), backspace(void);
+static void newchar(char c);
+static void backup(int count);
+
+/* lineeditor():
+ * This is a simpler version of lineeditor() (as found in lineedit.c).
+ * It does not have the capability of the vi-like version; however, for
+ * those not familiar with ksh, this one is probably a lot more intuitive.
+ *
+ * The line is modified in place so, if successful, the function
+ * returns the same pointer but with its contents modified based
+ * on the editor commands executed.
+ * If failure, the function returns (char *)0.
+ */
+static char *
+lineeditor(char *line_to_edit,int type)
+{
+ int state;
+
+ if (type == EDITCMDLINE) {
+ if (getchar() != OPEN_BRACKET) {
+ putchar('\n');
+ *line_to_edit = 0;
+ return((char *)0);
+ }
+ }
+
+ startOfLine = line_to_edit;
+ curPos = line_to_edit;
+ while(*curPos != ESC)
+ curPos++;
+
+ *curPos = 0; /* Remove the escape character from the line */
+ lineLen = (ulong)curPos - (ulong)startOfLine;
+ if (lineLen > 0) {
+ curPos--;
+ putstr(" \b\b");
+ }
+ else
+ putstr(" \b");
+
+ state = GOT_BRACKET;
+ lastsize = 0;
+ shwidx = stridx;
+ srchidx = stridx;
+ while(1) {
+ curChar = getchar();
+ switch(curChar) {
+ case CTLC:
+ putchar('\n');
+ *line_to_edit = 0;
+ return((char *)0);
+ case VT100_UP:
+ if (state == GOT_BRACKET) {
+ if (type == EDITCMDLINE)
+ showprev();
+ state = GOT_NUTTIN;
+ }
+ else {
+ newchar(curChar);
+ }
+ break;
+ case VT100_DOWN:
+ if (state == GOT_BRACKET) {
+ if (type == EDITCMDLINE)
+ shownext();
+ state = GOT_NUTTIN;
+ }
+ else {
+ newchar(curChar);
+ }
+ break;
+ case VT100_RIGHT:
+ if (state == GOT_BRACKET) {
+ if (curPos < startOfLine+lineLen) {
+ putchar(*curPos);
+ curPos++;
+ }
+ state = GOT_NUTTIN;
+ }
+ else {
+ newchar(curChar);
+ }
+ break;
+ case VT100_LEFT:
+ if (state == GOT_BRACKET) {
+ if (curPos > startOfLine) {
+ putchar('\b');
+ curPos--;
+ }
+ state = GOT_NUTTIN;
+ }
+ else {
+ newchar(curChar);
+ }
+ break;
+ case OPEN_BRACKET:
+ if (state == GOT_ESCAPE) {
+ state = GOT_BRACKET;
+ }
+ else {
+ newchar(curChar);
+ }
+ break;
+ case ESC:
+ state = GOT_ESCAPE;
+ break;
+ case VT100_DEL:
+ if (curPos != (startOfLine + lineLen))
+ ldelete();
+ break;
+ case '\b':
+ if (curPos > startOfLine)
+ backspace();
+ break;
+ case '\n':
+ case '\r':
+ putchar('\n');
+ if (lineLen == 0)
+ return((char *)0);
+ *(char *)(startOfLine + lineLen) = '\0';
+ return(startOfLine);
+ default:
+ newchar(curChar);
+ break;
+ }
+ }
+ return((char *)0);
+}
+
+/* line_edit() & file_line_edit():
+ * These two functions are simply front-ends to the lineeditor()
+ * function. The line_edit() function is called by the command line
+ * interface and file_line_edit() is called by the flash file editor
+ * to provide a convenient single line editor when modifying a file.
+ */
+
+char *
+line_edit(char *line_to_edit)
+{
+ return(lineeditor(line_to_edit,EDITCMDLINE));
+}
+
+char *
+file_line_edit(char *line_to_edit)
+{
+ return(lineeditor(line_to_edit,EDITFILELINE));
+}
+
+static void
+ldelete(void)
+{
+ char *eol, *now;
+ int cnt;
+
+ if (lineLen == 0)
+ return;
+ cnt = 0;
+ eol = startOfLine + lineLen - 1;
+ now = curPos;
+#if 0
+ if (curPos != eol) {
+ while(curPos <= eol) {
+ *curPos = *(curPos+1);
+ curPos++;
+ cnt++;
+ }
+ putbytes(now,cnt-1);
+ putchar(' ');
+ backup((int)cnt);
+ }
+ else {
+ putstr(" \b\b");
+ *eol = '\0';
+ now--;
+ }
+#else
+ while(curPos <= eol) {
+ *curPos = *(curPos+1);
+ curPos++;
+ cnt++;
+ }
+ putbytes(now,cnt-1);
+ putchar(' ');
+ backup((int)cnt);
+#endif
+ curPos = now;
+ lineLen--;
+ if (lineLen == 0)
+ curPos = startOfLine;
+}
+
+static void
+backup(int count)
+{
+ char string[CMDLINESIZE];
+ int i;
+
+ if (count <= 0)
+ return;
+ *string = '\0';
+ for(i=0;i<count;i++)
+ strcat(string,"\b");
+ putbytes(string,count);
+}
+
+static void
+backspace(void)
+{
+ curPos--;
+ putchar('\b');
+ ldelete();
+}
+
+static void
+newchar(char c)
+{
+ char string[CMDLINESIZE];
+
+ if (curPos == startOfLine + lineLen) {
+ putchar(c);
+ *curPos++ = c;
+ lineLen++;
+ }
+ else {
+ if (!isprint(c))
+ return;
+ putchar(c);
+ putstr(curPos);
+ backup((int)strlen(curPos));
+ strncpy(string,curPos,CMDLINESIZE-1);
+ *curPos++ = c;
+ strcpy(curPos,string);
+ lineLen++;
+ }
+}
+
+static void
+lerase(int count)
+{
+ char string[CMDLINESIZE];
+ int i;
+
+ if (count <= 0)
+ return;
+ *string = '\0';
+ for(i=0;i<count;i++)
+ strcat(string," ");
+ for(i=0;i<count;i++)
+ strcat(string,"\b");
+ putbytes(string,count*2);
+}
+
+/* showdone():
+ * Used as common completion code for the showprev() and
+ * shownext() functions below.
+ */
+static void
+showdone(int idx)
+{
+ if (idx == HMAX) {
+ printf("History buffer empty.\007\n");
+ return;
+ }
+
+ backup((int)(curPos - startOfLine));
+ lineLen = strlen(cmdhistory[shwidx]);
+ putbytes(cmdhistory[shwidx],lineLen);
+ lerase((int)(lastsize-lineLen));
+ strcpy(startOfLine,cmdhistory[shwidx]);
+ curPos = startOfLine + lineLen;
+ lastsize = lineLen;
+}
+
+/* showprev() & shownext():
+ * Show previous or next command in history list based on
+ * the current position in the list being established by
+ * the shwidx variable.
+ */
+static void
+showprev(void)
+{
+ int i;
+
+ if (shwidx == 0)
+ shwidx = HMAX-1;
+ else
+ shwidx--;
+
+ for(i=0;i<HMAX;i++) {
+ if (*cmdhistory[shwidx])
+ break;
+ if (shwidx == 0)
+ shwidx = HMAX-1;
+ else
+ shwidx--;
+ }
+ showdone(i);
+}
+
+static void
+shownext(void)
+{
+ int i;
+
+ if (shwidx == HMAX-1)
+ shwidx = 0;
+ else
+ shwidx++;
+
+ for(i=0;i<HMAX;i++) {
+ if (*cmdhistory[shwidx])
+ break;
+ if (shwidx == HMAX)
+ shwidx = 0;
+ else
+ shwidx++;
+ }
+ showdone(i);
+}
+
+/* History():
+ * Command used at the CLI to allow the user to dump the content
+ * of the history buffer.
+ */
+char * HistoryHelp[] = {
+ "Display command history",
+ "",
+ 0,
+};
+
+int
+History(int argc,char *argv[])
+{
+ int i;
+
+ for(i=stridx;i<HMAX;i++) {
+ if (cmdhistory[i][0])
+ printf("%s\n",cmdhistory[i]);
+ }
+ if (stridx) {
+ for(i=0;i<stridx;i++) {
+ if (cmdhistory[i][0])
+ printf("%s\n",cmdhistory[i]);
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
+/* historyinit():
+ * Initialize the command history...
+ */
+void
+historyinit()
+{
+ int i;
+
+ shwidx = stridx = 0;
+ for (i=0;i<HMAX;i++)
+ cmdhistory[i][0] = 0;
+}
+
+/* historylog():
+ * This function is called by the CLI retrieval code to store away
+ * the command in the CLI history list, a circular queue
+ * (size HMAX) of most recent commands.
+ */
+void
+historylog(char *cmdline)
+{
+ int idx;
+
+ if (strlen(cmdline) >= CMDLINESIZE)
+ return;
+
+ if (stridx == 0)
+ idx = HMAX-1;
+ else
+ idx = stridx -1;
+
+ /* don't store if this command is same as last command */
+ if (strcmp(cmdhistory[idx],cmdline) == 0)
+ return;
+
+ if (stridx == HMAX)
+ stridx = 0;
+
+ strcpy(cmdhistory[stridx++],cmdline);
+}
+
+#endif
diff --git a/main/common/malloc.c b/main/common/malloc.c
new file mode 100644
index 0000000..8050e05
--- /dev/null
+++ b/main/common/malloc.c
@@ -0,0 +1,763 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * malloc():
+ *
+ * A simple memory allocator useful for embedded systems to provide
+ * some level of debug, plus the ability to increase heap space into
+ * additional memory that is not contiguous with the intial statically
+ * allocated array of memory. The reason for supporting the ability to
+ * allocate from 2 distinct blocks of memory is so that the monitor can
+ * be built with some reasonable amount of heap space allocated to it; then
+ * if the application is going to also use this malloc, it can do so
+ * by simply extending the heap. The monitor would not have to be
+ * specifically built to support the large heap allocation.
+ *
+ * The allocator data structures are part of the memory space used for
+ * the allocation. To test for memory overruns (using memory after the
+ * end of the allocated space) or underruns (using memory prior to the
+ * beginning of the allocated space), the data structure starts and ends
+ * with a fixed tag that is always checked upon entry into malloc()
+ * or free().
+ * When the memory is freed, the next and previous block is checked to
+ * determine if this newly freed block can be combined with a neighboring
+ * block. This provides some level of defragmentation. Note, at
+ * this point, that the blocks are only combined if they are found to be
+ * contiguous. This correctly implies that neighboring free blocks need
+ * not be within contiguous memory space.
+ * A function called GetMemory() must be provided as the underlying resource
+ * of the memory used by the allocator.
+ *
+ * NOTE THAT THERE IS ABSOLUTELY NO CONCERN FOR SPEED IN THIS MEMORY
+ * ALLOCATOR, IT IS SLOW! Every call to malloc/free does a sanity check
+ * on all allocation structures, so it is fairly good at detecting illegal
+ * use of the allocated memory.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_MALLOC
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+
+#define FNAMESIZE 32
+
+#define PRETAG 0xDEAD
+#define POSTTAG 0xBEEF
+#define MHDRSIZE sizeof(struct mhdr)
+
+extern char *GetMemory(int);
+extern int GetMemoryLeft(void);
+extern int extendHeap(char *,int);
+extern void unExtendHeap(void);
+extern char *getExtHeapBase(void);
+
+
+/* mhdr:
+ The control structure used by the memory allocator.
+*/
+struct mhdr {
+ ushort pretag; /* Fixed value used as an overrun sanity
+ * check for the previous memory block.
+ */
+ int size; /* Size of useable memory block. Size is
+ * positive if block is free and negative if
+ * block is not free.
+ */
+ struct mhdr *next; /* Points to next mhdr structure (not
+ * necessarily in contiguous memory space).
+ */
+ struct mhdr *prev; /* Points to previous mhdr structure (not
+ * necessarily in contiguous memory space).
+ */
+ ushort posttag; /* Fixed value used as an underrun sanity
+ * check for this memory block.
+ */
+#ifdef MALLOC_DEBUG
+ char fname[FNAMESIZE];
+ int fline;
+#endif
+};
+
+/* mcalls, fcalls & mfails:
+ * Used to keep track of malloc and free calls. Plus keep track
+ * of the number of times malloc is called, but it returns 0.
+ */
+static int mcalls, rcalls, fcalls, mfails;
+
+/* mtot, ftot & highwater:
+ * Keep track of total amount of memory allocated.
+ */
+static int mtot, ftot, highwater;
+
+/* mquiet:
+ * If set (by heap -q), then the MALLOC ERROR messages are not
+ * printed at runtime when an error is detected.
+ */
+static char mquiet;
+
+/* mtrace:
+ * If set (by heap -V), then each call to malloc or free will include
+ * a printed message.
+ */
+static char mtrace;
+
+/* heapbase:
+ * Initially zero, this pointer is set to the base of the heap on
+ * the first call to malloc().
+ */
+static struct mhdr *heapbase;
+
+static void
+heapinit(void)
+{
+ mcalls = rcalls = fcalls = mfails = 0;
+ mtot = ftot = highwater = 0;
+ heapbase = (struct mhdr *)GetMemory(ALLOCSIZE);
+ heapbase->pretag = PRETAG;
+ heapbase->posttag = POSTTAG;
+ heapbase->size = ALLOCSIZE - MHDRSIZE;
+ if (heapbase->size < 0)
+ printf("heapinit(): ALLOCSIZE too small!\n");
+ heapbase->next = (struct mhdr *)0;
+ heapbase->prev = (struct mhdr *)0;
+}
+
+/* heapcheck():
+ * Called with an mhdr pointer (or NULL). This function just steps through
+ * the heap control structures to make sure there is some level of sanity.
+ * If the incoming mhdr pointer is non-zero, then it will also verify that
+ * the pointer is a valid control pointer in the heap.
+ */
+int
+heapcheck(struct mhdr *mp,char *msg)
+{
+ int i, mpok;
+ register struct mhdr *mptr;
+
+ mpok = 0;
+ if (!heapbase)
+ heapinit();
+
+ mptr = heapbase;
+ for(i=0;mptr;i++,mptr=mptr->next) {
+ if (mp == mptr)
+ mpok = 1;
+ if ((mptr->pretag != PRETAG) || (mptr->posttag != POSTTAG)) {
+ if (!mquiet) {
+ printf("\007MALLOC ERROR: heap corrupted at entry %d",i);
+ if (msg)
+ printf(" (%s)",msg);
+ printf("\n");
+ }
+ return(-1);
+ }
+ }
+ if ((mp) && (!mpok)) {
+ if (!mquiet) {
+ printf("\007MALLOC ERROR: 0x%lx (mem @ 0x%lx) invalid heap pointer",
+ (ulong)mp,(ulong)(mp+1));
+ if (msg)
+ printf(" (%s)",msg);
+ printf("\n");
+ }
+ return(-1);
+ }
+ return(0);
+}
+
+static char *
+_malloc(int size)
+{
+ register struct mhdr *mptr, *mptr1;
+
+ if (mtrace)
+ printf("malloc(%d) = ",size);
+
+ if (size <= 0) {
+ if (mtrace)
+ printf("0\n");
+ return(0);
+ }
+
+ /* Start by checking sanity of heap. */
+ if (heapcheck(0,0) < 0) {
+ if (mtrace)
+ printf("00\n");
+ return((char *)0);
+ }
+
+ /* Keep track of number of calls to malloc for debug. */
+ mcalls++;
+
+ /* Make size divisible by 4: */
+ if (size & 3) {
+ size += 4;
+ size &= 0xfffffffc;
+ }
+
+ mptr = (struct mhdr *)heapbase;
+ while(1) {
+ /* If request size is equal to the free block size or
+ * if the free block size is only slightly larger than the
+ * request size, then just use that free block as is.
+ * If the request size is at least "MHDRSIZE * 2"
+ * bytes smaller than free block size, then break
+ * that block up into 2 smaller chunks with one of the chunks
+ * being the size of the request and the size of the other chunk
+ * being whatever is left over.
+ */
+ if (mptr->size >= size) {
+ if (mptr->size <= (int)(size + (MHDRSIZE * 2))) {
+ mtot += mptr->size;
+ if ((mtot - ftot) > highwater)
+ highwater = (mtot - ftot);
+ mptr->size = -mptr->size;
+ }
+ else {
+ mptr1 = (struct mhdr *)((char *)(mptr+1) + size);
+ mptr1->pretag = PRETAG;
+ mptr1->posttag = POSTTAG;
+ mptr1->next = mptr->next;
+ mptr->next = mptr1;
+ if (mptr1->next)
+ mptr1->next->prev = mptr1;
+ mptr1->prev = mptr;
+ mptr1->size = (mptr->size - size) - MHDRSIZE;
+ mptr->size = -size;
+ mtot += size;
+ if ((mtot - ftot) > highwater)
+ highwater = (mtot - ftot);
+ }
+ if (mtrace)
+ printf("0x%lx\n",(long)(mptr+1));
+ return((char *)(mptr+1));
+ }
+ if (mptr->next == (struct mhdr *)0) {
+ struct mhdr *moremem;
+ int getsize;
+
+ getsize = size + MHDRSIZE;
+ moremem = (struct mhdr *)GetMemory(getsize);
+ if (!moremem) {
+ mfails++;
+ if (!mquiet)
+ printf("\007MALLOC ERROR: no more memory\n");
+ if (mtrace)
+ printf("000\n");
+ return((char *)0);
+ }
+ mptr->next = moremem;
+ mptr->next->prev = mptr;
+ mptr = mptr->next;
+ mptr->next = (struct mhdr *)0;
+ mptr->pretag = PRETAG;
+ mptr->posttag = POSTTAG;
+ mptr->size = getsize - MHDRSIZE;
+ }
+ else
+ mptr = mptr->next;
+ }
+}
+
+#ifdef MALLOC_DEBUG
+#undef malloc
+
+char *
+malloc(int size, char *fname, int fline)
+{
+ char *cp;
+ struct mhdr *mptr;
+
+ cp = _malloc(size);
+ if (cp) {
+ mptr = (struct mhdr *)cp;
+ mptr--;
+ strncpy(mptr->fname,fname,FNAMESIZE-1);
+ mptr->fline = fline;
+ mptr->fname[FNAMESIZE-1] = 0;
+ mptr->fline = fline;
+ }
+ return(cp);
+}
+
+#else
+char *
+malloc(int size)
+{
+ return(_malloc(size));
+}
+#endif
+
+void
+free(void *vp)
+{
+ char *cp = vp;
+ struct mhdr *mptr;
+
+ if (mtrace)
+ printf("free(0x%lx)\n",(long)cp);
+
+ /* Keep track of number of calls to free for debug. */
+ fcalls++;
+
+ mptr = (struct mhdr *)cp - 1;
+
+ /* Start by checking sanity of heap and make sure that the incoming
+ * pointer corresponds to a valid entry in the heap.
+ */
+ if (heapcheck(mptr,0) < 0)
+ return;
+
+ /* The first thing to do to free the block is to make the size
+ * positive.
+ */
+ mptr->size = abs(mptr->size);
+
+ /* Keep track of how much memory is freed for debug. */
+ ftot += mptr->size;
+
+ /* To defragment the memory, see if previous and/or
+ * next block is free; if yes, then join them into one larger
+ * block. Note that the blocks will only be joined if they are in
+ * contiguous memory space.
+ */
+ if (mptr->next) {
+ if ((mptr->next->size > 0) &&
+ (mptr->next == (struct mhdr *)
+ ((char *)mptr + mptr->size + MHDRSIZE))) {
+ mptr->size += mptr->next->size + MHDRSIZE;
+ mptr->next = mptr->next->next;
+ if (mptr->next)
+ mptr->next->prev = mptr;
+ }
+ }
+ if (mptr->prev) {
+ if ((mptr->prev->size > 0) &&
+ (mptr->prev == (struct mhdr *)
+ ((char *)mptr-mptr->prev->size - MHDRSIZE))) {
+ if (mptr->next)
+ mptr->next->prev = mptr->prev;
+ mptr->prev->next = mptr->next;
+ mptr->prev->size += mptr->size + MHDRSIZE;
+ }
+ }
+}
+
+/* calloc():
+ * Allocate space for an array of nelem elements of size elsize.
+ * Initialize the space to zero.
+ */
+static char *
+_calloc(int nelem, int elsize)
+{
+ register char *cp, *end;
+ char *base;
+ int size;
+
+ size = nelem * elsize;
+ base = _malloc(size);
+ if (base) {
+ cp = base;
+ end = base+size;
+ while(cp<end)
+ *cp++ = 0;
+ }
+ return(base);
+}
+
+#ifdef MALLOC_DEBUG
+char *
+calloc(int nelem, int elsize, char *fname, int fline)
+{
+ char *cp;
+ struct mhdr *mptr;
+
+ cp = _calloc(nelem, elsize);
+ if (cp) {
+ mptr = (struct mhdr *)cp;
+ mptr--;
+ strncpy(mptr->fname,fname,FNAMESIZE-1);
+ mptr->fline = fline;
+ mptr->fname[FNAMESIZE-1] = 0;
+ mptr->fline = fline;
+ }
+ return(cp);
+}
+
+#else
+
+char *
+calloc(int nelem, int elsize)
+{
+ return(_calloc(nelem,elsize));
+}
+#endif
+
+
+static char *
+_realloc(char *cp,int newsize)
+{
+ char *new;
+ int asize, delta;
+ struct mhdr *mptr, tmphdr;
+
+ rcalls++;
+
+ /* If incoming pointer is NULL, then do a regular malloc. */
+ if (!cp)
+ return(_malloc(newsize));
+
+ /* If newsize is zero and pointer is not null, then do a free. */
+ if (!newsize) {
+ free(cp);
+ return((char *)0);
+ }
+
+ /* Set the mhdr pointer to the header attached to the incoming
+ * char pointer. We assume here that the incoming pointer is the
+ * base address of the block of memory that is being reallocated.
+ */
+ mptr = (struct mhdr *)cp - 1;
+
+ /* Start by checking sanity of heap and make sure that the incoming
+ * pointer corresponds to a valid entry in the heap.
+ */
+ if (heapcheck(mptr,0) < 0)
+ return((char *)0);
+
+ /* Recall that mptr->size is negative since the block is not free, so
+ * use the absolute value of mptr->size...
+ */
+ asize = abs(mptr->size);
+
+ /* Make requested size divisible by 4:
+ */
+ if (newsize & 3) {
+ newsize += 4;
+ newsize &= 0xfffffffc;
+ }
+
+ /* If newsize is less than or equal to current size, just return with
+ * the same pointer. At some point, this should be improved so that
+ * the memory made made available by this reallocation is put back in
+ * the pool.
+ */
+ if (newsize <= asize)
+ return(cp);
+
+ /* Now we do the actual reallocation...
+ * If there is a fragment after this one (next != NULL) AND it is
+ * available (size > 0) AND the combined size of the next fragment
+ * along with the current fragment exceeds the request, then we can
+ * reallocate quickly.
+ * Otherwise, we have to just malloc a whole new block and copy the
+ * old buffer to the new larger space.
+ */
+ if ((mptr->next) && (mptr->next->size > 0) &&
+ ((asize + mptr->next->size + MHDRSIZE) > newsize)) {
+
+ /* At this point we know we have the space to reallocate without
+ * the malloc/free step. Now we need to add the necessary space
+ * to the current fragment, and take that much away from the next
+ * fragment...
+ */
+ delta = newsize - asize;
+ /* next line used to be: tmphdr = *mptr->next... */
+ memcpy((char *)&tmphdr,(char *)mptr->next, sizeof(struct mhdr));
+ mptr->size = -newsize;
+ mptr->next = (struct mhdr *)(delta + (int)(mptr->next));
+ mptr->next->size = (abs(tmphdr.size) - delta);
+ mptr->next->pretag = PRETAG;
+ mptr->next->posttag = POSTTAG;
+ mptr->next->next = tmphdr.next;
+ mptr->next->prev = tmphdr.prev;
+
+ /* Keep track of totals and highwater:
+ */
+ mtot += (newsize - asize);
+ if ((mtot - ftot) > highwater)
+ highwater = (mtot - ftot);
+ return(cp);
+ }
+
+ /* If the next fragment is not large enough, then malloc new space,
+ * copy the existing data to that block, free the old space and return
+ * a pointer to the new block.
+ */
+ new = _malloc(newsize);
+ if (!new)
+ return((char *)0);
+
+ memcpy(new,cp,asize);
+ free(cp);
+ return(new);
+}
+
+#ifdef MALLOC_DEBUG
+#undef realloc
+char *
+realloc(char *buf, int newsize, char *fname, int fline)
+{
+ char *cp;
+ struct mhdr *mptr;
+
+ cp = _realloc(buf, newsize);
+ if (cp) {
+ mptr = (struct mhdr *)cp;
+ mptr--;
+ strncpy(mptr->fname,fname,FNAMESIZE-1);
+ mptr->fline = fline;
+ mptr->fname[FNAMESIZE-1] = 0;
+ mptr->fline = fline;
+ }
+ return(cp);
+}
+
+#else
+
+char *
+realloc(char *buf, int newsize)
+{
+ return(_realloc(buf,newsize));
+}
+#endif
+
+
+void
+heapdump(int verbose)
+{
+ register struct mhdr *mptr;
+ char freenow;
+ int i, alloctot, freetot, size;
+
+ heapcheck(0,0);
+
+ mptr = heapbase;
+ i=0;
+ freetot = 0;
+ alloctot = 0;
+ if (verbose)
+ printf(" addr size free? mptr nxt prv ascii@addr\n");
+ else
+ printf("Heap summary:\n");
+ for(i=0;mptr;i++) {
+ if (mptr->size < 0) {
+ freenow = 'n';
+ size = -mptr->size;
+ alloctot += size;
+ }
+ else {
+ freenow = 'y';
+ size = mptr->size;
+ freetot += size;
+ }
+ if (verbose) {
+ printf("%3d: 0x%08lx %5d %c 0x%08lx 0x%08lx 0x%08lx ",
+ i,(ulong)(mptr+1),size,freenow,(ulong)mptr,
+ (ulong)(mptr->next),(ulong)(mptr->prev));
+ prascii((unsigned char *)(mptr+1),size > 16 ? 16 : size);
+ putchar('\n');
+#ifdef MALLOC_DEBUG
+ if (freenow == 'n')
+ printf(" %s %d\n",mptr->fname,mptr->fline);
+#endif
+ }
+ mptr = mptr->next;
+ }
+ if (verbose)
+ putchar('\n');
+ printf(" Malloc/realloc/free calls: %d/%d/%d\n",mcalls,rcalls,fcalls);
+ printf(" Malloc/free totals: %d/%d\n",mtot,ftot);
+ printf(" High-water level: %d\n",highwater);
+ printf(" Malloc failures: %d\n",mfails);
+ printf(" Bytes overhead: %d\n",i * MHDRSIZE);
+ printf(" Bytes currently allocated: %d\n",alloctot);
+ printf(" Bytes free on current heap: %d\n",freetot);
+ printf(" Bytes left in allocation pool: %d\n",GetMemoryLeft());
+}
+
+/* releaseExtendedHeap():
+ * If memory has been allocated through the extended heap established
+ * by the heap -x{start,size} command, this function will attempt
+ * to "undo" that. It can only be un-done if there is no currently active
+ * allocations in that range.
+ *
+ * This function is accessible by the application through monlib.
+ */
+int
+releaseExtendedHeap(int verbose)
+{
+ int i;
+ struct mhdr *mptr, *extbase;
+
+ extbase = (struct mhdr *)getExtHeapBase();
+ if (!extbase) {
+ if (verbose)
+ printf("Heap extension not set\n");
+ return(-1);
+ }
+
+ heapcheck(0,0);
+ mptr = heapbase;
+ for(i=0;mptr;i++) {
+ if (mptr->next == extbase) {
+ if (mptr->next->next == (struct mhdr *)0) {
+ mptr->next = (struct mhdr *)0;
+ unExtendHeap();
+ if (verbose)
+ printf("Heap extension cleared\n");
+ return(0);
+ }
+ else if (verbose)
+ printf("Extended heap space is in use.\n");
+ break;
+ }
+ mptr = mptr->next;
+ }
+ if (!mptr) { /* Heap was extended, but not used. */
+ unExtendHeap(); /* Remove the extension. */
+ if (verbose)
+ printf("Heap extension cleared.\n");
+ }
+ return(0);
+}
+
+
+char *HeapHelp[] = {
+ "Display heap statistics.",
+ "-[cf:m:qtvX:x]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -c clear high-water level and malloc/free totals",
+ " -f{ptr} free block @ 'ptr'",
+ " -m{size} malloc 'size' bytes",
+ " -q quiet runtime (don't print MALLOC ERROR msgs)",
+ " -v verbose (more detail)",
+ " -t toggle runtime malloc/free trace",
+ " -X{base,size}",
+ " extend heap by 'size' bytes starting at 'base'",
+ " -x clear heap extension",
+#endif
+ 0
+};
+
+int
+Heap(int argc,char *argv[])
+{
+ char *establish_extended_heap, buf[32];
+ int verbose, release_extended_heap, showheap, opt;
+
+ showheap = 1;
+ establish_extended_heap = (char *)0;
+ release_extended_heap = verbose = 0;
+ while((opt=getopt(argc,argv,"cf:m:qtvX:x")) != -1) {
+ switch(opt) {
+ case 'c':
+ mcalls = fcalls = 0;
+ mtot = ftot = highwater = 0;
+ showheap = 0;
+ break;
+ case 'f':
+ free((char *)strtoul(optarg,0,0));
+ showheap = 0;
+ break;
+ case 'm':
+ shell_sprintf("MALLOC","0x%lx",
+ (ulong)_malloc(strtoul(optarg,0,0)));
+ if (verbose)
+ printf("%s\n",buf);
+ showheap = 0;
+ break;
+ case 'q':
+ showheap = 0;
+ mquiet = 1;
+ break;
+ case 't':
+ mtrace = ~mtrace;
+ printf("Runtime trace: %sabled\n",
+ mtrace ? "en" : "dis");
+ return(CMD_SUCCESS);
+ case 'v':
+ verbose = 1;
+ break;
+ case 'X':
+ establish_extended_heap = optarg;
+ showheap = 0;
+ break;
+ case 'x':
+ release_extended_heap = 1;
+ showheap = 0;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ if (release_extended_heap)
+ releaseExtendedHeap(verbose);
+
+ if (establish_extended_heap) {
+ int size, rc;
+ char *comma, *begin;
+
+ comma = strchr(establish_extended_heap,',');
+ if (!comma)
+ return(CMD_PARAM_ERROR);
+ *comma = 0;
+ begin = (char *)strtoul(establish_extended_heap,0,0);
+ size = (int)strtoul(comma+1,0,0);
+ rc = extendHeap(begin,size);
+ if (rc == -1) {
+ printf("Extended heap already exists @ 0x%lx\n",
+ (ulong)getExtHeapBase());
+ }
+ if (rc < 0)
+ return(CMD_FAILURE);
+ }
+
+ if (!showheap)
+ return(CMD_SUCCESS);
+
+ if (optind == argc)
+ heapdump(verbose);
+
+ return(CMD_SUCCESS);
+}
+#else
+char *
+malloc(int size)
+{
+ return(0);
+}
+
+void
+free(char *buf)
+{
+}
+
+char *
+realloc(char *buf, int newsize, char *fname, int fline)
+{
+ return(0);
+}
+
+#endif
diff --git a/main/common/mallocdebug.h b/main/common/mallocdebug.h
new file mode 100644
index 0000000..8ab8cf1
--- /dev/null
+++ b/main/common/mallocdebug.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * FN:
+ *
+ * This file should be included in config.h if the monitor is
+ * to be built with malloc-debug enabled. The malloc-debug feature
+ * simply adds the filename and file line number to the mhdr structure.
+ *
+ * This makes it easier to find a memory leak because the location of
+ * the violating malloc call will be dumped by "heap -v".
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _MALLOCDEBUG_H_
+#define _MALLOCDEBUG_H_
+
+#ifndef ASSEMBLY_ONLY
+
+#define MALLOC_DEBUG
+extern char *malloc(int, char *, int);
+extern char *realloc(char *, int, char *, int);
+
+#define malloc(a) malloc(a,__FILE__,__LINE__)
+#define realloc(a,b) realloc(a,b,__FILE__,__LINE__)
+
+#endif /* ASSEMBLY_ONLY */
+
+#endif
diff --git a/main/common/memcmds.c b/main/common/memcmds.c
new file mode 100644
index 0000000..4ea2b86
--- /dev/null
+++ b/main/common/memcmds.c
@@ -0,0 +1,1259 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * memcmds.c:
+ *
+ * This code allows the monitor to display, modify, search, copy, fill
+ * and test memory in a variety of different ways.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include <ctype.h>
+#include "cli.h"
+
+/* With INCLUDE_MEMCMDS defined in config.h, all uMon commands in this
+ * file are automatically pulled into the build. If there is a need to
+ * be more selective, then set INCLUDE_MEMCMDS to zero in config.h and
+ * define only the INCLUDE_XX macros needed (shown below) to one in
+ * config.h.
+ */
+#if INCLUDE_MEMCMDS
+#define INCLUDE_PM 1
+#define INCLUDE_DM 1
+#define INCLUDE_FM 1
+#define INCLUDE_CM 1
+#define INCLUDE_SM 1
+#define INCLUDE_MT 1
+#endif
+
+#if INCLUDE_PM
+
+/* Pm():
+ * Put to memory.
+ *
+ * Arguments...
+ * arg1: address.
+ * arg2-argN: data to put beginning at specified address (max of 8).
+ *
+ * Options...
+ * -2 access as a short.
+ * -4 access as a long.
+ * -f fifo access (address does not increment).
+ * -s data is ascii string.
+ * -S data is ascii string and should be concatenated with the
+ * string that starts at the specified address.
+ */
+
+char *PmHelp[] = {
+ "Put to Memory",
+ "-[24aefosSx] {addr} {val|string} [val] ...",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -2 short access",
+ " -4 long access",
+ " -a AND operation",
+ " -e endian swap",
+ " -f fifo mode",
+ " -o OR operation",
+ " -s strcpy",
+ " -S strcat",
+ " -x XOR operation",
+#endif
+ 0,
+};
+
+#define PM_EQ_OPERATION 1
+#define PM_AND_OPERATION 2
+#define PM_OR_OPERATION 3
+#define PM_XOR_OPERATION 4
+
+int
+Pm(int argc,char *argv[])
+{
+ ulong val4, add, base;
+ ushort val2;
+ uchar val1, c;
+ int opt, width, ascii, fifo, i, j, concatenate, endian_swap, pmop;
+
+ pmop = PM_EQ_OPERATION;
+ width = 1;
+ ascii = fifo = 0;
+ concatenate = 0;
+ endian_swap = 0;
+ while((opt=getopt(argc,argv,"24aefosSx")) != -1) {
+ switch(opt) {
+ case '2':
+ width = 2;
+ break;
+ case '4':
+ width = 4;
+ break;
+ case 'a':
+ pmop = PM_AND_OPERATION;
+ break;
+ case 'e':
+ endian_swap = 1;
+ break;
+ case 'f':
+ fifo = 1;
+ break;
+ case 'o':
+ pmop = PM_OR_OPERATION;
+ break;
+ case 's':
+ ascii = 1;
+ break;
+ case 'S':
+ ascii = 1;
+ concatenate = 1;
+ break;
+ case 'x':
+ pmop = PM_XOR_OPERATION;
+ concatenate = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < (optind+2))
+ return(CMD_PARAM_ERROR);
+
+ add = strtoul(argv[optind],(char **)0,0);
+
+ if (ascii) {
+ base = add;
+ if (concatenate) { /* If concatenate, skip to */
+ while(*(uchar *)add) /* end of string, then start. */
+ add++;
+ }
+ for(i=optind+1;i<argc;i++) {
+ j = 0;
+ while(argv[i][j]) {
+ c = argv[i][j++];
+ if (c == '\\') {
+ c = argv[i][j++];
+ if (c == 'n')
+ *(char *)add = '\n';
+ else if (c == 'r')
+ *(char *)add = '\r';
+ else if (c == 't')
+ *(char *)add = '\t';
+ else {
+ *(char *)add = '\\';
+ if (!fifo)
+ add++;
+ *(char *)add = c;
+ }
+ }
+ else {
+ *(char *)add = c;
+ }
+ if (!fifo)
+ add++;
+ }
+ }
+ *(uchar *)add = 0;
+ shell_sprintf("STRLEN","%d",add-base);
+ return(CMD_SUCCESS);
+ }
+ for(i=optind+1;i<argc;i++) {
+ switch(width) {
+ case 1:
+ val1 = (uchar)strtoul(argv[i],(char **)0,0);
+ switch (pmop) {
+ case PM_EQ_OPERATION:
+ *(uchar *)add = val1;
+ break;
+ case PM_AND_OPERATION:
+ *(uchar *)add &= val1;
+ break;
+ case PM_OR_OPERATION:
+ *(uchar *)add |= val1;
+ break;
+ case PM_XOR_OPERATION:
+ *(uchar *)add ^= val1;
+ break;
+ }
+ if (!fifo) add++;
+ break;
+ case 2:
+ val2 = (ushort)strtoul(argv[i],(char **)0,0);
+ switch (pmop) {
+ case PM_EQ_OPERATION:
+ *(ushort *)add = endian_swap ? swap2(val2) : val2;
+ break;
+ case PM_AND_OPERATION:
+ *(ushort *)add &= endian_swap ? swap2(val2) : val2;
+ break;
+ case PM_OR_OPERATION:
+ *(ushort *)add |= endian_swap ? swap2(val2) : val2;
+ break;
+ case PM_XOR_OPERATION:
+ *(ushort *)add ^= endian_swap ? swap2(val2) : val2;
+ break;
+ }
+ if (!fifo) add += 2;
+ break;
+ case 4:
+ val4 = (ulong)strtoul(argv[i],(char **)0,0);
+ switch (pmop) {
+ case PM_EQ_OPERATION:
+ *(ulong *)add = endian_swap ? swap4(val4) : val4;
+ break;
+ case PM_AND_OPERATION:
+ *(ulong *)add &= endian_swap ? swap4(val4) : val4;
+ break;
+ case PM_OR_OPERATION:
+ *(ulong *)add |= endian_swap ? swap4(val4) : val4;
+ break;
+ case PM_XOR_OPERATION:
+ *(ulong *)add ^= endian_swap ? swap4(val4) : val4;
+ break;
+ }
+ if (!fifo) add += 4;
+ break;
+ }
+ }
+ return(CMD_SUCCESS);
+}
+#endif
+
+#if INCLUDE_DM
+/* Dm():
+ * Display memory.
+ *
+ * Arguments...
+ * arg1: address to start display
+ * arg2: if present, specifies the number of units to be displayed.
+ *
+ * Options...
+ * -2 a unit is a short.
+ * -4 a unit is a long.
+ * -b print chars out as is (binary).
+ * -d display in decimal.
+ * -e endian-swap for short/long display.
+ * -f fifo-type access (address does not increment).
+ * -l# size of line to be printed.
+ * -m prompt user for more.
+ * -s print chars out as is (binary) and terminates at a null.
+ * -v {varname} assign last value displayed to shell var varname.
+ *
+ * Defaults...
+ * Display in hex, and unit type is byte.
+ */
+
+char *DmHelp[] = {
+ "Display Memory",
+ "-[24bdefl:msv:] {addr} [byte-cnt]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -2 short access",
+ " -4 long access",
+ " -b binary",
+ " -d decimal",
+ " -e endian swap",
+ " -f fifo mode",
+ " -l# size of line (in bytes)",
+ " -m use 'more'",
+ " -s string",
+ " -v {var} load 'var' with element",
+#endif
+ 0,
+};
+
+#define BD_NULL 0
+#define BD_RAWBINARY 1
+#define BD_ASCIISTRING 2
+
+int
+Dm(int argc,char *argv[])
+{
+ ushort *sp;
+ uchar *cp, cbuf[128];
+ ulong *lp, add, count_rqst;
+ char *varname, *prfmt, *vprfmt;
+ int i, count, width, opt, more, size, fifo;
+ int hex_display, bin_display, endian_swap, linesize, sol;
+
+ linesize = 0;
+ width = 1;
+ more = fifo = 0;
+ bin_display = BD_NULL;
+ hex_display = 1;
+ endian_swap = 0;
+ varname = (char *)0;
+ while((opt=getopt(argc,argv,"24bdefl:msv:")) != -1) {
+ switch(opt) {
+ case '2':
+ width = 2;
+ break;
+ case '4':
+ width = 4;
+ break;
+ case 'b':
+ bin_display = BD_RAWBINARY;
+ break;
+ case 'd':
+ hex_display = 0;
+ break;
+ case 'e':
+ endian_swap = 1;
+ break;
+ case 'f':
+ fifo = 1;
+ break;
+ case 'l':
+ linesize = atoi(optarg);
+ break;
+ case 'm':
+ more = 1;
+ break;
+ case 'v':
+ varname = optarg;
+ break;
+ case 's':
+ bin_display = BD_ASCIISTRING;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < (optind+1))
+ return(CMD_PARAM_ERROR);
+
+ add = strtoul(argv[optind],(char **)0,0);
+ if (hex_display)
+ vprfmt = "0x%x";
+ else
+ vprfmt = "%d";
+
+ if (argc-(optind-1) == 3) {
+ count_rqst = strtoul(argv[optind+1],(char **)0,0);
+ count_rqst *= width;
+ }
+ else
+ count_rqst = 128;
+
+
+ if (bin_display != BD_NULL) {
+ cp = (uchar *)add;
+ if (bin_display == BD_ASCIISTRING) {
+ putstr((char *)cp);
+ if (varname) {
+ shell_sprintf(varname,vprfmt,cp+strlen((char *)cp)+1);
+ }
+ }
+ else {
+ for(i=0;i<count_rqst;i++)
+ putchar(*cp++);
+ }
+ putchar('\n');
+ return(CMD_SUCCESS);
+ }
+
+ sol = linesize == 0 ? 16 : linesize;
+ do {
+ count = count_rqst;
+
+ if (width == 1) {
+ cp = (uchar *)add;
+ if (hex_display)
+ prfmt = "%02X ";
+ else
+ prfmt = "%3d ";
+
+ if (varname) {
+ shell_sprintf(varname,vprfmt,*cp);
+ }
+ else {
+ while(count > 0) {
+ printf("%08lx: ",(ulong)cp);
+ if (count > sol)
+ size = sol;
+ else
+ size = count;
+
+ for(i=0;i<sol;i++) {
+ if (i >= size)
+ putstr(" ");
+ else {
+ cbuf[i] = *cp;
+ printf(prfmt,cbuf[i]);
+ }
+ if ((linesize == 0) && (i == 7))
+ putstr(" ");
+ if (!fifo)
+ cp++;
+ }
+ if ((hex_display) && (!fifo)) {
+ putstr(" ");
+ prascii(cbuf,size);
+ }
+ putchar('\n');
+ count -= size;
+ if (!fifo) {
+ add += size;
+ cp = (uchar *)add;
+ }
+ }
+ }
+ }
+ else if (width == 2) {
+ sp = (ushort *)add;
+ if (hex_display)
+ prfmt = "%04X ";
+ else
+ prfmt = "%5d ";
+
+ if (varname) {
+ shell_sprintf(varname,vprfmt,endian_swap ? swap2(*sp) : *sp);
+ }
+ else {
+ while(count>0) {
+ printf("%08lx: ",(ulong)sp);
+ if (count > sol)
+ size = sol;
+ else
+ size = count;
+
+ for(i=0;i<size;i+=2) {
+ printf(prfmt,endian_swap ? swap2(*sp) : *sp);
+ if (!fifo)
+ sp++;
+ }
+ putchar('\n');
+ count -= size;
+ if (!fifo) {
+ add += size;
+ sp = (ushort *)add;
+ }
+ }
+ }
+ }
+ else if (width == 4) {
+ lp = (ulong *)add;
+ if (hex_display)
+ prfmt = "%08X ";
+ else
+ prfmt = "%12d ";
+
+ if (varname) {
+ shell_sprintf(varname,vprfmt,endian_swap ? swap4(*lp) : *lp);
+ }
+ else {
+ while(count>0) {
+ printf("%08lx: ",(ulong)lp);
+ if (count > sol)
+ size = sol;
+ else
+ size = count;
+ for(i=0;i<size;i+=4) {
+ printf(prfmt,endian_swap ? swap4(*lp) : *lp);
+ if (!fifo)
+ lp++;
+ }
+ putchar('\n');
+ count -= size;
+ if (!fifo) {
+ add += size;
+ lp = (ulong *)add;
+ }
+ }
+ }
+ }
+ } while (more && More());
+ return(CMD_SUCCESS);
+}
+#endif
+
+
+#if INCLUDE_FM
+/* Fm():
+ * Fill memory with user-specified data.
+ * Syntax:
+ * fm [options] {start} {count | finish} {value}
+ */
+
+char *FmHelp[] = {
+ "Fill Memory",
+ "-[24cinp] {start} {finish|byte-cnt} {value|pattern}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -2 short access",
+ " -4 long access",
+ " -c arg2 is count (in bytes)",
+ " -i increment {value|pattern}",
+ " -n no verification",
+ " -p arg3 is a pattern",
+#endif
+ 0,
+};
+
+int
+Fm(int argc,char *argv[])
+{
+ char *pp, *pattern;
+ ulong start, finish;
+ uchar *cptr, cdata;
+ ushort *wptr, wdata;
+ ulong *lptr, ldata, error_at;
+ int width, opt, arg2iscount, arg3ispattern, err, verify, increment;
+
+ width = 1;
+ verify = 1;
+ increment = 0;
+ error_at = 0;
+ arg2iscount = 0;
+ arg3ispattern = 0;
+ pattern = pp = (char *)0;
+ while((opt=getopt(argc,argv,"24cinp")) != -1) {
+ switch(opt) {
+ case '2':
+ width = 2;
+ break;
+ case '4':
+ width = 4;
+ break;
+ case 'c':
+ arg2iscount = 1;
+ break;
+ case 'i':
+ increment = 1;
+ break;
+ case 'n':
+ verify = 0;
+ break;
+ case 'p':
+ arg3ispattern = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ /* Three args required...
+ * If -p is specfied, then width can only be 1...
+ */
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+
+ if ((arg3ispattern) && (width != 1)) {
+ printf("Note: -p uses byte-wide access (-%d ignored)\n",width);
+ width = 1;
+ }
+
+ start = strtoul(argv[optind],(char **)0,0);
+ finish = strtoul(argv[optind+1],(char **)0,0);
+ if (arg3ispattern) {
+ pattern = pp = argv[optind+2];
+ ldata = 0;
+ }
+ else
+ ldata = strtoul(argv[optind+2],0,0);
+
+ if (arg2iscount)
+ finish = start + finish;
+ else if (start >= finish) {
+ printf("start > finish\n");
+ return(CMD_PARAM_ERROR);
+ }
+
+ err = 0;
+ switch (width) {
+ case 1:
+ cdata = (uchar) ldata;
+ for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) {
+ if (arg3ispattern) {
+ if (*pp == 0)
+ pp = pattern;
+ cdata = (uchar)*pp++;
+ }
+ *cptr = cdata;
+ if (verify) {
+ if (*cptr != cdata) {
+ err = 1;
+ error_at = (ulong)cptr;
+ break;
+ }
+ }
+ cdata += increment;
+ }
+ break;
+ case 2:
+ wdata = (ushort) ldata;
+ for(wptr=(ushort *)start;wptr<(ushort *)finish;wptr++) {
+ *wptr = wdata;
+ if (verify) {
+ if (*wptr != wdata) {
+ err = 1;
+ error_at = (ulong)wptr;
+ break;
+ }
+ }
+ wdata += increment;
+ }
+ break;
+ case 4:
+ for(lptr=(ulong *)start;lptr<(ulong *)finish;lptr++) {
+ *lptr = ldata;
+ if (verify) {
+ if (*lptr != ldata) {
+ err = 1;
+ error_at = (ulong)lptr;
+ break;
+ }
+ }
+ ldata += increment;
+ }
+ break;
+ }
+ if (err) {
+ printf("Error at 0x%lx\n",error_at);
+ return(CMD_FAILURE);
+ }
+ return(CMD_SUCCESS);
+}
+#endif
+
+#if INCLUDE_SM
+
+/* Sm():
+ * Search memory.
+ */
+
+char *SmHelp[] = {
+ "Search Memory",
+ "-[24cnqsx] {start} {finish|byte-cnt} {srchfor}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -2 short access",
+ " -4 long access",
+ " -c arg2 is count (in bytes)",
+ " -n srchfor_not (NA for -s or -x)",
+ " -q quit after first search hit",
+ " -s string srch",
+ " -x hexblock srch",
+#endif
+ 0,
+};
+
+#define SM_NORMAL 1 /* Search for 1 value */
+#define SM_STRING 2 /* Search for ascii string */
+#define SM_HEXBLOCK 3 /* Search for block of hex data */
+
+int
+Sm(int argc,char *argv[])
+{
+ ulong start, finish;
+ int width, opt, i, j, mode, arg2iscount, not, quit;
+ char *srchfor, tmp;
+ uchar *cptr, cdata, data[32];
+ ushort *wptr, wdata;
+ ulong *lptr, ldata;
+
+ not = 0;
+ quit = 0;
+ width = 1;
+ arg2iscount = 0;
+ mode = SM_NORMAL;
+ while((opt=getopt(argc,argv,"24cnqsx")) != -1) {
+ switch(opt) {
+ case '2':
+ width = 2;
+ break;
+ case '4':
+ width = 4;
+ break;
+ case 'c':
+ arg2iscount = 1;
+ break;
+ case 'n':
+ not = 1; /* opposite logic SM_NORMAL only. */
+ break;
+ case 'q':
+ quit = 1; /* quit after first [no]match */
+ break;
+ case 's':
+ mode = SM_STRING; /* ascii string */
+ break;
+ case 'x':
+ mode = SM_HEXBLOCK; /* hex data */
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+
+ start = strtoul(argv[optind],(char **)0,0);
+ finish = strtoul(argv[optind+1],(char **)0,0);
+ if (arg2iscount)
+ finish = start + finish;
+ srchfor = argv[optind+2];
+
+ if (mode == SM_HEXBLOCK) {
+ char *ex;
+
+ if (not)
+ return(CMD_PARAM_ERROR);
+ ex = strpbrk(srchfor,"xX");
+ if (ex)
+ srchfor=ex+1;
+ if (strlen(srchfor) % 2)
+ return(CMD_PARAM_ERROR);
+ for(i=0,j=0;i<(sizeof data);i++,j+=2) {
+ if (srchfor[j] == 0)
+ break;
+ tmp = srchfor[j+2];
+ srchfor[j+2] = 0;
+ data[i] = (uchar)strtoul(&srchfor[j],0,16);
+ srchfor[j+2] = tmp;
+ }
+ for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) {
+ if (memcmp((char *)cptr,(char *)data,i) == 0) {
+ printf("Match @ 0x%lx\n",(ulong)cptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ return(CMD_SUCCESS);
+ }
+ else if (mode == SM_STRING) {
+ int len;
+
+ if (not)
+ return(CMD_PARAM_ERROR);
+ len = strlen(srchfor);
+ for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) {
+ if (strncmp((char *)cptr,srchfor,len) == 0) {
+ printf("Match @ 0x%lx\n",(ulong)cptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ }
+ else if (width == 1) {
+ cdata = (uchar)strtoul(srchfor,(char **)0,0);
+ for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) {
+ if (not) {
+ if (*cptr != cdata) {
+ printf("Nomatch @ 0x%lx (0x%x)\n",(ulong)cptr,*cptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ else if (*cptr == cdata) {
+ printf("Match @ 0x%lx\n",(ulong)cptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ }
+ else if (width == 2) {
+ wdata = (ushort)strtoul(srchfor,(char **)0,0);
+ for(wptr=(ushort *)start;wptr<(ushort *)finish;wptr++) {
+ if (not) {
+ if (*wptr != wdata) {
+ printf("Nomatch @ 0x%lx (0x%x)\n",(ulong)wptr,*wptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ else if (*wptr == wdata) {
+ printf("Match @ 0x%lx\n",(ulong)wptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ }
+ else {
+ ldata = (ulong)strtoul(srchfor,(char **)0,0);
+ for(lptr=(ulong *)start;lptr<(ulong *)finish;lptr++) {
+ if (not) {
+ if (*lptr != ldata) {
+ printf("Nomatch @ 0x%lx (0x%lx)\n",(ulong)lptr,*lptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ else if (*lptr == ldata) {
+ printf("Match @ 0x%lx\n",(ulong)lptr);
+ if (quit || gotachar())
+ break;
+ }
+ }
+ }
+ return(CMD_SUCCESS);
+}
+#endif
+
+#if INCLUDE_CM
+
+/* Cm():
+ * Copy memory.
+ *
+ * Arguments...
+ * arg1: source address
+ * arg2: destination address
+ * arg3: byte count
+ *
+ * Options...
+ * -2 access as a short.
+ * -4 access as a long.
+ * -f fifo access (address does not increment).
+ * -v verify (only) that the range specified, is copied.
+ */
+
+char *CmHelp[] = {
+ "Copy Memory",
+ "-[24fv] {src} {dst} {byte-cnt}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -2 short access",
+ " -4 long access",
+ " -f fifo mode",
+ " -v verify only",
+#endif
+ 0,
+};
+
+int
+Cm(int argc,char *argv[])
+{
+ ulong src, dest, end, bytecount;
+ int opt, width, fifo, verify, verify_failed;
+
+ width = 1;
+ fifo = verify = 0;
+ verify_failed = 0;
+ while((opt=getopt(argc,argv,"24fv")) != -1) {
+ switch(opt) {
+ case '2':
+ width = 2;
+ break;
+ case '4':
+ width = 4;
+ break;
+ case 'f':
+ fifo = 1;
+ break;
+ case 'v':
+ verify = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc != optind+3) {
+ return(CMD_PARAM_ERROR);
+ }
+ if ((verify) && (fifo)) {
+ printf("Can't verify in fifo mode\n");
+ return(CMD_FAILURE);
+ }
+
+ src = strtoul(argv[optind],(char **)0,0);
+ dest = strtoul(argv[optind+1],(char **)0,0);
+ bytecount = strtoul(argv[optind+2],(char **)0,0);
+
+ if (bytecount <= 0) {
+ printf("Invalid byte count\n");
+ return(CMD_FAILURE);
+ }
+
+ end = src+bytecount-1;
+ if (src > end) {
+ printf("Invalid range (possibly overlapping address 0?)\n");
+ return(CMD_FAILURE);
+ }
+
+ if (width == 1) {
+ while(src <= end) {
+ if (verify) {
+ if (*(uchar *)dest != *(uchar *)src) {
+ verify_failed = 1;
+ break;
+ }
+ }
+ else
+ *(uchar *)dest = *(uchar *)src;
+ if (!fifo)
+ dest++;
+ src++;
+ }
+ }
+ else if (width == 2) {
+ while(src <= end) {
+ if (verify) {
+ if (*(ushort *)dest != *(ushort *)src) {
+ verify_failed = 1;
+ break;
+ }
+ }
+ else
+ *(ushort *)dest = *(ushort *)src;
+ if (!fifo)
+ dest += 2;
+ src += 2;
+ }
+ }
+ else { /* width == 4 */
+ while(src <= end) {
+ if (verify) {
+ if (*(ulong *)dest != *(ulong *)src) {
+ verify_failed = 1;
+ break;
+ }
+ }
+ else
+ *(ulong *)dest = *(ulong *)src;
+ if (!fifo)
+ dest += 4;
+ src += 4;
+ }
+ }
+ if ((verify) && (verify_failed)) {
+ printf("Verify failed: *0x%lx != *0x%lx\n",src,dest);
+ return(CMD_FAILURE);
+ }
+ return(CMD_SUCCESS);
+}
+
+#endif
+
+#if INCLUDE_MT
+
+/* Mt():
+ * Memory test
+ * Walking ones and address-in-address tests for data and address bus
+ * testing respectively. This test, within the context of a monitor
+ * command, has limited value. It must assume that the memory space
+ * from which this code is executing is sane (obviously, or the code
+ * would not be executing) and the ram used for stack and bss must
+ * already be somewhat useable.
+ */
+char *MtHelp[] = {
+ "Memory test",
+ "-[CcqSs:t:v] {addr} {len}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -c continuous",
+ " -C crc32 calculation",
+ " -q quit on error",
+ " -S determine size of on-board memory (see note below)",
+ " -s## sleep ## seconds between adr-in-addr write and readback",
+ " -t## toggle data on '##'-bit boundary (##: 32 or 64)",
+ " -v cumulative verbosity...",
+ " -v=<ticker>, -vv=<ticker + msg-per-error>",
+ "",
+ "Memory test is walking ones followed by address-in-address",
+ "",
+ "Note1: For normal memory test, hit any key to abort test with errors",
+ "Note2: With -S option, {addr} is the base of physical memory and",
+ " {len} is the maximum expected size of that memory. The",
+ " shell variable MEMSIZE is loaded with the result.",
+#endif
+ 0,
+};
+
+int
+Mt(int argc,char *argv[])
+{
+ int errcnt, len, testaborted, opt, runcrc;
+ int quitonerr, verbose, continuous, testtot, sizemem;
+ ulong arg1, arg2, *start, rwsleep, togglemask;
+ ulong *end, walker, readback, shouldbe;
+ volatile ulong *addr;
+
+ runcrc = 0;
+ sizemem = 0;
+ continuous = 0;
+ quitonerr = 0;
+ verbose = 0;
+ rwsleep = 0;
+ togglemask = 0;
+ while((opt=getopt(argc,argv,"cCqSs:t:v")) != -1) {
+ switch(opt) {
+ case 'c':
+ continuous = 1;
+ break;
+ case 'C':
+ runcrc = 1;
+ break;
+ case 'q':
+ quitonerr = 1;
+ break;
+ case 'S':
+ sizemem = 1;
+ break;
+ case 's':
+ rwsleep = strtoul(optarg,0,0);
+ break;
+ case 't':
+ switch(atoi(optarg)) {
+ case 32:
+ togglemask = 0x00000004;
+ break;
+ case 64:
+ togglemask = 0x00000008;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ break;
+ case 'v':
+ verbose++; /* Cumulative verbosity */
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ arg1 = strtoul(argv[optind],(char **)0,0);
+ arg2 = strtoul(argv[optind+1],(char **)0,0);
+
+ /* If -S option, then run a memory size test.
+ * For this case, arg1 is the base and arg2 is the maximum expected
+ * size of the on-board memory...
+ */
+ if (sizemem) {
+ vulong tmp1, base, test;
+
+ base = arg1;
+ test = arg2;
+
+ tmp1 = *(vulong *)base;
+ *(vulong *)base = 0xDEADBEEF;
+
+ /* Got this algorithm from Bill Gatliff...
+ * Assume that memory always starts at address 0, for
+ * simplicity in the explanation. What you do is write 256
+ * at 256MB, 128 at 128MB, 64@64MB, and so on. When you get
+ * down to zero (or the smallest available memory address, if
+ * you want to stop sooner), you read the value stored at 0.
+ * That value is the size of available memory.
+ */
+ while(test >= 0x100000) {
+ *(vulong *)(base + test) = test/0x100000;
+ if (verbose)
+ printf("*0x%lx = 0x%lx (0x%lx)\n",(base+test),test/0x100000,
+ *(vulong *)(base + test));
+ test >>= 1;
+ }
+
+ /* If the base location was not changed by the above algorithm
+ * then the address bus doesn't alias, so try something else...
+ * This time, walk up the address space starting at 0x100000
+ * and doubling each time until the write to the address (minus 4)
+ * fails. The last successful write indicates the top of memory.
+ */
+ if (*(vulong *)base == 0xDEADBEEF) {
+ test = 0x100000;
+ while(test <= arg2) {
+ vulong *lp = (vulong *)(base+test-sizeof(long));
+
+ if (verbose)
+ printf("write to 0x%lx, ",(long)lp);
+ *lp = 0xdeadbeef;
+ monDelay(100);
+ if (*lp != 0xdeadbeef) {
+ if (verbose)
+ printf("failed\n");
+ break;
+ }
+ if (verbose)
+ printf("passed\n");
+ test <<= 1;
+ }
+ test >>= 1;
+ printf("Size: %ld MB\n",test/0x100000);
+ shell_sprintf("MEMSIZE","0x%lx",test);
+ }
+ else {
+ printf("Size: %ld MB\n",*(vulong *)base);
+ shell_sprintf("MEMSIZE","0x%lx",*(vulong *)base * 0x100000);
+ }
+
+ *(vulong *)base = tmp1;
+ return(CMD_SUCCESS);
+ }
+
+ /* If -C option, then run a CRC32 on a specified block of memory...
+ */
+ if (runcrc) {
+ ulong mtcrc;
+
+ mtcrc = crc32((uchar *)arg1,arg2);
+ printf("CRC32 @ 0x%lx (0x%lx bytes) = 0x%lx\n",arg1,arg2,mtcrc);
+ shell_sprintf("MTCRC","0x%lx",mtcrc);
+ return(CMD_SUCCESS);
+ }
+
+ arg1 &= ~0x3; /* Word align */
+ arg2 &= ~0x3;
+
+ testtot = 0;
+ printf("Testing 0x%lx .. 0x%lx\n",arg1,arg1+arg2);
+
+ start = (ulong *)arg1;
+ len = (int)arg2;
+ testaborted = errcnt = 0;
+
+ while(1) {
+ /* Walking Ones test:
+ * This test is done to verify that no data bits are shorted.
+ * Write 32 locations, each with a different bit set, then
+ * read back those 32 locations and make sure that bit (and only
+ * that bit) is set.
+ */
+ walker = 1;
+ end = start + 32;
+ for (addr=start;addr<end;addr++) {
+ *addr = walker;
+ walker <<= 1;
+ }
+
+ walker = 1;
+ for (addr=start;addr<end;addr++) {
+ readback = *addr;
+ if (readback != walker) {
+ errcnt++;
+ if (verbose > 1)
+ printf("WalkingOneErr @ x%lx: read x%lx expected x%lx\n",
+ (ulong)addr,readback,walker);
+ if (quitonerr)
+ break;
+ }
+ walker <<= 1;
+ }
+
+ /* Address-in-address test:
+ * This test serves three purposes...
+ * 1. the "address-in-address" tests for stuck address bits.
+ * 2. the "not-address-in-address" (-t option) exercises the
+ * data bus.
+ * 3. the sleep between read and write tests for valid memory
+ * refresh in SDRAM based systems.
+ *
+ * The togglemask is used to determine at what rate the data
+ * should be flipped... every 32 bits or every 64 bits.
+ */
+ if ((!testaborted) && ((!errcnt) || (errcnt && !quitonerr))) {
+
+ /* In each 32-bit address, store either the address or the
+ * complimented address...
+ */
+ end = (ulong *)((int)start + len);
+ for (addr=start;addr<end;addr++) {
+ if (((ulong)addr & 0x3ffff) == 0) {
+ if (gotachar()) {
+ testaborted = 1;
+ break;
+ }
+ if (verbose)
+ ticktock();
+ }
+
+ if ((ulong)addr & togglemask)
+ *addr = ~(ulong)addr;
+ else
+ *addr = (ulong)addr;
+ }
+
+ /* If -s is specified, then delay for the specified number
+ * of seconds. This option just allows the ram to "sit"
+ * for a a while; hence, verifying automatic refresh in
+ * the case of SDRAM.
+ */
+ if (rwsleep && !testaborted) {
+ int i;
+ for(i=0;i<rwsleep;i++) {
+ monDelay(1000);
+ if (gotachar()) {
+ testaborted = 1;
+ break;
+ }
+ if (verbose)
+ ticktock();
+ }
+ }
+
+ if (testaborted)
+ break;
+
+ /* For each 32-bit address, verify either the address or the
+ * complimented address...
+ */
+ for (addr=start;addr<end;addr++) {
+ if (((ulong)addr & 0x3ffff) == 0) {
+ if (gotachar()) {
+ testaborted = 1;
+ break;
+ }
+ if (verbose)
+ ticktock();
+ }
+
+ readback = *addr;
+ if ((ulong)addr & togglemask)
+ shouldbe = ~(ulong)addr;
+ else
+ shouldbe = (ulong)addr;
+ if (readback != shouldbe) {
+ errcnt++;
+ if (verbose > 1)
+ printf("AdrInAdrErr @ x%lx: read x%lx expected x%lx\n",
+ (ulong)addr,readback,shouldbe);
+ if (quitonerr) {
+ testaborted = 1;
+ break;
+ }
+ }
+ }
+ }
+ testtot++;
+ if (!continuous || testaborted || (errcnt && quitonerr))
+ break;
+ }
+
+
+ printf("Found %d errors", errcnt);
+ if (continuous && testaborted)
+ printf(" after %d test loops",testtot);
+ printf(".\n");
+
+ if (errcnt)
+ return(CMD_FAILURE);
+ else
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/memtrace.c b/main/common/memtrace.c
new file mode 100644
index 0000000..2962007
--- /dev/null
+++ b/main/common/memtrace.c
@@ -0,0 +1,379 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * memtrace.c:
+ *
+ * This file contains CLI and API code to support a simple memory trace
+ * capability that allows application developers to call mon_memtrace()
+ * with a "printf-like" formatted arglist and the formatted string is
+ * put into a circular buffer in some allocated RAM space.
+ * The circular buffer is established by "mtrace cfg" command, then all
+ * subsequent calls to mon_memtrace() will have the formatted string
+ * destined for that buffer.
+ *
+ * To keep the output formatted clean, the user of mon_memtrace() should
+ * not include any line-feeds in the string. Each time mon_memtrace() is
+ * called, a line feed and sequence number is prepended to the string.
+ * This allows the dump to simply run through the buffer using putchar().
+ *
+ * Both the mon_memtrace() API function and the dump facility in the CLI
+ * will deal with buffer wrapping.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include <stdarg.h>
+#include "stddefs.h"
+#include "genlib.h"
+#include "cli.h"
+
+#if INCLUDE_MEMTRACE
+
+#define MINBUFSIZE 512
+#define MAXLINSIZE MINBUFSIZE/2
+
+#define MODE_PRINT (1<<0) /* mtrace text is output to console */
+#define MODE_NOWRAP (1<<1) /* when mtrace buffer fills, stop */
+
+/* struct mtInfo:
+ * This structure is at the base of the memory space allocated for
+ * the print buffer. The control structure is part of the print buffer
+ * because the print buffer is assumed to be outside of the bss area
+ * of the monitor; hence, if a reset occurs and the monitor clears out
+ * its bss space, this structure will still be accessible and contain
+ * the data prior to the reset.
+ * So, to initialize a memory trace buffer use...
+ * mtrace cfg BASE SIZE
+ * and to re-establish the trace after a reset, use...
+ * mtrace mip BASE
+ */
+struct mtInfo {
+ char *base; /* Base of ram space allocated for print buffer. */
+ char *ptr; /* Running pointer into circular print buffer. */
+ char *end; /* End of ram space allocated. */
+ int size; /* Size of space originally allocated for mtrace. */
+ int off; /* Set if tracing is disabled. */
+ int sno; /* Sequence number of Mtrace() call. */
+ int wrap; /* Wrap counter. */
+ int mode; /* See MODE_XXX bits above. */
+ int reentered; /* Reentry counter. */
+};
+
+static struct mtInfo *Mip;
+
+/* Mtrace():
+ * Memory trace... This function can be used to place some trace statements
+ * (readable text) in some memory location specified by the
+ * setting of mtracebuf. This was originally written for debugging Xmodem
+ * because you can't use printf() since the protocol is using the serial
+ * port. I have since pulled it out of the Xmodem.c file and placed it in
+ * generally accessible space so that it can be made available to the
+ * application code and other monitor code.
+ */
+
+int
+Mtrace(char *fmt,...)
+{
+ static int inMtraceNow;
+ int len;
+ char *eolp;
+ va_list argp;
+
+ /* Mtrace not configured or disabled, so just return.
+ */
+ if (!Mip || Mip->off)
+ return(0);
+
+ /* This may be called from interrupt and/or non-interrupt space of
+ * an application, so we must deal with possible reentrancy here.
+ */
+ if (inMtraceNow) {
+ Mip->reentered++;
+ return(0);
+ }
+
+ inMtraceNow = 1;
+
+ Mip->ptr += snprintf(Mip->ptr,MAXLINSIZE,"\n<%04d> ",Mip->sno++);
+
+ va_start(argp,fmt);
+ len = vsnprintf(Mip->ptr,MAXLINSIZE,fmt,argp);
+ va_end(argp);
+
+ /* Strip all CR/LFs from the incoming string.
+ * The incoming string can have CR/LFs in it; however, they are stripped
+ * so that the format of the dump is stable (one line per Mtrace call).
+ * Notice that the top line of this function inserts a newline ahead
+ * of the sequence number; hence, additional CR/LFs in the text would
+ * just confuse the output.
+ */
+ eolp = Mip->ptr;
+ while(*eolp) {
+ if ((*eolp == '\r') || (*eolp == '\n')) {
+ strcpy(eolp,eolp+1);
+ len--;
+ }
+ else
+ eolp++;
+ }
+
+ /* If print flag is set, then dump to the console...
+ */
+ if (Mip->mode & MODE_PRINT) {
+ int i;
+ for(i=0;i<len;i++)
+ putchar(*Mip->ptr++);
+ putchar('\n');
+ }
+ else
+ Mip->ptr += len;
+
+ if (Mip->ptr >= Mip->end) {
+ Mip->ptr = Mip->base;
+ if (Mip->mode & MODE_NOWRAP)
+ Mip->off = 1;
+ else
+ Mip->wrap++;
+ }
+
+ /* Flush the d-cache of the mtrace buffer and Mip structure after each
+ * transfer...
+ * This is important because if this is being accessed from an
+ * application that has d-cache enabled, then the hardware is reset,
+ * there is a chance that the data written was in cache and would be
+ * lost.
+ */
+ flushDcache((char *)Mip,sizeof(struct mtInfo));
+ flushDcache((char *)Mip->base,Mip->end - Mip->base);
+
+ inMtraceNow = 0;
+ return(len);
+}
+
+void
+MtraceReset(void)
+{
+ Mip->ptr = Mip->base;
+ Mip->sno = 1;
+ Mip->wrap = 0;
+ Mip->off = 0;
+ Mip->mode = 0;
+ Mip->reentered = 0;
+ memset(Mip->base,0,Mip->size-sizeof(struct mtInfo));
+}
+
+void
+MtraceInit(char *base, int size)
+{
+ if (size < MINBUFSIZE)
+ return;
+
+ Mip = (struct mtInfo *)base;
+ Mip->base = base + sizeof(struct mtInfo);
+ Mip->size = size;
+ Mip->end = (Mip->base + size - MAXLINSIZE);
+ MtraceReset();
+}
+
+char *
+mDump(char *bp, int more)
+{
+ int line;
+
+ line = 0;
+
+ while((bp < Mip->end) && (*bp)) {
+ putchar(*bp);
+ if (more && (*bp == '\n')) {
+ if (++line == 24) {
+ line = 0;
+ if (!More())
+ return(0);
+ }
+ }
+ bp++;
+ }
+ while(*bp) {
+ putchar(*bp);
+ if (more && (*bp == '\n')) {
+ if (++line == 24) {
+ line = 0;
+ if (!More())
+ return(0);
+ }
+ }
+ bp++;
+ }
+ return(bp);
+}
+
+/* If Mip pointer is configured, return 1; else return zero
+ * and print an error message.
+ */
+static int
+MipConfigured(void)
+{
+ if (Mip)
+ return(1);
+ printf("Not configured\n");
+ return(0);
+}
+
+char *MtraceHelp[] = {
+ "Configure/Dump memory trace.",
+ "-[nm] {cmd} [cmd specific args]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -m enable 'more' flag for dump.",
+ " -n disable wrapping.",
+ "Cmd:",
+ " on",
+ " off",
+ " dump",
+ " pron",
+ " reset",
+ " log {msg}",
+ " mip {base}",
+ " cfg [{base} {size}]",
+#endif
+ 0
+};
+
+int
+MtraceCmd(int argc,char *argv[])
+{
+ char *bp;
+ int more, opt, nowrap;
+
+ more = 0;
+ nowrap = 0;
+ while((opt=getopt(argc,argv,"nm")) != -1) {
+ switch(opt) {
+ case 'n':
+ nowrap = 1;
+ break;
+ case 'm':
+ more = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc <= optind)
+ return(CMD_PARAM_ERROR);
+
+ if (!strcmp(argv[optind],"cfg")) {
+ if (argc == optind + 3) {
+ MtraceInit((char *)strtoul(argv[optind+1],0,0),
+ strtoul(argv[optind+2],0,0));
+ if (nowrap)
+ Mip->mode |= MODE_NOWRAP;
+ }
+ else if (argc == optind + 1) {
+ if (MipConfigured()) {
+ printf("Base: 0x%lx, End: 0x%lx\n",
+ (ulong)Mip->base,(ulong)Mip->end);
+ printf("Ptr: 0x%lx, Sno: %d\n",(ulong)Mip->ptr,Mip->sno);
+ printf("Wrap: %d\n",Mip->wrap);
+ }
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (!strcmp(argv[optind],"on")) {
+ if (MipConfigured()) {
+ Mip->mode &= ~MODE_PRINT;
+ Mip->off = 0;
+ }
+ }
+ else if (!strcmp(argv[optind],"pron")) {
+ if (MipConfigured()) {
+ Mip->mode |= MODE_PRINT;
+ Mip->off = 0;
+ }
+ }
+ else if (!strcmp(argv[optind],"off")) {
+ if (MipConfigured())
+ Mip->off = 1;
+ }
+ else if (!strcmp(argv[optind],"reset")) {
+ if (MipConfigured())
+ MtraceReset();
+ }
+ else if (!strcmp(argv[optind],"mip")) {
+ if (argc != optind + 2)
+ return(CMD_PARAM_ERROR);
+ Mip = (struct mtInfo *)strtoul(argv[optind+1],0,0);
+ }
+ else if (!strcmp(argv[optind],"log")) {
+ if (argc != optind + 2)
+ return(CMD_PARAM_ERROR);
+ Mtrace(argv[optind+1]);
+ }
+ else if (!strcmp(argv[optind],"dump")) {
+ if (MipConfigured()) {
+ if (Mip->reentered)
+ printf("Reentry count: %d\n",Mip->reentered);
+ if (Mip->wrap) {
+ printf("Buffer wrapped...\n");
+ bp = Mip->ptr;
+ while(bp < Mip->end) {
+ if (*bp == '\n') {
+ bp = mDump(bp,more);
+ break;
+ }
+ bp++;
+ }
+ if (bp) {
+ bp = Mip->base;
+ while(bp < Mip->ptr)
+ putchar(*bp++);
+ }
+ }
+ else {
+ bp = mDump(Mip->base,more);
+ }
+ printf("\n\n");
+ }
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+
+#else
+
+void
+MtraceInit(char *base, int size)
+{
+ printf("Mtrace() facility not built in.\n");
+}
+
+int
+Mtrace(char *fmt, ...)
+{
+ return(0);
+}
+
+#endif
diff --git a/main/common/misc.c b/main/common/misc.c
new file mode 100644
index 0000000..4e32ed5
--- /dev/null
+++ b/main/common/misc.c
@@ -0,0 +1,528 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * misc.c:
+ *
+ * This file contains miscellaneous functions that are used by all target
+ * versions of the monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "monflags.h"
+#include "monlib.h"
+#include "genlib.h"
+#include "devices.h"
+#include "cpuio.h"
+#include <ctype.h>
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "warmstart.h"
+#include "timer.h"
+#include "version.h"
+#include "target_version.h"
+
+#ifdef USR_HEADER_FUNC
+extern void USR_HEADER_FUNC(int center);
+#endif
+
+/* extWatchDog():
+ * This function pointer is used by the application to override the
+ * monitor's configured watchdog functionality. Refer to config.h
+ * in umon_ports/template for more information on the WATCHDOG macro.
+ */
+#ifdef WATCHDOG_ENABLED
+int (*extWatchDog)(void);
+#endif
+
+/* AppExitStatus:
+ * Global copy of the application's exit status.
+ */
+int AppExitStatus;
+
+char *
+monVersion(void)
+{
+ static char buf[16];
+
+ /* Build the version string as "X.Y.Z"
+ */
+ snprintf(buf,sizeof(buf),"%d.%d.%d",
+ MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION);
+
+ return(buf);
+}
+
+/* ShowVersion():
+ * Display the build time and date of the running monitor.
+ */
+void
+ShowVersion(void)
+{
+ printf("Monitor core release: %d.%d, target version %d (built: %s)\n",
+ MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION,monBuilt());
+ if (ApplicationInfo[0])
+ printf("%s\n",ApplicationInfo);
+}
+
+/* monHeader():
+ * Dump the common stuff that is displayed at the console port when
+ * the monitor first starts up. If called with 'center' set, then
+ * the printed output is centered on an 80-character screen width.
+ */
+void
+monHeader(int center)
+{
+ char *ip, *mac;
+ int (*pfunc)(char *, ...);
+
+ /* Some folks just don't like the opening banner to be centered, so
+ * force center to 0 if DONT_CENTER_MONHEADER is defined...
+ */
+#ifdef DONT_CENTER_MONHEADER
+ center = 0;
+#endif
+
+ if (center) {
+ printf("\n\n");
+ pfunc = cprintf;
+ }
+ else
+ pfunc = printf;
+
+ /* Optionally support (via config.h) up to four lines of user-specified
+ * header text...
+ */
+#ifdef USR_HEADER1
+ pfunc("%s\n",USR_HEADER1);
+#endif
+#ifdef USR_HEADER2
+ pfunc("%s\n",USR_HEADER2);
+#endif
+#ifdef USR_HEADER3
+ pfunc("%s\n",USR_HEADER3);
+#endif
+#ifdef USR_HEADER4
+ pfunc("%s\n",USR_HEADER4);
+#endif
+
+ pfunc("MICRO MONITOR %s\n",monVersion());
+ pfunc("Platform: %s\n",PLATFORM_NAME);
+ pfunc("CPU: %s\n",CPU_NAME);
+ pfunc("Built: %s\n",monBuilt());
+ pfunc("Monitor RAM: 0x%06x-0x%06x\n",&bss_start,&bss_end);
+ pfunc("Application RAM Base: 0x%06x\n",APPLICATION_RAMSTART);
+ mac = getenv("ETHERADD");
+ if (mac)
+ pfunc("MAC: %s\n",mac);
+ ip = getenv("IPADD");
+ if (ip)
+ pfunc("IP: %s\n",ip);
+
+#ifdef USR_HEADER_FUNC
+ USR_HEADER_FUNC(center);
+#endif
+
+#ifdef TOD_IN_MONHEADER
+ showDate(center);
+#endif
+}
+
+/* stkchk():
+ * The monitor's stack is a statically allocated array (MonStack).
+ * At initialization the stack pointer is set to the top of this stack
+ * and the bottom is loaded with 0xdeaddead. This function simply
+ * verifies that the bottom of the stack is sane (still reads 0xdeaddead).
+ * If not, an error is printed.
+ */
+int
+stkchk(char *msg)
+{
+ extern ulong MonStack[];
+
+ if (MonStack[0] != 0xdeaddead) {
+ printf("\n***** Monitor stack overflow (%s) *****\n",msg);
+ MonStack[0] = 0xdeaddead;
+ return(-1);
+ }
+ return(0);
+}
+
+void
+stkusage(void)
+{
+ int i;
+ ulong *sp, stackval;
+ extern ulong MonStack[];
+
+ printf("Stack: bottom=0x%lx, size=%d",(long)MonStack,MONSTACKSIZE);
+
+ sp = MonStack;
+ sp++; /* Increment past 0xdeaddead */
+
+ /* If the very first entry in stack space is not set to
+ * STACK_PREINIT_VAL, then we assume that stkinit() was not called
+ * at startup so don't print any stack usage information...
+ */
+ if (*sp == STACK_PREINIT_VAL) {
+ for(i=0;i<MONSTACKSIZE;i+=4) {
+ if (*sp++ != STACK_PREINIT_VAL)
+ break;
+ }
+ printf(" (%d%% used)",((MONSTACKSIZE-i)*100)/MONSTACKSIZE);
+ }
+ printf("\n");
+
+ /* Finally, check to make sure that the current stack pointer
+ * resides within the MonStack[] array...
+ */
+ if ((&stackval < MonStack) || (&stackval > &MonStack[MONSTACKSIZE/4]))
+ printf("WARNING: SP outside MonStack[]\n");
+}
+
+/* stkinit():
+ * This function should be called very early in uMon startup prior to
+ * the stack pointer being set to the end of MonStack[]. It
+ * simply initializes the MonStack[] array to a defined value so
+ * that the stack can be observed for fullness during runtime.
+ */
+void
+stkinit(void)
+{
+ extern ulong MonStack[];
+ volatile ulong *sp, *spend;
+
+ sp = (ulong *)MonStack;
+ spend = MonStack+MONSTACKSIZE/4;
+ while(sp < spend)
+ *sp++ = STACK_PREINIT_VAL;
+}
+
+/* writeprompt():
+ * Called to print out the monitor prompt. If the shell variable PROMPT
+ * exists, then use the content of that variable as a prompt; otherwise,
+ * just print uMON>.
+ */
+void
+writeprompt(void)
+{
+ char *prompt;
+
+ prompt = getenv("PROMPT");
+ if (!prompt)
+ prompt = "uMON>";
+ else if (strcmp(prompt,"NULL") == 0)
+ return;
+
+ putstr(prompt);
+}
+
+/* CommandLoop():
+ * This function is called at the end of monitor initialization.
+ * The monitor spends most of its time here, waiting for incoming
+ * characters on the console interface.
+ */
+void
+CommandLoop(void)
+{
+ static char cmdline[CMDLINESIZE];
+
+ while(1) {
+ stkchk("Cmdloop"); /* Verify valid monitor stack */
+ writeprompt(); /* Issue prompt */
+ memset(cmdline,0,CMDLINESIZE); /* Clear command line buffer */
+ if (getline(cmdline,CMDLINESIZE,INCLUDE_LINEEDIT) == 0)
+ continue;
+ docommand(cmdline,0);
+#if INCLUDE_FLASH
+ LowerFlashProtectWindow();
+#endif
+ }
+}
+
+int monitorFlags;
+
+struct monflag monflagtbl[] = {
+ { NOMONHEADER, "nophdr" }, /* Don't print header at startup */
+ { NODEFRAGPRN, "nopdf" }, /* Don't print defrag msg in tfsclean */
+ { NOTFTPPRN, "noptftp" }, /* Don't print for tftp RRQ or WRQ */
+ { NOMONCMDPRN, "nopmcmd" }, /* Don't print for incoming moncmd */
+ { NOTFTPOVW, "notftpovw" }, /* Don't allow TFTP srvr to overwrite */
+ { NOEXITSTATUS, "noexitstat" }, /* Don't ptint app exit status */
+ { 0,0 }
+};
+
+/* InitMonitorFlags():
+ * If the shell variable MONFLAGS exists, then use the content of that
+ * variable to populate the value monitorFlags. The syntax of the shell
+ * variable is "xxx:yyyy:zzzz:abcd" where xxx,yyyy,zzzz and abcd are
+ * strings from the monflagtbl that represent some bit in the long that
+ * is to be set.
+ */
+void
+InitMonitorFlags(void)
+{
+ char *mf, *colon;
+ struct monflag *mfp;
+
+ monitorFlags = 0;
+
+ mf = getenv("MONFLAGS");
+ if (!mf)
+ return;
+
+ while(1) {
+ colon = strchr(mf,':');
+ if (colon)
+ *colon = 0;
+ mfp = monflagtbl;
+ while(mfp->flagname) {
+ if (!strcmp(mf,mfp->flagname)) {
+ monitorFlags |= mfp->bit;
+ break;
+ }
+ mfp++;
+ }
+ if (!mfp->flagname)
+ printf("MONFLAGS err: %s\n",mf);
+ if (colon)
+ *colon = ':';
+ else
+ break;
+ mf = colon+1;
+ }
+}
+
+/* exceptionAutoRestart():
+ * Serves three purposes:
+ * 1. Copies the verbose description of the exception to the
+ * shell variable EXCEPTION_TYPE.
+ * 2. If there is an EXCEPTION_SCRIPT shell variable, then see if the
+ * user wants it to be executed.
+ * 3. If there is no NO_EXCEPTION_RESTART variable, then
+ * call monrestart with the incoming value (usually INITIALIZE).
+ */
+void
+exceptionAutoRestart(int restartvalue)
+{
+ char *script;
+ char *arglist[2];
+
+ setenv("EXCEPTION_TYPE",ExceptionType2String(ExceptionType));
+ script = getenv("EXCEPTION_SCRIPT");
+ if ((script) &&
+ (!pollConsole("Press any key to stop exception script.\n"))) {
+ arglist[0] = script;
+ arglist[1] = (char *)0;
+ tfsrun(arglist,0);
+ }
+
+ if (!getenv("NO_EXCEPTION_RESTART")) {
+ if (!pollConsole("Press any key to stop auto restart.\n"))
+ monrestart(restartvalue);
+ }
+}
+
+/* getAppRamStart():
+ * First looks for the content of APPRAMBASE shell variable;
+ * if present, that string is converted to a long and returned,
+ * else the value of APPLICATION_RAMSTART is returned.
+ */
+ulong
+getAppRamStart(void)
+{
+ char *apprambase;
+ ulong value;
+
+ apprambase = getenv("APPRAMBASE");
+ if (apprambase)
+ value = strtoul(apprambase,0,0);
+ else
+ value = APPLICATION_RAMSTART;
+ return(value);
+}
+
+/* uMonInRam():
+ * This function returns 1 if the image of the running monitor is
+ * in RAM; else 0. The function ramtstfunc() should NEVER be called.
+ * It is used as a test to determine if text space is writeable.
+ * If it is, then we assume that uMon is running from RAM.
+ */
+static int
+ramtstfunc(void)
+{
+ return(99);
+}
+
+int
+uMonInRam(void)
+{
+ int rc;
+ volatile unsigned char origvalue;
+ volatile unsigned char *testmem = (unsigned char *)&ramtstfunc;
+
+ origvalue = *testmem;
+ *testmem = ~origvalue;
+
+ /* Flush d-cache here to make sure that the write & readback actually
+ * interact with external memory and not just d-cache...
+ */
+ flushDcache((char *)testmem,1);
+
+ if (*testmem == (unsigned char)~origvalue)
+ rc = 1;
+ else
+ rc = 0;
+
+ *testmem = origvalue;
+ return(rc);
+}
+
+/* inUmonBssSpace()
+ * Return 1 if the address range falls within MicroMonitor's
+ * own RAM space.
+ */
+int
+inUmonBssSpace(char *start,char *end)
+{
+ static int nowarn;
+
+ if (nowarn || getenv("NO_UMONBSS_WARNING")) {
+ nowarn = 1;
+ return(0);
+ }
+
+ if (((start >= (char *)&bss_start) && (start < (char *)&bss_end)) ||
+ ((end >= (char *)&bss_start) && (end < (char *)&bss_end)) ||
+ ((start <= (char *)&bss_start) && (end >= (char *)&bss_end))) {
+ printf("\nError: addr range 0x%lx <-> 0x%lx violates uMon ram.\n",
+ (long)start,(long)end);
+ return(1);
+ }
+
+ return(0);
+}
+
+void
+monrestart(int val)
+{
+ /* Allow UART0 transmit FIFO to empty...
+ */
+ flush_console_out();
+ intsoff();
+ warmstart(val);
+}
+
+void
+appexit(int val)
+{
+ AppExitStatus = val;
+ monrestart(APP_EXIT);
+}
+
+/* monWatchDog():
+ * This function is hooked to the monitor API so that the application
+ * can use the same function used by monitor code for exciting the
+ * watchdog hardware.
+ * Note that if there is no defined WATCHDOG_MACRO, then this function
+ * returns -1; else it executes the macro and returns 0. This
+ * return value can be used by the application to decide whether or
+ * not the call to mon_watchdog() even needs to occur.
+ */
+int
+monWatchDog(void)
+{
+#ifdef WATCHDOG_ENABLED
+ WATCHDOG_MACRO;
+ return(0);
+#else
+ return(-1);
+#endif
+}
+
+#if INCLUDE_SHELLVARS
+
+/* putargv() & getargv():
+ * The getargv() function provides a hook allowing the downloaded
+ * application code to handle main(argc,argv) in a painless way.
+ * The Argv[] array location is returned by mon_getargv() and is
+ * assumed to contain the NULL terminated list of argv pointers...
+ * Immediately after the NULL termination is the data that the argv
+ * pointers are referencing.
+ *
+ * MONLIB NOTICE: getargv() is accessible through monlib.c.
+ */
+
+/* ArgvList:
+ * Used by the code that is behind the mon_getargv() API.
+ */
+static char *ArgvList[32];
+
+int
+putargv(int argnum,char *argptr)
+{
+ int i;
+ char buf[8];
+
+ if (argnum >= (sizeof(ArgvList)/sizeof(char *)))
+ return(-1);
+
+ if (argnum == 0) {
+ for(i=0;i<(sizeof(ArgvList)/sizeof(char *));i++) {
+ sprintf(buf,"ARG%d",i);
+ setenv(buf,0);
+ }
+ setenv("ARGC",0);
+ ArgvList[0] = (char *)0;
+ }
+
+ ArgvList[argnum] = argptr;
+
+ if (argptr) {
+ sprintf(buf,"ARG%d",argnum);
+ setenv(buf,ArgvList[argnum]);
+ }
+ else {
+ shell_sprintf("ARGC","%d",argnum);
+ }
+
+ return(0);
+}
+
+void
+getargv(int *argc,char ***argv)
+{
+ int i;
+
+ if (argv)
+ *argv = &ArgvList[0];
+ for(i=0;;i++)
+ if (ArgvList[i] == 0)
+ break;
+ if (argc)
+ *argc = i;
+}
+
+#endif
diff --git a/main/common/misccmds.c b/main/common/misccmds.c
new file mode 100644
index 0000000..742f5fb
--- /dev/null
+++ b/main/common/misccmds.c
@@ -0,0 +1,578 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * misccmds:
+ *
+ * More monitor commands...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "ether.h"
+#include "devices.h"
+#include "cli.h"
+#include <ctype.h>
+#include "warmstart.h"
+
+
+char ApplicationInfo[82];
+int (*extgetUsrLvl)(void);
+
+#if INCLUDE_USRLVL
+static int setUsrLvl(int, char *);
+static int UserLevel;
+
+char *UlvlHelp[] = {
+ "Display or modify current user level.",
+ "-[c:hp] [new_level|min|max] [password]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -c{cmd,lvl}",
+ " set command's user level",
+ " -h dump system header",
+ " -p build new password file",
+ "",
+ " Note: cmd==ALL, applies action to all commands.",
+#endif
+ 0
+};
+
+int
+Ulvl(int argc,char *argv[])
+{
+ char passwd[32], *pwp;
+ int level, opt, newulvl;
+
+ newulvl = 0;
+ pwp = (char *)0;
+ level = MINUSRLEVEL;
+ while((opt=getopt(argc,argv,"c:hp")) != -1) {
+ switch(opt) {
+ case 'c':
+ setCmdUlvl(optarg,1);
+ newulvl++;
+ break;
+ case 'h':
+ monHeader(0);
+ break;
+ case 'p':
+ newPasswordFile();
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ /* At this point, the newulvl flag is used to indicate that the
+ * -c option was used. If it was, then we return here.
+ */
+ if (newulvl)
+ return(CMD_SUCCESS);
+
+ /* If there is one or two arguments on the command line, then
+ * the user must want to modify the current user level. If
+ * there are no arguments, then simply display the current
+ * user level.
+ *
+ * If the new user level is lower than the current user level,
+ * then the user can simply enter the new level (one argument).
+ * If the new user level is higher than the current user level,
+ * then the user must also enter a password. The password is
+ * entered either as the second argument or interactively
+ * using getpass().
+ */
+ newulvl = 0;
+ if ((argc == optind+1) || (argc == optind+2)) {
+ if (!strcmp(argv[optind],"min"))
+ level = MINUSRLEVEL;
+ else if (!strcmp(argv[optind],"max"))
+ level = MAXUSRLEVEL;
+ else
+ level = atoi(argv[optind]);
+
+ if (argc == optind+1) {
+ if (level > UserLevel) {
+ getpass("Password: ",passwd,sizeof(passwd)-1,0);
+ pwp = passwd;
+ }
+ }
+ else {
+ pwp = argv[optind+1];
+ }
+ newulvl = 1;
+ }
+ else if (argc != optind) {
+ return(CMD_PARAM_ERROR);
+ }
+
+ /* At this point,the newulvl flag is used to indicate that an
+ * adjustment to the current user level is to be made.
+ */
+ if (newulvl) {
+ if (level <= UserLevel)
+ UserLevel = level;
+ else
+ setUsrLvl(level,pwp);
+ }
+
+ if (extgetUsrLvl)
+ printf("User level controlled by application: %d\n",extgetUsrLvl());
+ else
+ printf("Current monitor user level: %d\n",UserLevel);
+ return(CMD_SUCCESS);
+}
+
+void
+initUsrLvl(int lvl)
+{
+ extgetUsrLvl = 0;
+ UserLevel = lvl;
+}
+
+/* getUsrLvl():
+ * This is the ONLY point of access for retrieval of the user level.
+ * This allows the application to redefine how the monitor retrieves
+ * what it thinks of as the user level.
+ */
+int
+getUsrLvl(void)
+{
+ if (extgetUsrLvl)
+ return(extgetUsrLvl());
+ return(UserLevel);
+}
+
+int
+setUsrLvl(int level, char *password)
+{
+ int olvl;
+
+ olvl = UserLevel;
+
+ /* If level is -1, then assume this is only a request for the current */
+ /* user level. If the incoming level is any other value outside the */
+ /* range of MINUSRLEVEL and MAXUSRLEVEL, return -1. */
+ if (level == -1)
+ return(UserLevel);
+ if ((level > MAXUSRLEVEL) || (level < MINUSRLEVEL))
+ return(olvl);
+
+ /* If password pointer is NULL, then don't check for password, just set */
+ /* the level and be done. */
+ if (!password) {
+ UserLevel = level;
+ }
+ else {
+ if (validPassword(password,level))
+ UserLevel = level;
+ }
+ return(olvl);
+}
+
+/* returnMaxUsrLvl(), setTmpMaxUsrLvl() & clrTmpMaxUsrLvl():
+ * These three functions are used to allow a few places in the monitor
+ * to temporarily force the user level to MAXUSRLEVEL. This is necessary
+ * for accessing the password file and the tfs log file.
+ * Call setTmpMaxUsrLvl() to enable MAX mode and then clrTmpMaxUsrLvl()
+ * with the value returned by setTmpMaxUsrLvl() when done.
+ */
+int
+returnMaxUsrLvl(void)
+{
+ return(MAXUSRLEVEL);
+}
+
+void *
+setTmpMaxUsrLvl(void)
+{
+ void *fptr;
+
+ fptr = (void *)extgetUsrLvl;
+ extgetUsrLvl = returnMaxUsrLvl;
+ return(fptr);
+}
+
+void
+clrTmpMaxUsrLvl(int (*fptr)(void))
+{
+ extgetUsrLvl = fptr;
+}
+
+#else
+
+int
+getUsrLvl(void)
+{
+ return(MAXUSRLEVEL);
+}
+
+#endif
+
+char *VersionHelp[] = {
+ "Version information",
+ "[application_info]",
+ 0,
+};
+
+int
+Version(int argc,char *argv[])
+{
+ extern void ShowVersion(void);
+
+ if (argc == 1)
+ ShowVersion();
+ else {
+ strncpy(ApplicationInfo,argv[1],80);
+ ApplicationInfo[80] = 0;
+ }
+ return(CMD_SUCCESS);
+}
+
+#if INCLUDE_TFSSCRIPT
+char *EchoHelp[] = {
+ "Print string to local terminal",
+ "[arg1] ... [argn]",
+#if INCLUDE_VERBOSEHELP
+ " Special meaning: \\b \\c \\r \\n \\t \\x",
+#endif
+ 0,
+};
+
+int
+Echo(int argc,char *argv[])
+{
+ int i, done;
+ char *cp, c, hex[3];
+
+ for(i=optind;i<argc;i++) {
+ cp = argv[i];
+ done = 0;
+ while(!done && *cp) {
+ if (*cp == '\\') {
+ cp++;
+ switch(*cp) {
+ case 'b': /* Backspace */
+ c = '\b';
+ break;
+ case 'c': /* No newline, just end here */
+ return(CMD_SUCCESS);
+ case 'n': /* Newline */
+ c = '\n';
+ break;
+ case 'r': /* Carriage Return */
+ c = '\r';
+ break;
+ case 't': /* Tab */
+ c = '\t';
+ break;
+ case 'x': /* Hex conversion */
+ cp++;
+ hex[0] = *cp++;
+ hex[1] = *cp;
+ hex[2] = 0;
+ c = strtol(hex,0,16);
+ break;
+ case '\\': /* Backslash */
+ c = '\\';
+ break;
+ default: /* Ignore backslash */
+ c = *cp;
+ break;
+ }
+ putchar(c);
+ }
+ else {
+ putchar(*cp);
+ }
+ if (cp)
+ cp++;
+ }
+ if (i != argc-1) {
+ putchar(' ');
+ }
+ }
+ putchar('\n');
+ flush_console_out();
+ return(CMD_SUCCESS);
+}
+#endif
+
+/* Call():
+ * This function is called when the user wants to execute an
+ * embedded function.
+ * The the argument is preceded by an ampersand, then a pointer
+ * to the argument is passed to the function instead of a
+ * strtol() conversion.
+ */
+char *CallHelp[] = {
+ "Call embedded function",
+ "-[Aaqv:] {address} [arg1] [arg2] ...",
+#if INCLUDE_VERBOSEHELP
+ " -a build (argc,argv) then call function",
+#if INCLUDE_SHELLVARS
+ " -A build arglist for use by mon_getargv()",
+#endif
+ " -q quiet mode",
+ " -v {var} put return val in varname",
+#endif
+ 0,
+};
+
+int
+Call(int argc,char *argv[])
+{
+ char *varname;
+ long args[10];
+ int i, j, ret, opt, useargc, quiet, monargs;
+ int (*func)(long,long,long,long,long,long,long,long,long,long);
+
+ quiet = 0;
+ useargc = 0;
+ monargs = 0;
+ varname = (char *)0;
+ while((opt=getopt(argc,argv,"Aaqv:")) != -1) {
+ switch(opt) {
+ case 'a':
+ useargc = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'v':
+ varname = optarg;
+ break;
+ case 'A':
+#if INCLUDE_SHELLVARS
+ monargs = 1;
+ break;
+#endif
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if ((argc < optind+1) || (argc > optind+11))
+ return(CMD_PARAM_ERROR);
+
+ func = (int(*)(long,long,long,long,long,long,long,long,long,long))
+ strtol(argv[optind],(char **)0,0);
+
+ if ((func == 0) && (isdigit(argv[optind][0]) == 0)) {
+ return(CMD_PARAM_ERROR);
+ }
+
+ /* If useargc flag is not set, then retrieve and convert
+ * args from command line. If the first character of the
+ * argument is an ampersand (&), then a pointer to the argument
+ * is passed; otherwise, the argument is converted to a long
+ * integer using strtol()...
+ */
+ if (!useargc) {
+ for(j=0,i=optind+1;i<argc;i++,j++) {
+ if (argv[i][0] == '&')
+ args[j] = (ulong)&argv[i][1];
+ else
+ args[j] = strtol(argv[i],(char **)0,0);
+ }
+ }
+
+#if INCLUDE_SHELLVARS
+ if (monargs) {
+ for(j=0,i=optind;i<argc;i++,j++)
+ putargv(j,argv[i]);
+ putargv(j,(char *)0);
+ }
+#endif
+
+ if (useargc) {
+ ret = func(argc-optind,(long)&argv[optind],0,0,0,0,0,0,0,0);
+ }
+ else {
+ ret = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],
+ args[7],args[8],args[9]);
+ }
+
+ if (varname)
+ shell_sprintf(varname,"0x%x",ret);
+
+ if (!quiet)
+ printf("Returned: %d (0x%x)\n",ret,ret);
+
+ return(CMD_SUCCESS);
+}
+
+/* Reset():
+ * Used to re-initialize the monitor through the command interface.
+ */
+
+char *ResetHelp[] = {
+ "Reset monitor firmware",
+ "-[xt:]",
+#if INCLUDE_VERBOSEHELP
+ " -x app_exit",
+ " -t ## warmstart type",
+#endif
+ 0,
+};
+
+int
+Reset(int argc,char *argv[])
+{
+ extern void appexit(int);
+ int opt;
+
+ intsoff();
+
+ /* For some systems, the reset occurs while characters are in the
+ * UART FIFO (so they don't get printed). Adding this delay will
+ * hopefully allow the characters in the FIFO to drain...
+ */
+ monDelay(250);
+
+ while((opt=getopt(argc,argv,"xt:")) != -1) {
+ switch(opt) {
+ case 'x':
+ appexit(0);
+ break;
+ case 't':
+ monrestart((int)strtol(optarg,0,0));
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ target_reset();
+ return(CMD_SUCCESS);
+}
+
+#if INCLUDE_TFS
+/* WhatCmd():
+ * Used to search through a binary file displaying any "WHAT" strings
+ * that may be present...
+ *
+ * Just what is "what"?
+ * This is a tool that simply prints all strings found that start with
+ * "@(#)" in an input file. This is called a "what string". It is useful
+ * for storage of retrievable information from a binary file.
+ */
+
+#define WHATSEARCH 1
+#define WHATMATCH 2
+
+char *WhatHelp[] = {
+ "Search file for 'what' strings; put last result in 'WHATSTRING' shell var",
+ "[-t:v] {filename}",
+#if INCLUDE_VERBOSEHELP
+ " -t{tok} match on what-string with subtoken",
+ " -v verbose",
+#endif
+ 0,
+};
+
+
+int
+WhatCmd(int argc,char **argv)
+{
+ TFILE *tfp;
+ int opt, state, verbose, idx;
+ char whatbuf[64], *whattok, *varname;
+ char *ifile, *buf, *end, *bp, *whatstring, *wsp;
+
+ whattok = 0;
+ whatstring = "@(#)";
+ idx = verbose = 0;
+ varname = "WHATSTRING";
+ while((opt=getopt(argc,argv,"t:v")) != -1) {
+ switch(opt) {
+ case 'v':
+ verbose++;
+ break;
+ case 't':
+ whattok = optarg;
+ break;
+ default:
+ return(CMD_FAILURE);
+ }
+ }
+ if (argc-optind != 1)
+ return(CMD_PARAM_ERROR);
+
+ ifile = argv[optind];
+
+ /* Open input file: */
+ if ((tfp = tfsstat(ifile)) == (TFILE *)0) {
+ printf("Can't find file: %s\n",ifile);
+ return(CMD_FAILURE);
+ }
+ bp = buf = TFS_BASE(tfp);
+ end = buf + TFS_SIZE(tfp);
+
+ state = WHATSEARCH;
+ wsp = whatstring;
+ setenv(varname,0);
+ while(bp < end) {
+ switch(state) {
+ case WHATSEARCH:
+ if (*bp == *wsp) {
+ wsp++;
+ if (*wsp == 0) {
+ wsp = whatstring;
+ state = WHATMATCH;
+ idx = 0;
+ if (verbose)
+ putchar('\t');
+ }
+ }
+ else
+ wsp = whatstring;
+ break;
+ case WHATMATCH:
+ if (isprint(*bp)) {
+ if (verbose)
+ putchar(*bp);
+ if (idx < sizeof(whatbuf)-1)
+ whatbuf[idx++] = *bp;
+ }
+ else {
+ if (verbose)
+ putchar('\n');
+ if (idx < sizeof(whatbuf))
+ whatbuf[idx] = 0;
+ if (whattok) {
+ if (strstr(whatbuf,whattok))
+ setenv(varname,whatbuf);
+ }
+ else
+ setenv(varname,whatbuf);
+
+ state = WHATSEARCH;
+ }
+ break;
+ }
+ bp++;
+ }
+ return(0);
+}
+#endif
diff --git a/main/common/monbuilt.c b/main/common/monbuilt.c
new file mode 100644
index 0000000..e4f1951
--- /dev/null
+++ b/main/common/monbuilt.c
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monbuilt.c:
+ *
+ * This file contains all of the monitor code that constructs
+ * the time and date of the build.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+/* whatbuild:
+ * A 'what' string to allow the 'what' tool to query the binary
+ * image built with this source code.
+ */
+#define WHAT_PREFIX "@(#)"
+
+char *whatbuild = WHAT_PREFIX __DATE__ " @ " __TIME__;
+
+/* monBuilt():
+ * Return a pointer to a string that is a concatenation of the
+ * build date and build time.
+ */
+
+char *
+monBuilt(void)
+{
+ return(whatbuild+sizeof(WHAT_PREFIX)-1);
+}
diff --git a/main/common/moncom.c b/main/common/moncom.c
new file mode 100644
index 0000000..319d884
--- /dev/null
+++ b/main/common/moncom.c
@@ -0,0 +1,427 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * moncom.c:
+ *
+ * This function is used by the application to interface to code that
+ * is part of the monitor. A pointer to this function exists at some
+ * "well-known" address in the monitors space. This location must be
+ * known by the application (hence... "well-known").
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "monlib.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "monflags.h"
+#include "pci.h"
+#include "i2c.h"
+#include "ether.h"
+#include "flash.h"
+#include "date.h"
+#include "timer.h"
+
+extern int addcommand(struct monCommand *cmdlist, char *cmdlvl);
+extern int profiler(void *);
+static int moncom_pcnt;
+
+int monErrorStub(void);
+
+int
+moncom(int cmd, void *arg1, void *arg2, void *arg3)
+{
+ int retval;
+
+ /* eliminate warnings due to arg2 & arg3 not being used...
+ */
+ if (arg2 == arg3)
+ retval = 0;
+ else
+ retval = 0;
+
+ switch(cmd) {
+ case GETMONFUNC_PUTCHAR:
+ *(unsigned long *)arg1 = (unsigned long)putchar;
+ break;
+ case GETMONFUNC_GETCHAR:
+ *(unsigned long *)arg1 = (unsigned long)getchar;
+ break;
+ case GETMONFUNC_GOTACHAR:
+ *(unsigned long *)arg1 = (unsigned long)gotachar;
+ break;
+ case GETMONFUNC_GETBYTES:
+ *(unsigned long *)arg1 = (unsigned long)getbytes;
+ break;
+ case GETMONFUNC_PRINTF:
+ *(unsigned long *)arg1 = (unsigned long)printf;
+ break;
+ case GETMONFUNC_CPRINTF:
+ *(unsigned long *)arg1 = (unsigned long)cprintf;
+ break;
+ case GETMONFUNC_SPRINTF:
+ *(unsigned long *)arg1 = (unsigned long)sprintf;
+ break;
+ case GETMONFUNC_RESTART:
+ *(unsigned long *)arg1 = (unsigned long)monrestart;
+ break;
+ case GETMONFUNC_GETENV:
+ *(unsigned long *)arg1 = (unsigned long)getenv;
+ break;
+ case GETMONFUNC_SETENV:
+ *(unsigned long *)arg1 = (unsigned long)setenv;
+ break;
+
+#if !INCLUDE_TFS
+ case GETMONFUNC_TFSINIT:
+ case GETMONFUNC_TFSADD:
+ case GETMONFUNC_TFSUNLINK:
+ case GETMONFUNC_TFSRUN:
+ case GETMONFUNC_TFSNEXT:
+ case GETMONFUNC_TFSFSTAT:
+ case GETMONFUNC_TFSTRUNCATE:
+ case GETMONFUNC_TFSEOF:
+ case GETMONFUNC_TFSSTAT:
+ case GETMONFUNC_TFSREAD:
+ case GETMONFUNC_TFSWRITE:
+ case GETMONFUNC_TFSOPEN:
+ case GETMONFUNC_TFSCLOSE:
+ case GETMONFUNC_TFSSEEK:
+ case GETMONFUNC_TFSGETLINE:
+ case GETMONFUNC_TFSIPMOD:
+ case GETMONFUNC_TFSCTRL:
+ case GETMONFUNC_TFSLINK:
+ case GETMONFUNC_TFSTELL:
+#endif
+#if !INCLUDE_UNZIP
+ case GETMONFUNC_DECOMPRESS:
+#endif
+#if !INCLUDE_MALLOC
+ case GETMONFUNC_MALLOC:
+ case GETMONFUNC_FREE:
+ case GETMONFUNC_HEAPXTEND:
+#endif
+#if !INCLUDE_PROFILER
+ case GETMONFUNC_PROFILER:
+#endif
+#if !INCLUDE_BBC
+ case GETMONFUNC_BBC:
+#endif
+#if !INCLUDE_MEMTRACE
+ case GETMONFUNC_MEMTRACE:
+#endif
+#if !INCLUDE_ETHERNET
+ case GETMONFUNC_SENDENETPKT:
+ case GETMONFUNC_RECVENETPKT:
+#endif
+#if !INCLUDE_ETHERVERBOSE
+ case GETMONFUNC_PRINTPKT:
+#endif
+#if !INCLUDE_FLASH
+ case GETMONFUNC_FLASHWRITE:
+ case GETMONFUNC_FLASHERASE:
+ case GETMONFUNC_FLASHINFO:
+ case GETMONFUNC_FLASHOVRRD:
+#endif
+#if !INCLUDE_PORTCMD
+ case GETMONFUNC_PORTCMD:
+#endif
+#ifndef ALLOW_HANDLER_ASSIGNMENT
+ case GETMONFUNC_ASSIGNHDLR:
+#endif
+#ifndef NO_MONLIB_PCI_STUBS
+ case GETMONFUNC_PCICFGREAD:
+ case GETMONFUNC_PCICFGWRITE:
+ case GETMONFUNC_PCICONTROL:
+#endif
+#ifndef NO_MONLIB_I2C_STUBS
+ case GETMONFUNC_I2CWRITE:
+ case GETMONFUNC_I2CREAD:
+ case GETMONFUNC_I2CCONTROL:
+#endif
+#if !INCLUDE_TIMEOFDAY
+ case GETMONFUNC_TIMEOFDAY:
+#endif
+#if !INCLUDE_SHELLVARS
+ case GETMONFUNC_GETARGV:
+#endif
+ case GETMONFUNC_PIOGET: /* As of uMon 1.0, these are */
+ case GETMONFUNC_PIOSET: /* no longer supported. */
+ case GETMONFUNC_PIOCLR:
+ *(unsigned long *)arg1 = (unsigned long)monErrorStub;
+ break;
+
+#if INCLUDE_TFS
+ case GETMONFUNC_TFSINIT:
+ *(unsigned long *)arg1 = (unsigned long)tfsinit;
+ break;
+ case GETMONFUNC_TFSADD:
+ *(unsigned long *)arg1 = (unsigned long)tfsadd;
+ break;
+ case GETMONFUNC_TFSUNLINK:
+ *(unsigned long *)arg1 = (unsigned long)tfsunlink;
+ break;
+ case GETMONFUNC_TFSRUN:
+ *(unsigned long *)arg1 = (unsigned long)tfsrun;
+ break;
+ case GETMONFUNC_TFSNEXT:
+ *(unsigned long *)arg1 = (unsigned long)tfsnext;
+ break;
+ case GETMONFUNC_TFSFSTAT:
+ *(unsigned long *)arg1 = (unsigned long)tfsfstat;
+ break;
+ case GETMONFUNC_TFSTRUNCATE:
+ *(unsigned long *)arg1 = (unsigned long)tfstruncate;
+ break;
+ case GETMONFUNC_TFSEOF:
+ *(unsigned long *)arg1 = (unsigned long)tfseof;
+ break;
+ case GETMONFUNC_TFSSTAT:
+ *(unsigned long *)arg1 = (unsigned long)tfsstat;
+ break;
+ case GETMONFUNC_TFSREAD:
+ *(unsigned long *)arg1 = (unsigned long)tfsread;
+ break;
+ case GETMONFUNC_TFSWRITE:
+ *(unsigned long *)arg1 = (unsigned long)tfswrite;
+ break;
+ case GETMONFUNC_TFSOPEN:
+ *(unsigned long *)arg1 = (unsigned long)tfsopen;
+ break;
+ case GETMONFUNC_TFSCLOSE:
+ *(unsigned long *)arg1 = (unsigned long)tfsclose;
+ break;
+ case GETMONFUNC_TFSSEEK:
+ *(unsigned long *)arg1 = (unsigned long)tfsseek;
+ break;
+ case GETMONFUNC_TFSGETLINE:
+ *(unsigned long *)arg1 = (unsigned long)tfsgetline;
+ break;
+ case GETMONFUNC_TFSIPMOD:
+ *(unsigned long *)arg1 = (unsigned long)tfsipmod;
+ break;
+ case GETMONFUNC_TFSCTRL:
+ *(unsigned long *)arg1 = (unsigned long)tfsctrl;
+ break;
+ case GETMONFUNC_TFSLINK:
+ *(unsigned long *)arg1 = (unsigned long)tfslink;
+ break;
+ case GETMONFUNC_TFSTELL:
+ *(unsigned long *)arg1 = (unsigned long)tfstell;
+ break;
+#endif
+#if INCLUDE_UNZIP
+ case GETMONFUNC_DECOMPRESS:
+ *(unsigned long *)arg1 = (unsigned long)decompress;
+ break;
+#endif
+#if INCLUDE_MALLOC
+ case GETMONFUNC_MALLOC:
+ *(unsigned long *)arg1 = (unsigned long)malloc;
+ break;
+ case GETMONFUNC_FREE:
+ *(unsigned long *)arg1 = (unsigned long)free;
+ break;
+ case GETMONFUNC_HEAPXTEND:
+ *(unsigned long *)arg1 = (unsigned long)extendHeap;
+ break;
+#endif
+#if INCLUDE_PROFILER
+ case GETMONFUNC_PROFILER:
+ *(unsigned long *)arg1 = (unsigned long)profiler;
+ break;
+#endif
+#if INCLUDE_BBC
+ case GETMONFUNC_BBC:
+ *(unsigned long *)arg1 = (unsigned long)bbc;
+ break;
+#endif
+#if INCLUDE_MEMTRACE
+ case GETMONFUNC_MEMTRACE:
+ *(unsigned long *)arg1 = (unsigned long)Mtrace;
+ break;
+#endif
+#if INCLUDE_ETHERNET
+ case GETMONFUNC_SENDENETPKT:
+ *(unsigned long *)arg1 = (unsigned long)monSendEnetPkt;
+ break;
+ case GETMONFUNC_RECVENETPKT:
+ *(unsigned long *)arg1 = (unsigned long)monRecvEnetPkt;
+ break;
+#endif
+#if INCLUDE_ETHERVERBOSE
+ case GETMONFUNC_PRINTPKT:
+ *(unsigned long *)arg1 = (unsigned long)AppPrintPkt;
+ break;
+#endif
+#if INCLUDE_FLASH
+ case GETMONFUNC_FLASHOVRRD:
+ *(unsigned long *)arg1 = (unsigned long)FlashOpOverride;
+ break;
+ case GETMONFUNC_FLASHWRITE:
+ *(unsigned long *)arg1 = (unsigned long)AppFlashWrite;
+ break;
+ case GETMONFUNC_FLASHERASE:
+ *(unsigned long *)arg1 = (unsigned long)AppFlashErase;
+ break;
+ case GETMONFUNC_FLASHINFO:
+ *(unsigned long *)arg1 = (unsigned long)sectortoaddr;
+ break;
+#endif
+#if INCLUDE_PORTCMD
+ case GETMONFUNC_PORTCMD:
+ *(unsigned long *)arg1 = (unsigned long)portCmd;
+ break;
+#endif
+#ifdef ALLOW_HANDLER_ASSIGNMENT
+ case GETMONFUNC_ASSIGNHDLR:
+ *(unsigned long *)arg1 = (unsigned long)assign_handler;
+ break;
+#endif
+#ifdef NO_MONLIB_I2C_STUBS
+ case GETMONFUNC_I2CWRITE:
+ *(unsigned long *)arg1 = (unsigned long)i2cWrite;
+ break;
+ case GETMONFUNC_I2CREAD:
+ *(unsigned long *)arg1 = (unsigned long)i2cRead;
+ break;
+ case GETMONFUNC_I2CCONTROL:
+ *(unsigned long *)arg1 = (unsigned long)i2cCtrl;
+ break;
+#endif
+#ifdef NO_MONLIB_PCI_STUBS
+ case GETMONFUNC_PCICFGREAD:
+ *(unsigned long *)arg1 = (unsigned long)pciCfgRead;
+ break;
+ case GETMONFUNC_PCICFGWRITE:
+ *(unsigned long *)arg1 = (unsigned long)pciCfgWrite;
+ break;
+ case GETMONFUNC_PCICONTROL:
+ *(unsigned long *)arg1 = (unsigned long)pciCtrl;
+ break;
+#endif
+#if INCLUDE_TIMEOFDAY
+ case GETMONFUNC_TIMEOFDAY:
+ *(unsigned long *)arg1 = (unsigned long)timeofday;
+ break;
+#endif
+#if INCLUDE_SHELLVARS
+ case GETMONFUNC_GETARGV:
+ *(unsigned long *)arg1 = (unsigned long)getargv;
+ break;
+#endif
+ case GETMONFUNC_ADDCOMMAND:
+ *(unsigned long *)arg1 = (unsigned long)addcommand;
+ break;
+ case GETMONFUNC_DOCOMMAND:
+ *(unsigned long *)arg1 = (unsigned long)docommand;
+ break;
+ case GETMONFUNC_CRC16:
+ *(unsigned long *)arg1 = (unsigned long)xcrc16;
+ break;
+ case GETMONFUNC_CRC32:
+ *(unsigned long *)arg1 = (unsigned long)crc32;
+ break;
+ case GETMONFUNC_INTSOFF:
+ *(unsigned long *)arg1 = (unsigned long)intsoff;
+ break;
+ case GETMONFUNC_INTSRESTORE:
+ *(unsigned long *)arg1 = (unsigned long)intsrestore;
+ break;
+ case GETMONFUNC_APPEXIT:
+ *(unsigned long *)arg1 = (unsigned long)appexit;
+ break;
+ case GETMONFUNC_GETLINE:
+ *(unsigned long *)arg1 = (unsigned long)getline;
+ break;
+ case GETMONFUNC_VERSION:
+ *(unsigned long *)arg1 = (unsigned long)monVersion;
+ break;
+ case GETMONFUNC_WARMSTART:
+ *(unsigned long *)arg1 = (unsigned long)AppWarmStart;
+ break;
+ case GETMONFUNC_MONDELAY:
+ *(unsigned long *)arg1 = (unsigned long)monDelay;
+ break;
+ case GETMONFUNC_GETENVP:
+ *(unsigned long *)arg1 = (unsigned long)getenvp;
+ break;
+ case GETMONFUNC_REALLOC:
+ *(unsigned long *)arg1 = (unsigned long)realloc;
+ break;
+ case GETMONFUNC_GETSYM:
+ *(unsigned long *)arg1 = (unsigned long)getsym;
+ break;
+ case GETMONFUNC_WATCHDOG:
+ *(unsigned long *)arg1 = (unsigned long)monWatchDog;
+ break;
+ case GETMONFUNC_PRINTMEM:
+ *(unsigned long *)arg1 = (unsigned long)printMem;
+ break;
+ case GETMONFUNC_TIMER:
+ *(unsigned long *)arg1 = (unsigned long)monTimer;
+ break;
+ case CACHEFTYPE_DFLUSH:
+ dcacheFlush = (int(*)(char *,int))arg1;
+ break;
+ case CACHEFTYPE_IINVALIDATE:
+ icacheInvalidate = (int(*)(char *,int))arg1;
+ break;
+ case CHARFUNC_PUTCHAR:
+ remoteputchar = (int(*)(int))arg1;
+ break;
+ case CHARFUNC_GETCHAR:
+ remotegetchar = (int(*)(void))arg1;
+ break;
+ case CHARFUNC_GOTACHAR:
+ remotegotachar = (int(*)(void))arg1;
+ break;
+ case CHARFUNC_RAWMODEON:
+ remoterawon = (int(*)(void))arg1;
+ break;
+ case CHARFUNC_RAWMODEOFF:
+ remoterawoff = (int(*)(void))arg1;
+ break;
+ case ASSIGNFUNC_GETUSERLEVEL:
+ extgetUsrLvl = (int(*)(void))arg1;
+ break;
+#ifdef WATCHDOG_ENABLED
+ case ASSIGNFUNC_WATCHDOG:
+ remoteWatchDog = (int(*)(void))arg1;
+ break;
+#endif
+ default:
+ printf("moncom unknown command: 0x%x\n",cmd);
+ retval = -1;
+ break;
+ }
+ moncom_pcnt++;
+ return(retval);
+}
+
+int
+monErrorStub(void)
+{
+ printf("ERROR: Facility not included in monitor build\n");
+ return(-1);
+}
diff --git a/main/common/moncomptr.S b/main/common/moncomptr.S
new file mode 100644
index 0000000..3ad94dd
--- /dev/null
+++ b/main/common/moncomptr.S
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * moncomptr.S:
+ *
+ * The tag moncomptr is a tag established at a point in the target's
+ * memory map that is unlikely to change as a result of rebuilding the
+ * monitor. As a result, this file is included by most of the target
+ * ports in the very beginning of the reset space.
+ *
+ * The address of moncom (moncomptr) is used by the monConnect()
+ * function in application space when the application attempts to
+ * connect to the monitor's API.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+ .extern moncom
+ .global moncomptr
+
+moncomptr:
+ .long moncom
diff --git a/main/common/monflags.h b/main/common/monflags.h
new file mode 100644
index 0000000..d4260ea
--- /dev/null
+++ b/main/common/monflags.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monflags.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _MONFLAGS_H_
+#define _MONFLAGS_H_
+
+struct monflag {
+ unsigned long bit;
+ char *flagname;
+};
+
+extern int monitorFlags;
+
+#define NOMONHEADER (1 << 0) /* Don't print header at startup */
+#define NODEFRAGPRN (1 << 1) /* Don't print defrag message */
+#define NOTFTPPRN (1 << 2) /* Don't print tftp message */
+#define NOMONCMDPRN (1 << 3) /* Don't print MONCMD message */
+#define NOTFTPOVW (1 << 4) /* Don't allow tftp srvr to overwrite */
+ /* an existing file. */
+#define MONCOMVERBOSE (1 << 5) /* The moncom() function will print */
+ /* status. */
+#define NOEXITSTATUS (1 << 6) /* Don't print app exit status. */
+
+#define MFLAGS_NOMONHEADER() (monitorFlags & NOMONHEADER)
+#define MFLAGS_NODEFRAGPRN() (monitorFlags & NODEFRAGPRN)
+#define MFLAGS_NOTFTPPRN() (monitorFlags & NOTFTPPRN)
+#define MFLAGS_NOMONCMDPRN() (monitorFlags & NOMONCMDPRN)
+#define MFLAGS_NOTFTPOVW() (monitorFlags & NOTFTPOVW)
+#define MFLAGS_MONCOMVERBOSE() (monitorFlags & MONCOMVERBOSE)
+#define MFLAGS_NOEXITSTATUS() (monitorFlags & NOEXITSTATUS)
+
+extern void InitMonitorFlags(void);
+
+#endif
diff --git a/main/common/monlib.c b/main/common/monlib.c
new file mode 100644
index 0000000..40204af
--- /dev/null
+++ b/main/common/monlib.c
@@ -0,0 +1,1133 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monlib.c:
+ *
+ * This file is part of the monitor code, but it is actually linked into
+ * the application. It is built with (but not linked with) the monitor,
+ * then the monlib.o file is linked with the application.
+ * The only requirement on the application is that it know where the address
+ * of the monCom function is in the monitor's space.
+ * The monCom function will be accessible in some "well-known" way (processor
+ * and platform dependent) so that this will not be a problem.
+ *
+ * This monlib.c file is a replacement for the older mechanism that was
+ * a bit more error-prone... A table of function pointers existed at some
+ * well-known location in the monitor, and the content of that table was
+ * assumed to also be "well-known". This new version only assumes that the
+ * pointer to monCom is well-known; everything else will work based on the
+ * fact that the monitor and application will share the monlib.h header
+ * file.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "monlib.h"
+
+static int (*_tfsseek)(int,int,int);
+static int (*_tfsgetline)(int,char *,int);
+static int (*_tfsipmod)(char *,char *,int,int);
+static int (*_tfsinit)(void);
+static int (*_tfsadd)(char *,char *,char *,unsigned char *,int);
+static int (*_tfsunlink)(char *);
+static int (*_tfsrun)(char **,int);
+static int (*_tfsread)(int,char *,int);
+static int (*_tfswrite)(int,char *,int);
+static int (*_tfsopen)(char *,long,char *);
+static int (*_tfsclose)(int,char *);
+static int (*_printf)();
+static int (*_cprintf)();
+static int (*_sprintf)();
+static int (*_monrestart)(int);
+static int (*_rputchar)(unsigned char c);
+static int (*_getchar)(void);
+static int (*_gotachar)(void);
+static int (*_getbytes)(char *,int,int);
+static int (*_addcommand)(struct monCommand *,char *);
+static int (*_docommand)(char *,int);
+static int (*_getline)(char *,int,int);
+static int (*_tfsfstat)(char *,struct tfshdr *);
+static int (*_tfseof)(int);
+static int (*_decompress)(char *,int,char *);
+static int (*_tfstruncate)(int,long);
+static int (*_heapextend)(char *,int);
+static int (*_tfslink)(char *,char *);
+static int (*_pcicfgwrite)(int,int,int,int,int,unsigned long);
+static int (*_i2cwrite)(int,int,unsigned char *,int);
+static int (*_i2cread)(int,int,unsigned char *,int);
+static int (*_flashwrite)(char *,char *,int);
+static int (*_flasherase)(int);
+static int (*_flashinfo)(int,int *,char **);
+static int (*_flashoverride)(void *,int,int);
+static int (*_sendenet)(char *,int);
+static int (*_recvenet)(char *,int);
+static int (*_printpkt)(char *,int,int);
+static int (*_setenv)(char *,char *);
+static int (*_watchdog)(void);
+static int (*_timeofday)(int,void *);
+static int (*_montimer)(int cmd, void *arg);
+
+static char *(*_getenv)(char *);
+static char *(*_version)(void);
+static char *(*_getenvp)(void);
+#ifdef MALLOC_DEBUG
+static char *(*_malloc)(int,char *,int);
+static char *(*_realloc)(char *buf,int,char *,int);
+#else
+static char *(*_malloc)(int);
+static char *(*_realloc)(char *,int);
+#endif
+static char *(*_getsym)(char *,char *,int);
+
+static void (*_intsrestore)(unsigned long);
+static void (*_appexit)(int);
+static void (*_free)(char *);
+static void (*_getargv)(int *,char ***);
+static void (*_profiler)(void *);
+static void (*_bbc)(char *,int);
+static void (*_memtrace)();
+static void (*_appwarmstart)(unsigned long);
+static void (*_mondelay)(long);
+static void (*_printmem)(char *,int,int);
+
+static long (*_tfsctrl)(int,long,long);
+static long (*_tfstell)(int);
+static long (*_portcmd)(int,void *);
+
+static struct tfshdr *(*_tfsnext)(struct tfshdr *);
+static struct tfshdr *(*_tfsstat)(char *);
+
+static unsigned long (*_i2cctrl)(int,int,unsigned long,unsigned long);
+static unsigned long (*_pcicfgread)(int,int,int,int,int);
+static unsigned long (*_pcictrl)(int,int,unsigned long,unsigned long);
+static unsigned long (*_crc32)(unsigned char *,unsigned long);
+static unsigned long (*_intsoff)(void);
+static unsigned long (*_assign_handler)(long,unsigned long,unsigned long);
+
+static unsigned short (*_xcrc16)(unsigned char *,unsigned long);
+
+
+static void (*_monlock)(void);
+static void (*_monunlock)(void);
+static int (*_moncom)(int,void *,void *, void *);
+
+/**************************************************************************
+ *
+ * The following macros support the default monitor lock/unlock mechanism when
+ * they point to monLock and monUnlock. If something other than the default
+ * is to be used, then simply redefine them here. Refer to the monitor
+ * app note that discusses multi-tasking access to the monitor API for more
+ * information.
+ *
+ * TFS_MONLOCK/UNLOCK:
+ * Lock/unlock for functions that access TFS flash space:
+ */
+#define TFS_MONLOCK monLock
+#define TFS_MONUNLOCK monUnlock
+
+/* ENV_MONLOCK/UNLOCK:
+ * Lock/unlock for functions that access monitor shell variables:
+ */
+#define ENV_MONLOCK monLock
+#define ENV_MONUNLOCK monUnlock
+
+/* CONSOLE_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that deal with console output.
+ */
+#define CONSOLE_MONLOCK monLock
+#define CONSOLE_MONUNLOCK monUnlock
+
+/* HEAP_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that deal with the heap.
+ */
+#define HEAP_MONLOCK monLock
+#define HEAP_MONUNLOCK monUnlock
+
+/* BLOCKING_MONLOCK/UNLOCK:
+ * Lock/unlock for functions in the monitor that block waiting for
+ * console input.
+ */
+#define BLOCKING_MONLOCK monLock
+#define BLOCKING_MONUNLOCK monUnlock
+
+/* GENERIC_MONLOCK/UNLOCK:
+ * Lock/unlock for all functions not covered by the above macros.
+ */
+#define GENERIC_MONLOCK monLock
+#define GENERIC_MONUNLOCK monUnlock
+
+/**************************************************************************
+ *
+ * monConnect():
+ * This must be the first call by the application code to talk to the
+ * monitor. It is expecting three incoming function pointers:
+ *
+ * mon: Points to the monitor's _moncom function;
+ * This is a "well-known" address because the monitor and
+ * application code (two separately linked binaries) must
+ * know it.
+ * lock: Points to a function in the application code that will be
+ * used by the monitor as a lock-out function (some kind of
+ * semaphore in the application).
+ * unlock: Points to a function in the application code that will be
+ * used by the monitor as an un-lock-out function (undo whatever
+ * lock-out mechanism was done by lock).
+ */
+int
+monConnect(int (*mon)(int,void *,void *,void *),
+ void (*lock)(void), void (*unlock)(void))
+{
+ int rc = 0;
+
+ /* Assign incoming lock and unlock functions... */
+ _monlock = lock;
+ _monunlock = unlock;
+
+ /* If the mon pointer is non-zero, then make the mon_ connections... */
+ if (mon) {
+
+ _moncom = mon;
+
+ /* Make the connections between "mon_" functions that are */
+ /* symbolically accessible by the application and the corresponding */
+ /* functions that exists in the monitor. */
+ rc += _moncom(GETMONFUNC_PUTCHAR,&_rputchar,0,0);
+ rc += _moncom(GETMONFUNC_GETCHAR,&_getchar,0,0);
+ rc += _moncom(GETMONFUNC_GOTACHAR,&_gotachar,0,0);
+ rc += _moncom(GETMONFUNC_GETBYTES,&_getbytes,0,0);
+ rc += _moncom(GETMONFUNC_PRINTF,&_printf,0,0);
+ rc += _moncom(GETMONFUNC_CPRINTF,&_cprintf,0,0);
+ rc += _moncom(GETMONFUNC_SPRINTF,&_sprintf,0,0);
+ rc += _moncom(GETMONFUNC_RESTART,&_monrestart,0,0);
+ rc += _moncom(GETMONFUNC_GETENV,&_getenv,0,0);
+ rc += _moncom(GETMONFUNC_SETENV,&_setenv,0,0);
+ rc += _moncom(GETMONFUNC_TFSINIT,&_tfsinit,0,0);
+ rc += _moncom(GETMONFUNC_TFSADD,&_tfsadd,0,0);
+ rc += _moncom(GETMONFUNC_TFSUNLINK,&_tfsunlink,0,0);
+ rc += _moncom(GETMONFUNC_TFSRUN,&_tfsrun,0,0);
+ rc += _moncom(GETMONFUNC_TFSNEXT,&_tfsnext,0,0);
+ rc += _moncom(GETMONFUNC_TFSSTAT,&_tfsstat,0,0);
+ rc += _moncom(GETMONFUNC_TFSREAD,&_tfsread,0,0);
+ rc += _moncom(GETMONFUNC_TFSWRITE,&_tfswrite,0,0);
+ rc += _moncom(GETMONFUNC_TFSOPEN,&_tfsopen,0,0);
+ rc += _moncom(GETMONFUNC_TFSCLOSE,&_tfsclose,0,0);
+ rc += _moncom(GETMONFUNC_TFSSEEK,&_tfsseek,0,0);
+ rc += _moncom(GETMONFUNC_TFSGETLINE,&_tfsgetline,0,0);
+ rc += _moncom(GETMONFUNC_TFSIPMOD,&_tfsipmod,0,0);
+ rc += _moncom(GETMONFUNC_TFSCTRL,&_tfsctrl,0,0);
+ rc += _moncom(GETMONFUNC_ADDCOMMAND,&_addcommand,0,0);
+ rc += _moncom(GETMONFUNC_DOCOMMAND,&_docommand,0,0);
+ rc += _moncom(GETMONFUNC_GETARGV,&_getargv,0,0);
+ rc += _moncom(GETMONFUNC_CRC16,&_xcrc16,0,0);
+ rc += _moncom(GETMONFUNC_CRC32,&_crc32,0,0);
+ rc += _moncom(GETMONFUNC_INTSOFF,&_intsoff,0,0);
+ rc += _moncom(GETMONFUNC_INTSRESTORE,&_intsrestore,0,0);
+ rc += _moncom(GETMONFUNC_APPEXIT,&_appexit,0,0);
+ rc += _moncom(GETMONFUNC_MALLOC,&_malloc,0,0);
+ rc += _moncom(GETMONFUNC_FREE,&_free,0,0);
+ rc += _moncom(GETMONFUNC_GETLINE,&_getline,0,0);
+ rc += _moncom(GETMONFUNC_TFSFSTAT,&_tfsfstat,0,0);
+ rc += _moncom(GETMONFUNC_TFSEOF,&_tfseof,0,0);
+ rc += _moncom(GETMONFUNC_DECOMPRESS,&_decompress,0,0);
+ rc += _moncom(GETMONFUNC_TFSTRUNCATE,&_tfstruncate,0,0);
+ rc += _moncom(GETMONFUNC_HEAPXTEND,&_heapextend,0,0);
+ rc += _moncom(GETMONFUNC_PROFILER,&_profiler,0,0);
+ rc += _moncom(GETMONFUNC_TFSLINK,&_tfslink,0,0);
+ rc += _moncom(GETMONFUNC_BBC,&_bbc,0,0);
+ rc += _moncom(GETMONFUNC_MEMTRACE,&_memtrace,0,0);
+ rc += _moncom(GETMONFUNC_TFSTELL,&_tfstell,0,0);
+ rc += _moncom(GETMONFUNC_VERSION,&_version,0,0);
+ rc += _moncom(GETMONFUNC_WARMSTART,&_appwarmstart,0,0);
+ rc += _moncom(GETMONFUNC_PCICFGREAD,&_pcicfgread,0,0);
+ rc += _moncom(GETMONFUNC_PCICFGWRITE,&_pcicfgwrite,0,0);
+ rc += _moncom(GETMONFUNC_PCICONTROL,&_pcictrl,0,0);
+ rc += _moncom(GETMONFUNC_I2CREAD,&_i2cread,0,0);
+ rc += _moncom(GETMONFUNC_I2CWRITE,&_i2cwrite,0,0);
+ rc += _moncom(GETMONFUNC_I2CCONTROL,&_i2cctrl,0,0);
+ rc += _moncom(GETMONFUNC_MONDELAY,&_mondelay,0,0);
+ rc += _moncom(GETMONFUNC_GETENVP,&_getenvp,0,0);
+ rc += _moncom(GETMONFUNC_REALLOC,&_realloc,0,0);
+ rc += _moncom(GETMONFUNC_SENDENETPKT,&_sendenet,0,0);
+ rc += _moncom(GETMONFUNC_RECVENETPKT,&_recvenet,0,0);
+ rc += _moncom(GETMONFUNC_GETSYM,&_getsym,0,0);
+ rc += _moncom(GETMONFUNC_PRINTPKT,&_printpkt,0,0);
+ rc += _moncom(GETMONFUNC_FLASHWRITE,&_flashwrite,0,0);
+ rc += _moncom(GETMONFUNC_FLASHERASE,&_flasherase,0,0);
+ rc += _moncom(GETMONFUNC_FLASHINFO,&_flashinfo,0,0);
+ rc += _moncom(GETMONFUNC_ASSIGNHDLR,&_assign_handler,0,0);
+ rc += _moncom(GETMONFUNC_WATCHDOG,&_watchdog,0,0);
+ rc += _moncom(GETMONFUNC_PRINTMEM,&_printmem,0,0);
+ rc += _moncom(GETMONFUNC_PORTCMD,&_portcmd,0,0);
+ rc += _moncom(GETMONFUNC_TIMEOFDAY,&_timeofday,0,0);
+ rc += _moncom(GETMONFUNC_TIMER,&_montimer,0,0);
+ rc += _moncom(GETMONFUNC_FLASHOVRRD,&_flashoverride,0,0);
+ }
+ return(rc);
+}
+
+/* ignorelock:
+ * Used as a back-door to disable the monLock()/monUnlock() stuff.
+ * This is useful if the application CLI falls through to the monitor's
+ * CLI and you are using the "call" command in the monitor to execute some
+ * function that has a mon_xxx function in it. In this case, the fact that
+ * the application has fallen through to the monitor means that the lock
+ * is already active, so when the function tries to call some other mon_xxx
+ * function it won't be able to because of the lock already being set.
+ *
+ * With these functions in the application space, the user can do the
+ * following:
+ * call %DisableLock
+ * call %Func_with_monXXX_in_it
+ * call %EnableLock
+ *
+ * Note that this is NOT to be used by application code, it is simply a
+ * back-door mechanism to allow "call" from the CLI to invoke functions
+ * that have mon_XXX functionality in them.
+ */
+static int ignorelock = 0;
+
+void
+DisableMonLock(void)
+{
+ ignorelock = 2;
+}
+
+void
+EnableMonLock(void)
+{
+ ignorelock = 0;
+}
+
+/* monLock() & monUnlock():
+ * Used by all of the wrapper functions below this point to call
+ * the function pointed to by _monlock & _monunlock function pointers
+ * (if set).
+ * These functions must test both the function pointer and the state
+ * of the ignorelock variable. The function DisableMonLock() sets the
+ * ignorelock variable to 2 because it is being executed through "call"
+ * which means that the lock is active.
+ */
+static void
+monLock()
+{
+ if (_monlock) {
+ switch(ignorelock) {
+ case 1:
+ break;
+ case 2:
+ ignorelock--;
+ break;
+ default:
+ _monlock();
+ break;
+ }
+ }
+}
+
+static void
+monUnlock()
+{
+ if (_monunlock) {
+ switch(ignorelock) {
+ case 1:
+ break;
+ case 2:
+ ignorelock--;
+ default:
+ _monunlock();
+ break;
+ }
+ }
+}
+
+int
+mon_com(int cmd, void *arg1, void *arg2, void *arg3)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _moncom(cmd,arg1,arg2,arg3);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_putchar(char c)
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _rputchar(c);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_getchar(void)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getchar();
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_gotachar(void)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _gotachar();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_getbytes(char *buf,int cnt,int block)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getbytes(buf,cnt,block);
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ CONSOLE_MONLOCK();
+ ret = _cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ CONSOLE_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt, *buf;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_restart(int val)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _monrestart(val);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getenvp(void)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getenvp();
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getenv(char *name)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getenv(name);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_setenv(char *name,char *val)
+{
+ int ret;
+
+ ENV_MONLOCK();
+ ret = _setenv(name,val);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_getsym(char *name,char *buf, int bufsize)
+{
+ char *ret;
+
+ ENV_MONLOCK();
+ ret = _getsym(name,buf,bufsize);
+ ENV_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsinit(void)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsinit();
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsadd(char *name, char *info, char *flags, unsigned char *src, int size)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsadd(name,info,flags,src,size);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfslink(char *src, char *target)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfslink(src,target);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsunlink(char *name)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsunlink(name);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsrun(char **name,int verbose)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsrun(name,verbose);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+struct tfshdr *
+mon_tfsnext(struct tfshdr *fp)
+{
+ struct tfshdr *ret;
+
+ TFS_MONLOCK();
+ ret = _tfsnext(fp);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfstruncate(int tfd, long len)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfstruncate(tfd,len);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfseof(int tfd)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfseof(tfd);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsfstat(char *name, struct tfshdr *fp)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsfstat(name,fp);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+struct tfshdr *
+mon_tfsstat(char *name)
+{
+ struct tfshdr *ret;
+
+ TFS_MONLOCK();
+ ret = _tfsstat(name);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsread(int fd, char *buf, int cnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsread(fd,buf,cnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfswrite(int fd, char *buf, int cnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfswrite(fd,buf,cnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsopen(char *file,long flagmode,char *buf)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsopen(file,flagmode,buf);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsclose(int fd,char *info)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsclose(fd,info);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsseek(int fd, int offset, int whence)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsseek(fd,offset,whence);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsgetline(int fd,char *bp,int max)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsgetline(fd,bp,max);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_tfsipmod(char *name,char *buf,int offset,int size)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _tfsipmod(name,buf,offset,size);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+long
+mon_tfsctrl(int rqst,long arg1,long arg2)
+{
+ long ret;
+
+ TFS_MONLOCK();
+ ret = _tfsctrl(rqst,arg1,arg2);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+long
+mon_tfstell(int fd)
+{
+ long ret;
+
+ TFS_MONLOCK();
+ ret = _tfstell(fd);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_addcommand(struct monCommand *cmdlist, char *cmdlvl)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _addcommand(cmdlist,cmdlvl);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_docommand(char *cmdline,int verbose)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _docommand(cmdline,verbose);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_getargv(int *argc,char ***argv)
+{
+ GENERIC_MONLOCK();
+ _getargv(argc,argv);
+ GENERIC_MONUNLOCK();
+}
+
+unsigned long
+mon_crc32(char *buf,long nbytes)
+{
+ unsigned long ret;
+
+ GENERIC_MONLOCK();
+ ret = _crc32((unsigned char *)buf,nbytes);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+unsigned short
+mon_xcrc16(char *buf,long nbytes)
+{
+ unsigned short ret;
+
+ GENERIC_MONLOCK();
+ ret = _xcrc16((unsigned char *)buf,nbytes);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+unsigned long
+mon_intsoff(void)
+{
+ unsigned long ret;
+
+ GENERIC_MONLOCK();
+ ret = _intsoff();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_intsrestore(unsigned long msr)
+{
+ GENERIC_MONLOCK();
+ _intsrestore(msr);
+ GENERIC_MONUNLOCK();
+}
+
+void
+mon_appexit(int val)
+{
+ GENERIC_MONLOCK();
+ _appexit(val);
+ GENERIC_MONUNLOCK();
+}
+
+#ifdef MALLOC_DEBUG
+char *
+mon_malloc(int size,char *fname,int fline)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _malloc(size,fname,fline);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_realloc(char *buf, int size, char *fname, int fline)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _realloc(buf,size, fname, fline);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+#else
+char *
+mon_malloc(int size)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _malloc(size);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+
+char *
+mon_realloc(char *buf, int size)
+{
+ char *ret;
+
+ HEAP_MONLOCK();
+ ret = _realloc(buf,size);
+ HEAP_MONUNLOCK();
+ return(ret);
+}
+#endif
+
+void
+mon_free(char *cp)
+{
+ HEAP_MONLOCK();
+ _free(cp);
+ HEAP_MONUNLOCK();
+}
+
+int
+mon_getline(char *buf,int max,int ledit)
+{
+ int ret;
+
+ BLOCKING_MONLOCK();
+ ret = _getline(buf,max,ledit);
+ BLOCKING_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_decompress(char *src,int srcsize,char *dest)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _decompress(src,srcsize,dest);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_heapextend(char *base,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _heapextend(base,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_bbc(char *filename, int lineno)
+{
+ _bbc(filename, lineno);
+}
+
+void
+mon_profiler(void *pdata)
+{
+ _profiler(pdata);
+}
+
+void
+mon_memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
+char *fmt;
+int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12;
+{
+ _memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
+}
+
+char *
+mon_version(void)
+{
+ char *ret;
+
+ GENERIC_MONLOCK();
+ ret = _version();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_warmstart(unsigned long mask)
+{
+ GENERIC_MONLOCK();
+ _appwarmstart(mask);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg,
+ unsigned long val)
+{
+ int retval;
+
+ GENERIC_MONLOCK();
+ retval = _pcicfgwrite(interface,bus,dev,func,reg,val);
+ GENERIC_MONUNLOCK();
+ return(retval);
+}
+
+unsigned long
+mon_pcicfgread(int interface,int bus,int dev, int func,int reg)
+{
+ unsigned long retval;
+
+ GENERIC_MONLOCK();
+ retval = _pcicfgread(interface,bus,dev,func,reg);
+ GENERIC_MONUNLOCK();
+ return(retval);
+}
+
+unsigned long
+mon_pcictrl(int interface, int cmd, unsigned long arg1, unsigned long arg2)
+{
+ unsigned long val;
+
+ GENERIC_MONLOCK();
+ val = _pcictrl(interface,cmd,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+unsigned long
+mon_i2cctrl(int interface, int cmd, unsigned long arg1, unsigned long arg2)
+{
+ unsigned long val;
+
+ GENERIC_MONLOCK();
+ val = _i2cctrl(interface,cmd,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+int
+mon_i2cwrite(int interface, int bigaddr, unsigned char *data, int len)
+{
+ int val;
+
+ GENERIC_MONLOCK();
+ val = _i2cwrite(interface,bigaddr,data,len);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+int
+mon_i2cread(int interface, int bigaddr, unsigned char *data, int len)
+{
+ int val;
+
+ GENERIC_MONLOCK();
+ val = _i2cread(interface,bigaddr,data,len);
+ GENERIC_MONUNLOCK();
+ return(val);
+}
+
+void
+mon_delay(long msec)
+{
+ GENERIC_MONLOCK();
+ _mondelay(msec);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_timer(int cmd, void *arg)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _montimer(cmd, arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_sendenetpkt(char *pkt,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _sendenet(pkt,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_recvenetpkt(char *pkt,int size)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _recvenet(pkt,size);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_printpkt(char *buf,int size, int incoming)
+{
+ GENERIC_MONLOCK();
+ _printpkt(buf,size,incoming);
+ GENERIC_MONUNLOCK();
+}
+
+int
+mon_flashoverride(void *flashinfo,int get,int bank)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashoverride(flashinfo,get,bank);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flashwrite(char *dest,char *src,int bytecnt)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashwrite(dest,src,bytecnt);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flasherase(int snum)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flasherase(snum);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_flashinfo(int snum, int *size, char **base)
+{
+ int ret;
+
+ TFS_MONLOCK();
+ ret = _flashinfo(snum,size,base);
+ TFS_MONUNLOCK();
+ return(ret);
+}
+
+unsigned long
+mon_assignhandler(long hnum, unsigned long arg1, unsigned long arg2)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _assign_handler(hnum,arg1,arg2);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_watchdog(void)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _watchdog();
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+void
+mon_printmem(char *mem, int size, int ascii)
+{
+ GENERIC_MONLOCK();
+ _printmem(mem,size,ascii);
+ GENERIC_MONUNLOCK();
+}
+
+long
+mon_portcmd(int cmd, void *arg)
+{
+ long ret;
+
+ GENERIC_MONLOCK();
+ ret = _portcmd(cmd,arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
+
+int
+mon_timeofday(int cmd, void *arg)
+{
+ int ret;
+
+ GENERIC_MONLOCK();
+ ret = _timeofday(cmd,arg);
+ GENERIC_MONUNLOCK();
+ return(ret);
+}
diff --git a/main/common/monlib.h b/main/common/monlib.h
new file mode 100644
index 0000000..36c605b
--- /dev/null
+++ b/main/common/monlib.h
@@ -0,0 +1,253 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monlib.h:
+ *
+ * This header file is used by both the monitor and the application that
+ * may reside on top of the monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _MONLIB_H_
+#define _MONLIB_H_
+
+#include "tfs.h"
+#include "cli.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SHOWVARARGS
+#define SHOWVARARGS 1
+#endif
+
+
+extern int monConnect(int (*monptr)(int,void *,void *,void *),
+ void (*lock)(void),void (*unlock)(void));
+extern void mon_getargv(int *argc,char ***argv);
+extern void mon_intsrestore(unsigned long oldval);
+extern void mon_appexit(int exit_value);
+extern void mon_free(char *buffer);
+extern void mon_profiler(void *pdata);
+extern void mon_bbc(char *filename, int linenum);
+extern void mon_warmstart(unsigned long mask);
+extern void mon_delay(long msec);
+extern void mon_printpkt(char *buf, int size, int incoming);
+extern void mon_printmem(char *mem, int size, int ascii);
+
+
+extern int mon_com(int cmd,void *arg1,void *arg2,void *arg3);
+extern int mon_timer(int cmd, void * arg);
+extern int mon_setenv(char *varname,char *value);
+extern int mon_putchar(char c);
+extern int mon_getchar(void);
+extern int mon_gotachar(void);
+extern int mon_getbytes(char *buf,int count,int block);
+extern int mon_restart(int restart_value);
+extern int mon_tfsinit(void);
+extern int mon_tfsunlink(char *filename);
+extern int mon_tfslink(char *source, char *target);
+extern int mon_tfsrun(char **arglist,int verbosity);
+extern int mon_tfsfstat(char *filename,struct tfshdr *tfp);
+extern int mon_tfseof(int file_descriptor);
+extern int mon_tfstruncate(int file_descriptor,long length);
+extern int mon_tfsread(int file_descriptor,char *buffer,int size);
+extern int mon_tfswrite(int file_descriptor,char *buffer,int size);
+extern int mon_tfsopen(char *filename,long mode,char *buffer);
+extern int mon_tfsclose(int file_descriptor,char *info);
+extern int mon_tfsseek(int file_descriptor,int offset,int whence);
+extern int mon_tfsgetline(int file_descriptor,char *buffer,int bufsize);
+extern int mon_tfsipmod(char *name,char *buffer,int offset,int size);
+extern int mon_addcommand(struct monCommand *command_list,char *);
+extern int mon_docommand(char *cmdline,int verbosity);
+extern int mon_getline(char *buffer,int max,int ledit);
+extern int mon_decompress(char *src,int srcsize,char *dest);
+extern int mon_heapextend(char *base,int size);
+extern int mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg,
+ unsigned long val);
+extern int mon_tfsadd(char *filename, char *info, char *flags,
+ unsigned char *src, int size);
+extern int mon_i2cwrite(int interface, int bigaddr, unsigned char *data,
+ int len);
+extern int mon_i2cread(int interface, int bigaddr, unsigned char *data,
+ int len);
+extern int mon_sendenetpkt(char *pkt, int len);
+extern int mon_recvenetpkt(char *pkt, int len);
+extern int mon_flashoverride(void *flashinfo, int get, int bank);
+extern int mon_flasherase(int snum);
+extern int mon_flashwrite(char *dest,char *src, int bytecnt);
+extern int mon_flashinfo(int snum,int *size, char **base);
+extern int mon_watchdog(void);
+extern int mon_timeofday(int cmd, void *arg);
+
+extern char *mon_getsym(char *symname, char *buf, int bufsize);
+extern char *mon_getenv(char *varname);
+extern char *mon_getenvp(void);
+extern char *mon_version(void);
+#ifdef MALLOC_DEBUG
+extern char *mon_malloc(int size,char *file, int line);
+extern char *mon_realloc(char *buf,int size,char *file, int line);
+#else
+extern char *mon_malloc(int size);
+extern char *mon_realloc(char *buf,int size);
+#endif
+
+extern long mon_tfsctrl(int command,long arg1,long arg2);
+extern long mon_tfstell(int file_descriptor);
+extern long mon_portcmd(int cmd, void *arg);
+
+extern unsigned short mon_xcrc16(char *buffer,long length);
+extern unsigned long mon_crc32(char *buffer,long length);
+
+extern unsigned long mon_intsoff(void);
+
+extern unsigned long mon_pcicfgread(int interface,int bus,int dev,
+ int func,int reg);
+
+extern unsigned long mon_pcictrl(int interface, int cmd,
+ unsigned long arg1, unsigned long arg2);
+
+extern unsigned long mon_i2cctrl(int interface, int cmd,
+ unsigned long arg1, unsigned long arg2);
+
+extern unsigned long mon_assignhandler(long hnum,
+ unsigned long arg1,unsigned long arg2);
+
+extern struct tfshdr *mon_tfsnext(struct tfshdr *tfp);
+extern struct tfshdr *mon_tfsstat(char *filename);
+
+#if SHOWVARARGS
+extern void mon_memtrace(char *fmt, ...);
+extern int mon_printf(char *fmt, ...);
+extern int mon_cprintf(char *fmt, ...);
+extern int mon_sprintf(char *,char *fmt, ...);
+#else
+extern void mon_memtrace();
+extern int mon_printf();
+extern int mon_cprintf();
+extern int mon_sprintf();
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* defines used by monConnect():
+ */
+#define GETMONFUNC_PUTCHAR 1
+#define GETMONFUNC_GETCHAR 2
+#define GETMONFUNC_GOTACHAR 3
+#define GETMONFUNC_GETBYTES 4
+#define GETMONFUNC_PRINTF 5
+#define GETMONFUNC_CPRINTF 6
+#define GETMONFUNC_SPRINTF 7
+#define GETMONFUNC_RESTART 8
+#define GETMONFUNC_GETENV 9
+#define GETMONFUNC_SETENV 10
+#define GETMONFUNC_TFSINIT 11
+#define GETMONFUNC_TFSADD 12
+#define GETMONFUNC_TFSUNLINK 13
+#define GETMONFUNC_TFSRUN 14
+#define GETMONFUNC_TFSNEXT 15
+#define GETMONFUNC_TFSSTAT 16
+#define GETMONFUNC_TFSREAD 17
+#define GETMONFUNC_TFSWRITE 18
+#define GETMONFUNC_TFSOPEN 19
+#define GETMONFUNC_TFSCLOSE 20
+#define GETMONFUNC_TFSSEEK 21
+#define GETMONFUNC_TFSGETLINE 22
+#define GETMONFUNC_TFSIPMOD 23
+#define GETMONFUNC_TFSCTRL 24
+#define GETMONFUNC_ADDCOMMAND 25
+#define GETMONFUNC_DOCOMMAND 26
+#define GETMONFUNC_GETARGV 27
+#define GETMONFUNC_CRC16 28
+#define GETMONFUNC_CRC32 29
+#define GETMONFUNC_PIOGET 30 /* NA (removed as of 1.0) */
+#define GETMONFUNC_PIOSET 31 /* NA (removed as of 1.0) */
+#define GETMONFUNC_PIOCLR 32 /* NA (removed as of 1.0) */
+#define GETMONFUNC_INTSOFF 33
+#define GETMONFUNC_INTSRESTORE 34
+#define GETMONFUNC_APPEXIT 35
+#define GETMONFUNC_MALLOC 36
+#define GETMONFUNC_FREE 37
+#define GETMONFUNC_GETLINE 38
+#define GETMONFUNC_TFSFSTAT 39
+#define GETMONFUNC_TFSEOF 40
+#define GETMONFUNC_DECOMPRESS 41
+#define GETMONFUNC_TFSTRUNCATE 42
+#define GETMONFUNC_HEAPXTEND 43
+#define GETMONFUNC_PROFILER 44
+#define GETMONFUNC_TFSLINK 45
+#define GETMONFUNC_BBC 46
+#define GETMONFUNC_MEMTRACE 47
+#define GETMONFUNC_TFSTELL 48
+#define GETMONFUNC_VERSION 49
+#define GETMONFUNC_WARMSTART 50
+#define GETMONFUNC_PCICFGREAD 51
+#define GETMONFUNC_PCICFGWRITE 52
+#define GETMONFUNC_PCICONTROL 53
+#define GETMONFUNC_I2CREAD 54
+#define GETMONFUNC_I2CWRITE 55
+#define GETMONFUNC_I2CCONTROL 56
+#define GETMONFUNC_MONDELAY 57
+#define GETMONFUNC_GETENVP 58
+#define GETMONFUNC_REALLOC 59
+#define GETMONFUNC_SENDENETPKT 60
+#define GETMONFUNC_RECVENETPKT 61
+#define GETMONFUNC_GETSYM 62
+#define GETMONFUNC_PRINTPKT 63
+#define GETMONFUNC_FLASHWRITE 64
+#define GETMONFUNC_FLASHERASE 65
+#define GETMONFUNC_FLASHINFO 66
+#define GETMONFUNC_ASSIGNHDLR 67
+#define GETMONFUNC_WATCHDOG 68
+#define GETMONFUNC_PRINTMEM 69
+#define GETMONFUNC_PORTCMD 70
+#define GETMONFUNC_TIMEOFDAY 71
+#define GETMONFUNC_TIMER 72
+#define GETMONFUNC_FLASHOVRRD 73
+
+#define CACHEFTYPE_DFLUSH 200
+#define CACHEFTYPE_IINVALIDATE 201
+
+#define CHARFUNC_PUTCHAR 300
+#define CHARFUNC_GETCHAR 301
+#define CHARFUNC_GOTACHAR 302
+#define CHARFUNC_RAWMODEON 303
+#define CHARFUNC_RAWMODEOFF 304
+
+#define ASSIGNFUNC_GETUSERLEVEL 400
+#define ASSIGNFUNC_WATCHDOG 401
+
+
+/* Defines used by mon_warmstart():
+ */
+#define WARMSTART_IOINIT 0x00000001
+#define WARMSTART_BSSINIT 0x00000002
+#define WARMSTART_RUNMONRC 0x00000004
+#define WARMSTART_MONHEADER 0x00000008
+#define WARMSTART_TFSAUTOBOOT 0x00000010
+#define WARMSTART_BOARDINFO 0x00000020
+#define WARMSTART_ALL 0xffffffff
+#endif
diff --git a/main/common/monprof.c b/main/common/monprof.c
new file mode 100644
index 0000000..ebf673b
--- /dev/null
+++ b/main/common/monprof.c
@@ -0,0 +1,646 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monprof.c:
+ *
+ * This command and support code allow the monitor to provide an application
+ * with some system profiling capabilities. The function "profiler"
+ * is part of the API to allow the application to take advantage of this.
+ *
+ * The basic assumption is that the application has the ability to insert
+ * a call to mon_profiler() in its system tick handler (actually the call
+ * can be put anywhere in the application, but this is the most logical
+ * place to put it). The content of the structure passed in to
+ * mon_profiler() depends on what kind of profiling the application wants
+ * to do. The tool works partially through calls made by the application
+ * into the monitor's api (mon_profiler()) and partially through
+ * interaction with the user at the monitor command line. The runtime
+ * profiling calls are done in application space, but the initial setup of
+ * the profiling session is done at the CLI.
+ *
+ * There are a few different profiling mechanisms in place...
+ *
+ * FUNCTION LOGGING:
+ * This capability makes the same assumption regarding the symtbl file
+ * as does strace... That the symbols are listed in the file in ascending
+ * address order. Ideally, the only symbols in the file would be the
+ * functions, so some processing can be done on the symtbl file prior to
+ * putting it on the target, this would help (not mandatory). At the CLI,
+ * the user issues the "prof init [address]" command. This initializes
+ * a table in the monitor that contains one pdata structure for each entry
+ * in the symtbl file. The pdata structure simply contains the starting
+ * address and a pass count for each entry in symtbl. After this
+ * initialization, runtime profiling can start. This is used by setting
+ * the MONPROF_FUNCLOG (see monprof.h) flag in the 'type' member of the
+ * monprof structure. Upon entry into the profiler, the 'pc' member of
+ * the incoming structure is assumed to contain the address that was
+ * executing at the time of the interrupt. The profiler uses a simple
+ * binary search to scan through all entries in the table to find the
+ * symbol (function) that the address falls within. When this is found,
+ * that entry's pass count variable is incremented. At some point later,
+ * profiling is completed and the user can dump the results to show the
+ * user what functions were hogging the CPU during the profiling session.
+ *
+ * Example setup:
+ * prof init # Initialize internals.
+ * prof funccfg # Configure function logging using symtbl.
+ * prof on # Enable profiling.
+ *
+ *
+ * PC LOGGING:
+ * This capability assumes that every instruction is the same size (typical
+ * for RISC CPUs). It uses a block of memory equal in size to the .text
+ * section of the application and treats that block as a table of counters.
+ * Each time the profiler is called, the PC (along with some delta) is
+ * used as an offset into the table and that offset is incremented.
+ * This may be used as a better alternative to the FUNCTION LOGGING
+ * mechanism described above; but it does have some additional requirements,
+ * (fixed-width instruction & extra ram space == .text size) so it may not
+ * be an option.
+ *
+ * Example setup:
+ * prof init # Initialize internals.
+ * prof pccfg 4 0x22000 0x10000 # Configure pc logging for 32-bit
+ * # instructions. The .text space of
+ * # the application starts at 0x22000
+ * # with a size of 0x10000 bytes.
+ * prof on # Enable profiling.
+ *
+ * TASK ID LOGGING:
+ * Similar to function logging except that the MONPROF_TIDLOG flag is set
+ * in the 'type' member, and the 'tid' member is used...
+ * The user initializes with the "prof tinit {count}" command. The count
+ * is the maximum number of unique task ids expected. The monitor builds
+ * another table and as each tid comes in through mon_profiler, if this is
+ * the first time mon_profiler() is being called with the specific incoming
+ * tid value, then it is added to the list of pdata structures and the pass
+ * count is set to 1; otherwise if it has already been logged, only the
+ * pass count is incremented.
+ *
+ * Example setup:
+ * prof init # Initialize internals.
+ * prof tidcfg 16 # Configure tid logging for 16 unique tids.
+ * prof on # Enable profiling.
+ *
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "monprof.h"
+#if INCLUDE_PROFILER
+#include "stddefs.h"
+#include "genlib.h"
+#include <ctype.h>
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+
+#define HALF(m) (m >> 1)
+
+/* pdata:
+ * One of these represents each symbol (or tid) in the profiling session.
+ * For MONPROF_FUNCLOG, the data member is the starting address of the symbol
+ * and for MONPROF_TIDLOG, the data member is the tid value.
+ */
+struct pdata {
+ ulong data; /* Start of symbol or tid. */
+ int pcount; /* Pass count. */
+};
+
+static int prof_Enabled; /* If set, profiler runs; else return. */
+static int prof_BadSymCnt; /* Number of hits not within a symbol. */
+static int prof_CallCnt; /* Number of times profiler was called. */
+static int prof_FuncTot; /* Number of functions being profiled. */
+static int prof_TidTot; /* Number of TIDs being profiled. */
+static int prof_TidTally; /* Number of unique TIDs logged so far. */
+static int prof_TidOverflow; /* More TIDs than the table was built for. */
+static int prof_PcTot; /* Number of instructions being profiled. */
+static int prof_PcDelta; /* Delta between .text space and PC table. */
+static int prof_PcWidth; /* Width (2 or 4) of PC table elements. */
+static int prof_PcOORCnt; /* Out-of-range hit count for PC profiler */
+static ulong prof_PcTxtEnd; /* End of .text area being profiled */
+static ulong prof_PcTxtBase; /* Base of .text area being profiled */
+
+static struct pdata *prof_FuncTbl;
+static struct pdata *prof_TidTbl;
+static uchar *prof_PcTbl;
+static char prof_SymFile[TFSNAMESIZE+1];
+
+void
+profiler(struct monprof *mpp)
+{
+ struct pdata *current, *base;
+ int nmem;
+
+ if (prof_Enabled == 0)
+ return;
+
+ if (mpp->type & MONPROF_FUNCLOG) {
+ nmem = prof_FuncTot;
+ base = prof_FuncTbl;
+ while(nmem) {
+ current = &base[HALF(nmem)];
+ if (mpp->pc < current->data)
+ nmem = HALF(nmem);
+ else if (mpp->pc > current->data) {
+ if (mpp->pc < (current+1)->data) {
+ current->pcount++;
+ goto tidlog;
+ }
+ else {
+ base = current + 1;
+ nmem = (HALF(nmem)) - (nmem ? 0 : 1);
+ }
+ }
+ else {
+ current->pcount++;
+ goto tidlog;
+ }
+ }
+ prof_BadSymCnt++;
+ }
+tidlog:
+ if (mpp->type & MONPROF_TIDLOG) {
+ /* First see if the tid is already in the table. If it is,
+ * increment the pcount. If it isn't add it to the table.
+ */
+ nmem = prof_TidTally;
+ base = prof_TidTbl;
+ while(nmem) {
+ current = &base[HALF(nmem)];
+ if (mpp->tid < current->data)
+ nmem = HALF(nmem);
+ else if (mpp->tid > current->data) {
+ base = current + 1;
+ nmem = (HALF(nmem)) - (nmem ? 0 : 1);
+ }
+ else {
+ current->pcount++;
+ goto pclog;
+ }
+ }
+ /* Since we got here, the tid must not be in the table, so
+ * do an insertion into the table. Items are in the table in
+ * ascending order.
+ */
+ if (prof_TidTally == 0) {
+ prof_TidTbl->pcount = 1;
+ prof_TidTbl->data = mpp->tid;
+ prof_TidTally++;
+ }
+ else if (prof_TidTally >= prof_TidTot) {
+ prof_TidOverflow++;
+ }
+ else {
+ current = prof_TidTbl + prof_TidTally - 1;
+ while(current >= prof_TidTbl) {
+ if (mpp->tid > current->data) {
+ current++;
+ current->pcount = 1;
+ current->data = mpp->tid;
+ break;
+ }
+ else {
+ *(current+1) = *current;
+ if (current == prof_TidTbl) {
+ current->pcount = 1;
+ current->data = mpp->tid;
+ break;
+ }
+ }
+ current--;
+ }
+ prof_TidTally++;
+ }
+ }
+pclog:
+ if (mpp->type & MONPROF_PCLOG) {
+ ulong offset;
+
+ if ((mpp->pc > prof_PcTxtEnd) || (mpp->pc < prof_PcTxtBase)) {
+ prof_PcOORCnt++;
+ }
+ else {
+ offset = mpp->pc - prof_PcDelta;
+ switch(prof_PcWidth) {
+ case 2:
+ (*(ushort *)offset)++;
+ break;
+ case 4:
+ (*(ulong *)offset)++;
+ break;
+ }
+ }
+ }
+ prof_CallCnt++;
+ return;
+}
+
+int
+prof_GetSymFile(void)
+{
+ int tfd;
+
+ if (prof_SymFile[0] == 0) {
+ tfd = SymFileFd(1);
+ }
+ else {
+ tfd = tfsopen(prof_SymFile,TFS_RDONLY,0);
+ if (tfd < 0) {
+ printf("%s: %s\n",prof_SymFile,(char *)tfsctrl(TFS_ERRMSG,tfd,0));
+ }
+ }
+ return(tfd);
+}
+
+void
+prof_ShowStats(int minhit, int more)
+{
+ int i, tfd, linecount;
+ ulong notused;
+ char symname[64];
+ struct pdata *pptr;
+
+ printf("FuncCount Cfg: tbl: 0x%08lx, size: 0x%x\n",
+ (ulong)prof_FuncTbl, prof_FuncTot);
+ printf("TidCount Cfg: tbl: 0x%08lx, size: 0x%x\n",
+ (ulong)prof_TidTbl, prof_TidTot);
+ printf("PcCount Cfg: tbl: 0x%08lx, size: 0x%x\n",
+ (ulong)prof_PcTbl, prof_PcTot*prof_PcWidth);
+
+ if (prof_CallCnt == 0) {
+ printf("No data collected%s",
+ prof_Enabled == 0 ? " (profiling disabled)\n" : "\n");
+ return;
+ }
+ linecount = 0;
+ tfd = prof_GetSymFile();
+ if ((prof_FuncTbl) && (prof_FuncTot > 0)) {
+ printf("\nFUNC_PROF stats:\n");
+ pptr = prof_FuncTbl;
+ for(i=0;i<prof_FuncTot;pptr++,i++) {
+ if (pptr->pcount < minhit)
+ continue;
+ if ((tfd < 0) ||
+ (AddrToSym(tfd,pptr->data,symname,&notused) == 0)) {
+ printf(" %08lx : %d\n",pptr->data,pptr->pcount);
+ }
+ else {
+ printf(" %-25s: %d\n",symname,pptr->pcount);
+ }
+ if ((more) && (++linecount >= more)) {
+ linecount = 0;
+ if (More() == 0)
+ goto showdone;
+ }
+ }
+ }
+ if ((prof_TidTbl) && (prof_TidTot > 0)) {
+ printf("\nTID_PROF stats:\n");
+ pptr = prof_TidTbl;
+ for(i=0;i<prof_TidTot;pptr++,i++) {
+ if (pptr->pcount < minhit)
+ continue;
+ printf(" %08lx : %d\n",pptr->data,pptr->pcount);
+ if ((more) && (++linecount >= more)) {
+ linecount = 0;
+ if (More() == 0)
+ goto showdone;
+ }
+ }
+ }
+ if (prof_PcTbl) {
+ ushort *sp;
+ ulong *lp;
+
+ sp = (ushort *)prof_PcTbl;
+ lp = (ulong *)prof_PcTbl;
+ printf("\nPC_PROF stats:\n");
+ for(i=0;i<prof_PcTot;i++) {
+ switch(prof_PcWidth) {
+ case 2:
+ if (*sp >= minhit) {
+ printf(" %08x : %d\n",
+ (int)sp + prof_PcDelta,*sp);
+ linecount++;
+ }
+ sp++;
+ break;
+ case 4:
+ if (*lp >= minhit) {
+ printf(" %08x : %ld\n",
+ (int)lp + prof_PcDelta,*lp);
+ linecount++;
+ }
+ lp++;
+ break;
+ }
+ if ((more) && (linecount >= more)) {
+ linecount = 0;
+ if (More() == 0)
+ goto showdone;
+ }
+ }
+ }
+showdone:
+ putchar('\n');
+ if (prof_BadSymCnt)
+ printf("%d out-of-range symbols\n",prof_BadSymCnt);
+ if (prof_TidOverflow)
+ printf("%d tid overflow attempts\n",prof_TidOverflow);
+ if (prof_PcOORCnt)
+ printf("%d pc out-of-range hits\n",prof_PcOORCnt);
+ printf("%d total profiler calls\n",prof_CallCnt);
+
+ if (tfd >= 0)
+ tfsclose(tfd,0);
+ return;
+}
+
+/* prof_FuncConfig():
+ * This function builds a table of pdata structures based on the
+ * content of the symbol table.
+ * It assumes the file is a list of symbols and addresses listed
+ * in ascending address order.
+ */
+void
+prof_FuncConfig(void)
+{
+ int tfd, i;
+ struct pdata *pfp;
+ char line[80], *space;
+
+ tfd = prof_GetSymFile();
+ if (tfd < 0)
+ return;
+
+ prof_FuncTot = 0;
+ pfp = prof_FuncTbl;
+
+ while(tfsgetline(tfd,line,sizeof(line)-1)) {
+ space = strpbrk(line,"\t ");
+ if (!space)
+ continue;
+ *space++ = 0;
+ while(isspace(*space))
+ space++;
+ pfp->data = strtoul(space,0,0);
+ pfp->pcount = 0;
+ pfp++;
+ prof_FuncTot++;
+ }
+ tfsclose(tfd,0);
+
+ /* Add one last item to the list so that there is an upper limit for
+ * the final symbol in the table:
+ */
+ pfp->data = 0xffffffff;
+ pfp->pcount = 0;
+
+ /* Test to verify that all symbols are in ascending address order...
+ */
+ for (i=0;i<prof_FuncTot;i++) {
+ if (prof_FuncTbl[i].data > prof_FuncTbl[i+1].data) {
+ printf("Warning: function addresses not in order\n");
+ break;
+ }
+ }
+ prof_FuncTot++;
+}
+
+/* prof():
+ */
+
+char *ProfHelp[] = {
+ "Profiler configuration and result display",
+ "-[h:m:s:] [operation] [op-specific args]",
+#if INCLUDE_VERBOSEHELP
+ "Operations:",
+ " on enable profiler",
+ " off disable profiler",
+ " show dump stats",
+ " init clear internal tables and runtime stats",
+ " call {type pc tid} call profiler from CLI",
+ " ('type' can be any combination of 't', 'f' & 'p')",
+ " restart clear runtime stats only",
+ " tidcfg {tidtot} init tid profiler based on number of task ids",
+ " funccfg init function profiler from symtbl file",
+ " pccfg {wid add siz} init pc profiler with instruction width (2 or 4)",
+ " plus size and addr of text area",
+ "",
+ "Options:",
+ " -a{#} address to use for table",
+ " -h{#} minimum hit count for show",
+ " -m{#} line count for output throttling in show",
+ " -s{symfile} use this file for symbols instead of default",
+#endif
+ 0,
+};
+
+int
+Prof(int argc,char *argv[])
+{
+ char *arg1, *arg2, *arg3, *arg4;
+ ulong address;
+ int i, opt, minhit, ret, more;
+
+ ret = CMD_SUCCESS;
+ minhit = 1;
+ more = 0;
+ address = 0;
+ while((opt=getopt(argc,argv,"a:h:m:s:")) != -1) {
+ switch(opt) {
+ case 'a':
+ address = strtoul(optarg,0,0);
+ break;
+ case 'h':
+ minhit = atoi(optarg);
+ break;
+ case 'm':
+ more = atoi(optarg);
+ break;
+ case 's':
+ strncpy(prof_SymFile,optarg,TFSNAMESIZE);
+ prof_SymFile[TFSNAMESIZE] = 0;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ arg1 = argv[optind];
+ arg2 = argv[optind+1];
+ arg3 = argv[optind+2];
+ arg4 = argv[optind+3];
+
+ if (argc == optind+1) {
+ if (!strcmp(arg1,"on")) {
+ prof_Enabled = 1;
+ }
+ else if (!strcmp(arg1,"off")) {
+ prof_Enabled = 0;
+ }
+ else if (!strcmp(arg1,"show")) {
+ prof_ShowStats(minhit, more);
+ }
+ else if (!strcmp(arg1,"init")) {
+ prof_BadSymCnt = 0;
+ prof_CallCnt = 0;
+ prof_TidTally = 0;
+ prof_Enabled = 0;
+ prof_FuncTot = 0;
+ prof_TidTot = 0;
+ prof_PcTot = 0;
+ prof_FuncTbl = (struct pdata *)0;
+ prof_TidTbl = (struct pdata *)0;
+ prof_PcTbl = (uchar *)0;
+ prof_PcWidth = 0;
+ prof_PcDelta = 0;
+ prof_SymFile[0] = 0;
+ }
+ else if (!strcmp(arg1,"restart")) {
+ prof_BadSymCnt = 0;
+ prof_CallCnt = 0;
+ prof_TidTally = 0;
+ if (prof_FuncTbl) {
+ for(i=0;i<prof_FuncTot;i++)
+ prof_FuncTbl[i].pcount = 0;
+ }
+ if (prof_TidTbl) {
+ for(i=0;i<prof_TidTot;i++)
+ prof_TidTbl[i].pcount = 0;
+ prof_TidTbl[i].data = 0;
+ }
+ if (prof_PcTbl) {
+ memset((char *)prof_PcTbl,0,prof_PcTot*prof_PcWidth);
+ }
+ }
+ else if (!strcmp(arg1,"funccfg")) {
+ if (prof_FuncTbl) {
+ printf("Already configured, run init to re-configure\n");
+ return(CMD_FAILURE);
+ }
+ else if (prof_PcTbl) {
+ printf("Can't use PC and FUNC profiling simultaneously\n");
+ return(CMD_FAILURE);
+ }
+ else if (address) {
+ prof_FuncTbl = (struct pdata *)address;
+ }
+ else if (prof_TidTbl) {
+ prof_FuncTbl = &prof_TidTbl[prof_TidTot];
+ }
+ else
+ prof_FuncTbl = (struct pdata *)getAppRamStart();
+
+ prof_FuncConfig();
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+ else if (argc == optind+2) {
+ if (!strcmp(arg1,"tidcfg")) {
+ if (prof_TidTbl) {
+ printf("Already configured, run init to re-configure\n");
+ return(CMD_FAILURE);
+ }
+ else if (address) {
+ prof_TidTbl = (struct pdata *)address;
+ }
+ else if (prof_FuncTbl) {
+ prof_TidTbl = &prof_FuncTbl[prof_FuncTot];
+ }
+ else if (prof_PcTbl) {
+ prof_TidTbl = (struct pdata *)&prof_PcTbl[prof_PcTot];
+ }
+ else
+ prof_TidTbl = (struct pdata *)getAppRamStart();
+ prof_TidTot = strtoul(arg2,0,0);
+ for(i=0;i<prof_TidTot;i++) {
+ prof_TidTbl[i].data = 0;
+ prof_TidTbl[i].pcount = 0;
+ }
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+ else if (argc == optind+4) {
+ if (!strcmp(arg1,"call")) {
+ struct monprof mp;
+
+ mp.type = 0;
+
+ if (strchr(arg2,'f'))
+ mp.type |= MONPROF_FUNCLOG;
+ if (strchr(arg2,'p'))
+ mp.type |= MONPROF_PCLOG;
+ if (strchr(arg2,'t'))
+ mp.type |= MONPROF_TIDLOG;
+
+ mp.pc = strtoul(arg3,0,0);
+ mp.tid = strtoul(arg4,0,0);
+
+ profiler(&mp);
+ }
+ else if (!strcmp(arg1,"pccfg")) {
+ int size;
+
+ if (prof_PcTbl) {
+ printf("Already configured, run init to re-configure\n");
+ return(CMD_FAILURE);
+ }
+ else if (prof_FuncTbl) {
+ printf("Can't use PC and FUNC profiling simultaneously\n");
+ return(CMD_FAILURE);
+ }
+ else if (address) {
+ prof_PcTbl = (uchar *)address;
+ }
+ else if (prof_TidTbl) {
+ prof_PcTbl = (uchar *)&prof_TidTbl[prof_TidTot];
+ }
+ else
+ prof_PcTbl = (uchar *)getAppRamStart();
+ prof_PcWidth = strtol(arg2,0,0); /* instruction width */
+ prof_PcTxtBase = strtol(arg3,0,0); /* address of .text */
+ size = strtol(arg4,0,0); /* size of .text */
+ prof_PcTxtEnd = prof_PcTxtBase + size;
+ prof_PcTot = size / prof_PcWidth;
+ prof_PcDelta = (ulong)prof_PcTxtBase - (ulong)prof_PcTbl;
+ memset((char *)prof_PcTbl,0,prof_PcTot*prof_PcWidth);
+
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+ }
+ else
+ ret = CMD_PARAM_ERROR;
+
+ return(ret);
+}
+#else
+
+void
+profiler(struct monprof *mpp)
+{
+}
+
+#endif
diff --git a/main/common/monprof.h b/main/common/monprof.h
new file mode 100644
index 0000000..5eebe31
--- /dev/null
+++ b/main/common/monprof.h
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * monprof.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _MONPROF_H_
+#define _MONPROF_H_
+
+#define MONPROF_FUNCLOG (1 << 0)
+#define MONPROF_TIDLOG (1 << 1)
+#define MONPROF_PCLOG (1 << 2)
+
+struct monprof {
+ unsigned long type;
+ unsigned long pc;
+ unsigned long tid;
+};
+
+#endif
diff --git a/main/common/mprintf.c b/main/common/mprintf.c
new file mode 100644
index 0000000..c178253
--- /dev/null
+++ b/main/common/mprintf.c
@@ -0,0 +1,691 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * vmprintf.c:
+ *
+ * Same as mprintf, but this uses stdarg.h.
+ * Cleaner and simpler. I have some targets using this and will probably
+ * convert all targets to use this eventually.
+ *
+ * Note that this requires that the CFLAGS used in the building of this
+ * file should omit the "-nostdinc" option, so that the standard header
+ * (stdarg.h) can be pulled in.
+ *
+ * Public functions:
+ * vsnprintf(), snprintf(), sprintf(), printf(), cprintf()
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include <stdarg.h>
+#include "stddefs.h"
+#include "cli.h"
+
+extern long abs(long);
+extern void puts(char *);
+extern int atoi(char *), putchar(char);
+int printf(char *fmt, ...);
+
+static char *hexdigits = "0123456789abcdef";
+static char *Hexdigits = "0123456789ABCDEF";
+
+#define MAX_NUMBER_SIZE 18
+#define HDRSIZE 4
+#define NEGATIVE 1
+#define POSITIVE 2
+#define SCREENWIDTH 80
+
+/* PROCCHARP(), PROCCHAR(), BUFDEC() & BUFINC():
+ * Macros used to conveniently distinguish between buffer-bound
+ * and console-bound characters during the formatting process.
+ */
+#define PROCCHARP(bp,eob,cp) \
+ if (bp) { \
+ if (eob && (bp >= eob)) { \
+ puts("s_printf buffer overflow"); \
+ return(-1); \
+ } \
+ *bp++ = *cp++; \
+ } \
+ else { \
+ putchar(*cp++); \
+ }
+
+#define PROCCHAR(bp,eob,c) \
+ if (bp) { \
+ if (eob && (bp >= eob)) { \
+ puts("s_printf buffer overflow"); \
+ return(-1); \
+ } \
+ *bp++ = c; \
+ } \
+ else { \
+ if (c) \
+ putchar(c); \
+ }
+
+#define BUFDEC(bp,val) \
+ if (bp) { \
+ bp -= val; \
+ }
+
+#define BUFINC(bp,val) \
+ if (bp) { \
+ bp += val; \
+ }
+
+
+/* isdigit():
+ * Copied here to avoid inclusion of ctype.h
+ */
+static int
+isdigit(char ch)
+{
+ return ((ch >= '0') && (ch <= '9'));
+}
+
+/* proc_d_prefix():
+ * Deal with the characters prior to the 'd' format designator.
+ * For example, hdr would be '8' in the format %8d.
+ */
+static int
+proc_d_prefix(char *hdr, char *lbp)
+{
+ char fill;
+ int minsize, i;
+
+ minsize = 0;
+ if (hdr[0]) {
+ if (hdr[0] == '0')
+ fill = '0';
+ else
+ fill = ' ';
+ minsize = (short)atoi(hdr);
+ for(i=0;i<minsize;i++)
+ *lbp++ = fill;
+ }
+ return(minsize);
+}
+
+
+/* long_to_dec():
+ * Convert an incoming long value to ASCII decimal notation.
+ */
+int
+long_to_dec(long lval,char *buf,char *bufend,char *hdr)
+{
+ unsigned long value;
+ short size, i, minsize;
+ char lbuf[MAX_NUMBER_SIZE], *lbp;
+
+ lbp = lbuf;
+ minsize = proc_d_prefix(hdr,lbuf);
+
+ /* First determine how many ascii digits are needed. */
+ value = abs(lval);
+ size = 0;
+ while (value > 0) {
+ size++;
+ value /= 10;
+ }
+ if (lval < 0)
+ size++;
+ if (minsize > size)
+ size = minsize;
+ lbp += size;
+
+ /* Now build the string. */
+ value = abs(lval);
+ if (value == 0) {
+ if (minsize==0) {
+ lbuf[0] = '0';
+ size = 1;
+ }
+ else
+ *--lbp = '0';
+ }
+ else {
+ while (value > 0) {
+ *--lbp = (char)((value % 10) + '0');
+ value /= 10;
+ }
+ }
+ if (lval < 0)
+ *--lbp = '-';
+ lbuf[size] = 0;
+
+ /* At this point, lbuf[] contains the ascii decimal string
+ * so we can now pass it through PROCCHAR...
+ */
+ for(i=0;i<size;i++) {
+ PROCCHAR(buf,bufend,lbuf[i]);
+ }
+ return((int)size);
+}
+
+/* llong_to_dec():
+ * Convert an incoming long long value to ASCII decimal notation.
+ * This is essentially identical to long_to_dec, but we use longlong.
+ */
+static int
+llong_to_dec(int64_t llval,char *buf,char *bufend,char *hdr)
+{
+ uint64_t value;
+ short size, i, minsize;
+ char lbuf[MAX_NUMBER_SIZE], *lbp;
+
+ lbp = lbuf;
+ minsize = proc_d_prefix(hdr, lbuf);
+
+ /* First determine how many ascii digits are needed. */
+ value = llval < 0 ? -llval : llval;
+ size = 0;
+ while (value > 0) {
+ size++;
+ value /= 10;
+ }
+ if (llval < 0)
+ size++;
+ if (minsize > size)
+ size = minsize;
+ lbp += size;
+
+ /* Now build the string. */
+ value = llval < 0 ? -llval : llval;
+ if (value == 0) {
+ if (minsize==0) {
+ lbuf[0] = '0';
+ size = 1;
+ }
+ else
+ *--lbp = '0';
+ }
+ else {
+ while (value > 0) {
+ *--lbp = (char)((value % 10) + '0');
+ value /= 10;
+ }
+ }
+ if (llval < 0)
+ *--lbp = '-';
+ lbuf[size] = 0;
+
+ /* At this point, lbuf[] contains the ascii decimal string
+ * so we can now pass it through PROCCHAR...
+ */
+ for(i=0;i<size;i++) {
+ PROCCHAR(buf,bufend,lbuf[i]);
+ }
+ return((int)size);
+}
+
+/* long_to_ip():
+ * Convert an incoming long value to an ascii IP formatted
+ * string (i.e. 0x01020304 is converted to "1.2.3.4")
+ */
+static int
+long_to_ip(long lval,char *buf,char *bufend,char *hdr)
+{
+ int i, j, len;
+ unsigned char *lp;
+
+ len = 0;
+ lp = (unsigned char *)&lval;
+ for(j=0;j<4;j++) {
+ i = long_to_dec(*lp++,buf,bufend,hdr);
+ BUFINC(buf,i);
+ if (j < 3) {
+ PROCCHAR(buf,bufend,'.');
+ }
+ len += (i + 1);
+ }
+ BUFDEC(buf,1);
+ len--;
+ return(len);
+}
+
+/* proc_x_prefix():
+ * Deal with the characters prior to the 'x' format designator.
+ * For example, hdr would be '02' in the format %02x.
+ */
+static int
+proc_x_prefix(char *hdr, char *lbp)
+{
+ int i, minsize;
+
+ minsize = 0;
+ if (hdr[0]) {
+ if (hdr[1]) {
+ minsize = (short)(hdr[1]&0xf);
+ for(i=0;i<minsize;i++)
+ *lbp++ = hdr[0];
+ }
+ else {
+ minsize = (short)(hdr[0]&0xf);
+ for(i=0;i<minsize;i++)
+ *lbp++ = ' ';
+ }
+ }
+ return(minsize);
+}
+
+/* long_to_hex():
+ * Convert an incoming long value to ASCII hexadecimal notation.
+ */
+static int
+long_to_hex(ulong lval,char *buf,char *bufend,char *hdr, char x)
+{
+ ulong value;
+ short size, i, minsize;
+ char lbuf[MAX_NUMBER_SIZE], *lbp;
+
+ lbp = lbuf;
+ minsize = proc_x_prefix(hdr,lbuf);
+
+ /* First determine how many ascii digits are needed. */
+ value = lval;
+ size = 0;
+ while (value > 0) {
+ size++;
+ value /= 16;
+ }
+ if (minsize > size)
+ size = minsize;
+ lbp += size;
+
+ /* Now build the string. */
+ if (lval == 0) {
+ if (size == 0)
+ size = 1;
+ else
+ lbp--;
+ *lbp = '0';
+ }
+ else {
+ while (lval > 0) {
+ if (x == 'X')
+ *--lbp = Hexdigits[(int)(lval % 16)];
+ else
+ *--lbp = hexdigits[(int)(lval % 16)];
+ lval /= 16;
+ }
+ }
+ lbp[size] = 0;
+
+ /* At this point, lbuf[] contains the ascii hex string
+ * so we can now pass it through PROCCHAR...
+ */
+ for(i=0;i<size;i++) {
+ PROCCHAR(buf,bufend,lbuf[i]);
+ }
+
+ return((int)size);
+}
+
+/* llong_to_hex():
+ * Convert an incoming long long value to ASCII hexadecimal notation.
+ */
+static int
+llong_to_hex(uint64_t llval,char *buf,char *bufend,char *hdr, char x)
+{
+ uint64_t value;
+ short size, i, minsize;
+ char lbuf[MAX_NUMBER_SIZE], *lbp;
+
+ lbp = lbuf;
+ minsize = proc_x_prefix(hdr,lbuf);
+
+ /* First determine how many ascii digits are needed. */
+ value = llval;
+ size = 0;
+ while (value > 0) {
+ size++;
+ value /= 16;
+ }
+ if (minsize > size)
+ size = minsize;
+ lbp += size;
+
+ /* Now build the string. */
+ if (llval == 0) {
+ if (size == 0)
+ size = 1;
+ else
+ lbp--;
+ *lbp = '0';
+ }
+ else {
+ while (llval > 0) {
+ if (x == 'X')
+ *--lbp = Hexdigits[(int)(llval % 16)];
+ else
+ *--lbp = hexdigits[(int)(llval % 16)];
+ llval /= 16;
+ }
+ }
+ lbp[size] = 0;
+
+ /* At this point, lbuf[] contains the ascii hex string
+ * so we can now pass it through PROCCHAR...
+ */
+ for(i=0;i<size;i++) {
+ PROCCHAR(buf,bufend,lbuf[i]);
+ }
+
+ return((int)size);
+}
+
+/* bin_to_mac():
+ * Convert an incoming buffer to an ascii MAC formatted
+ * string (i.e. buf[] = 010203040506 is converted to "01:02:03:04:05:06")
+ */
+static int
+bin_to_mac(uchar *ibin,char *buf,char *bufend)
+{
+ int i, j, len;
+
+ len = 0;
+ for(j=0;j<6;j++) {
+ i = long_to_hex(*ibin++,buf,bufend,"02",'x');
+ BUFINC(buf,i);
+ if (j < 5) {
+ PROCCHAR(buf,bufend,':');
+ }
+ len += (i + 1);
+ }
+ BUFDEC(buf,1);
+ len--;
+ return(len);
+}
+
+/* build_string():
+ * Build a string from 'src' to 'dest' based on the hdr and sign
+ * values. Return the size of the string (may include left or right
+ * justified padding).
+ */
+static int
+build_string(char *src,char *dest,char *bufend,char *hdr,int sign)
+{
+ char *cp1;
+ short minsize, i, j;
+
+ if (!src) {
+ cp1 = "NULL_POINTER";
+ while(*cp1) {
+ PROCCHARP(dest,bufend,cp1);
+ }
+ return(12);
+ }
+ if (!*src)
+ return(0);
+ if (!hdr[0]) {
+ j = 0;
+ while(*src) {
+ PROCCHARP(dest,bufend,src);
+ j++;
+ }
+ return(j);
+ }
+ minsize = (short)atoi(hdr);
+ i = 0;
+ cp1 = (char *)src;
+ while(*cp1) {
+ i++;
+ cp1++;
+ }
+ cp1 = (char *)src;
+ j = 0;
+ if (minsize > i) {
+ if (sign == POSITIVE) {
+ while(minsize > i) {
+ j++;
+ PROCCHAR(dest,bufend,' ');
+ minsize--;
+ }
+ while(*cp1) {
+ j++;
+ PROCCHARP(dest,bufend,cp1);
+ }
+ }
+ else {
+ while(*cp1) {
+ j++;
+ PROCCHARP(dest,bufend,cp1);
+ }
+ while(minsize > i) {
+ j++;
+ PROCCHAR(dest,bufend,' ');
+ minsize--;
+ }
+ }
+ }
+ else {
+ while(*cp1) {
+ j++;
+ PROCCHARP(dest,bufend,cp1);
+ }
+ }
+ return(j);
+}
+
+/* vsnprintf():
+ * Backend to all the others below it.
+ * Formats incoming argument list based on format string.
+ * Terminates population of buffer if it is to exceed the
+ * specified buffer size.
+ */
+int
+vsnprintf(char *buf,int bsize, char *fmt, va_list argp)
+{
+ long arg_l;
+ long long arg_ll;
+ int i, sign, tot;
+ char *cp, hdr[HDRSIZE], *base, *bufend, arg_c, *arg_cp, ll;
+
+ ll = 0;
+ tot = 0;
+ base = buf;
+
+ if (bsize == 0)
+ bufend = 0;
+ else
+ bufend = base+(bsize-1);
+
+ cp = fmt;
+ for(i=0;i<HDRSIZE;i++)
+ hdr[i] = 0;
+ while(*cp) {
+ if (*cp != '%') {
+ PROCCHARP(buf,bufend,cp);
+ tot++;
+ continue;
+ }
+ cp++;
+ if (*cp == '%') {
+ PROCCHARP(buf,bufend,cp);
+ tot++;
+ continue;
+ }
+ sign = POSITIVE;
+ if (*cp == '-') {
+ sign = NEGATIVE;
+ cp++;
+ }
+ if (isdigit(*cp)) {
+ for(i=0;i<(HDRSIZE-1);i++) {
+ if (isdigit(*cp))
+ hdr[i] = *cp++;
+ else
+ break;
+ }
+ }
+
+ ll = 0;
+ if (*cp == 'l') { /* Ignore the 'long' designator */
+ cp++;
+ if (*cp == 'l') { /* unless its the longlong designator */
+ cp++;
+ ll = 1;
+ }
+ }
+
+ switch(*cp) {
+ case 'c': /* Character conversion */
+ arg_c = (char)va_arg(argp,int);
+ PROCCHAR(buf,bufend,arg_c);
+ tot++;
+ break;
+ case 's': /* String conversion */
+ arg_cp = (char *)va_arg(argp,int);
+ i = build_string(arg_cp,buf,bufend,hdr,sign);
+ BUFINC(buf,i);
+ tot += i;
+ break;
+ case 'M': /* MAC address conversion */
+ arg_cp = (char *)va_arg(argp,int);
+ i = bin_to_mac((uchar *)arg_cp,buf,bufend);
+ BUFINC(buf,i);
+ tot += i;
+ break;
+ case 'I': /* IP address conversion */
+ arg_l = (long)va_arg(argp,int);
+ i = long_to_ip(arg_l,buf,bufend,hdr);
+ BUFINC(buf,i);
+ tot += i;
+ break;
+ case 'd': /* Decimal conversion */
+ case 'u':
+ if (ll) {
+ arg_ll = (long long)va_arg(argp,long long);
+ i = llong_to_dec(arg_ll,buf,bufend,hdr);
+ }
+ else {
+ arg_l = (long)va_arg(argp,int);
+ i = long_to_dec(arg_l,buf,bufend,hdr);
+ }
+ BUFINC(buf,i);
+ tot += i;
+ break;
+ case 'p': /* Hex conversion */
+ case 'x':
+ case 'X':
+ if (*cp == 'p') {
+ PROCCHAR(buf,bufend,'0');
+ PROCCHAR(buf,bufend,'x');
+ }
+ if (ll) {
+ arg_ll = (long long)va_arg(argp,long long);
+ i = llong_to_hex(arg_ll,buf,bufend,hdr,*cp);
+ }
+ else {
+ arg_l = (long)va_arg(argp,int);
+ i = long_to_hex((ulong)arg_l,buf,bufend,hdr,*cp);
+ }
+ BUFINC(buf,i);
+ tot += i;
+ break;
+ default:
+ PROCCHARP(buf,bufend,cp);
+ tot++;
+ break;
+ }
+ cp++;
+
+ if (hdr[0]) {
+ for(i=0;i<HDRSIZE;i++)
+ hdr[i] = 0;
+ }
+ }
+ PROCCHAR(buf,bufend,0);
+ return(tot);
+}
+
+/* snprintf(), sprintf(), printf() & cprintf():
+ * All functions use vsnprintf() to format a string.
+ * The string is either transferred to a buffer or transferred
+ * directly to this target's console through putchar (refer to
+ * the macros at the top of this file).
+ *
+ * - sprintf() formats to a buffer.
+ * - printf() formats to stdio.
+ * - cprintf() formats to a buffer, then centers the content of
+ * the buffer based on its size and a console screen with of
+ * SCREENWIDTH characters.
+ */
+int
+snprintf(char *buf, int bsize, char *fmt, ...)
+{
+ int tot;
+ va_list argp;
+
+ va_start(argp,fmt);
+ tot = vsnprintf(buf,bsize,fmt,argp);
+ va_end(argp);
+ return(tot);
+}
+
+int
+sprintf(char *buf, char *fmt, ...)
+{
+ int tot;
+ va_list argp;
+
+ va_start(argp,fmt);
+ tot = vsnprintf(buf,0,fmt,argp);
+ va_end(argp);
+ return(tot);
+}
+
+int
+printf(char *fmt, ...)
+{
+ int tot;
+ va_list argp;
+
+ va_start(argp,fmt);
+ tot = vsnprintf(0,0,fmt,argp);
+ va_end(argp);
+ return(tot);
+}
+
+int
+cprintf(char *fmt, ...)
+{
+ int i, tot, spaces;
+ char pbuf[CMDLINESIZE];
+ va_list argp;
+
+ va_start(argp,fmt);
+ tot = vsnprintf(pbuf,CMDLINESIZE,fmt,argp);
+ va_end(argp);
+
+ if (tot < SCREENWIDTH) {
+ spaces = (SCREENWIDTH-tot)/2;
+ for(i=0;i<spaces;i++)
+ putchar(' ');
+ }
+ else
+ spaces = 0;
+
+ for(i=0;i<tot;i++)
+ putchar(pbuf[i]);
+
+ return(tot+spaces);
+}
diff --git a/main/common/msbin.h b/main/common/msbin.h
new file mode 100644
index 0000000..dd9650f
--- /dev/null
+++ b/main/common/msbin.h
@@ -0,0 +1,87 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * msbin.h:
+ *
+ * The following information was retrieved from the MSDN technical
+ * support web site...
+ *
+ * Windows CE Binary Image Data Format (.bin):
+ * The binary image file format organizes data by sections.
+ * Each section contains a section header that specifies the starting
+ * address, length, and checksum for that section. Romimage.exe writes
+ * data organized by logical sections, such as an application's text or
+ * .data region, to the .bin file. The image terminates with an image
+ * record header with the physical address and checksum set to zero.
+ * A configuration file formatted as a .bin file is small and fast.
+ * A .bin file is about half the size of an .sre file.
+ * This smaller size allows a .bin file to download faster than an
+ * .sre file when you are using the Windows CE Console Debug Shell
+ * tool (Cesh.exe).
+ *
+ * The following table shows the .bin file format.
+ *
+ * FIELD LENGTH DESCRIPTION
+ * (bytes)
+ * Sync bytes (optional) 7 Byte 0 is B, indicating a .bin file
+ * format. Bytes 1-6 are reserved
+ * and set to 0, 0, 0, F, F, \n.
+ * Or in hex: 0x4230303046460a
+ * Image header, consisting of:
+ * Image address 4 Start address of image.
+ * Image length 4 Length, in bytes, of image.
+ * One or more records of:
+ * Record address 4 Starting address of data record.
+ * If this value is zero, the record
+ * address is the end of the file,
+ * and record length contains the
+ * starting address of the image.
+ * Record length 4 Length of record data, in bytes.
+ * Record checksum 4 Signed 32-bit sum of record data bytes.
+ * Record data N Record data
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _MSBIN_H_
+#define _MSBIN_H_
+
+#define MSBIN_SYNC_SIZE 7
+#define MSBIN_SYNC_DATA "B000FF\n"
+
+#define MSBINFHDR struct msbin_imghdr
+#define MSBINSHDR struct msbin_record
+
+/* File header:
+ */
+struct msbin_imghdr {
+ ulong imageaddr;
+ ulong imagelen;
+};
+
+/* Section header:
+ */
+struct msbin_record {
+ ulong addr;
+ ulong len;
+ ulong csum;
+};
+
+#endif
diff --git a/main/common/nand.c b/main/common/nand.c
new file mode 100755
index 0000000..45e7483
--- /dev/null
+++ b/main/common/nand.c
@@ -0,0 +1,350 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * nand.c
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_NANDCMD
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+#include "nand.h"
+
+int nandVerbose;
+
+#define END_OF_NAND (BASE_OF_NAND+SIZE_OF_NAND-1)
+
+#ifdef FLASHRAM_BASE
+#ifndef NAND_TFSRAM_BASE
+#define NAND_TFSRAM_BASE FLASHRAM_BASE
+#endif
+#endif
+
+char *nandHelp[] = {
+ "Interface with Nand-Flash",
+ "-[v] {cmd} [cmd-specific args]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -v incrementing verbosity level",
+ "",
+ "Cmds:",
+ " init initialize interface",
+ " info show device info",
+#ifdef FLASHRAM_BASE
+ " tfsls list files directly out of SPI flash",
+ " tfsload copy NAND to TFSRAM",
+ " tfsstat show state of SPI flash",
+ " tfsstore copy TFSRAM to NAND",
+ " tfserase erase NAND space allocated to TFS",
+ " tfsrm {name} remove file directly out of NAND flash",
+ " tfsadd {name} [src sz] add file directly to NAND flash",
+#endif
+ " erase {addr len} erase block",
+ " read {addr dest len} read block",
+ " write {addr src len} write block",
+#endif
+ 0,
+};
+
+int
+nandCmd(int argc,char *argv[])
+{
+ unsigned long addr;
+ char *cmd, *dest, *src;
+ int opt, len, rc;
+
+ rc = 0;
+ nandVerbose = 0;
+ while((opt=getopt(argc,argv,"v")) != -1) {
+ switch(opt) {
+ case 'v':
+ nandVerbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind+1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (nandVerbose)
+ printf("CMD: %s\n",cmd);
+
+ if (strcmp(cmd,"init") == 0) {
+ nandInit();
+ }
+ else if (strcmp(cmd,"info") == 0) {
+ nandInfo();
+ }
+ else if (strcmp(cmd,"erase") == 0) {
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ len = (int)strtol(argv[optind+2],0,0);
+ nandEraseChunk((char *)addr,len);
+ }
+ else if (strcmp(cmd,"write") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ src = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ nandWriteChunk((char *)addr,src,len);
+ }
+ else if (strcmp(cmd,"read") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ dest = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ nandReadChunk((char *)addr,dest,len);
+ }
+#ifdef FLASHRAM_BASE
+ else if (strcmp(cmd,"tfsload") == 0) {
+ }
+ else if (strcmp(cmd,"tfsstore") == 0) {
+ }
+ else if (strcmp(cmd,"tfserase") == 0) {
+ }
+ else if (strcmp(cmd, "tfsls") == 0) {
+ int ftot;
+ char *addr;
+ TFILE tfshdr, *fp;
+
+ ftot = 0;
+ fp = &tfshdr;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ char fbuf[32], *flags;
+
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+ if (TFS_FILEEXISTS(fp)) {
+ if (ftot == 0)
+ printf(" Name Size Offset Flags Info\n");
+ ftot++;
+ flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf);
+ if ((!flags) || (!fbuf[0]))
+ flags = " ";
+ printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp),
+ TFS_SIZE(fp),(unsigned long)(addr+TFSHDRSIZ),
+ flags,TFS_INFO(fp));
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsrm") == 0) {
+ char *addr;
+ TFILE tfshdr, *fp;
+ char *arg2 = argv[optind+1];
+
+ fp = &tfshdr;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff) {
+ printf("%s not found\n",arg2);
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ fp->flags &= ~TFS_ACTIVE;
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ break;
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsadd") == 0) {
+ int size;
+ long bflags;
+ TFILE tfshdr, *fp;
+ char *addr;
+ char *src, *name, *info;
+ char *arg2 = argv[optind+1];
+ char *arg3 = argv[optind+2];
+ char *arg4 = argv[optind+3];
+ char *icomma, *fcomma;
+
+ info = "";
+ bflags = 0;
+ name = arg2;
+ addr = (char *)BASE_OF_NAND;
+
+ /* The incoming arguments can be either just the filename (in which
+ * case we assume the source is the file in TFS with the same name),
+ * or the filename, source address and size...
+ */
+ if (argc == optind+2) { // Just filename?
+ if ((fp = tfsstat(name)) == (TFILE *)0) {
+ printf("File '%s' not in TFS\n",name);
+ return(CMD_FAILURE);
+ }
+ name = fp->name;
+ info = fp->info;
+ bflags = fp->flags;
+ size = fp->filsize;
+ src = (char *)(fp + 1);
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ }
+ else if (argc == optind+4) { // Filename with addr and len
+ // Extract flags and info fields (if any) from the name...
+ fcomma = strchr(name,',');
+ if (fcomma) {
+ icomma = strchr(fcomma+1,',');
+ if (icomma) {
+ *icomma = 0;
+ info = icomma+1;
+ }
+ *fcomma = 0;
+ bflags = tfsctrl(TFS_FATOB,(long)(fcomma+1),0);
+ }
+
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ size = (int)strtol(arg4,0,0);
+ src = (char *)strtoul(arg3,0,0);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ break;
+ if (fp->hdrsize == 0xffff) {
+ unsigned long nextfileaddr;
+
+ /* We're at the address in NAND where we can add the new
+ * file, but first we need to make sure there's enough
+ * room...
+ */
+ if ((TFSHDRSIZ + size + 16) >= ((char *)END_OF_NAND - addr)) {
+ printf(" not enough space\n");
+ return(CMD_FAILURE);
+ }
+
+ /* Copy name and info data to header.
+ */
+ strcpy(fp->name, name);
+ strcpy(fp->info, info);
+ fp->hdrsize = TFSHDRSIZ;
+ fp->hdrvrsn = TFSHDRVERSION;
+ fp->filsize = size;
+ fp->flags = bflags;
+ fp->flags |= (TFS_ACTIVE | TFS_NSTALE);
+ fp->filcrc = crc32((unsigned char *)src,size);
+ fp->modtime = tfsGetLtime();
+#if TFS_RESERVED
+ {
+ int rsvd;
+ for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
+ fp->rsvd[rsvd] = 0xffffffff;
+ }
+#endif
+ fp->next = 0;
+ fp->hdrcrc = 0;
+ fp->hdrcrc = crc32((unsigned char *)fp,TFSHDRSIZ);
+ nextfileaddr = NAND_TFSRAM_BASE - NAND_TFS_BASE + (long)addr + TFSHDRSIZ + size;
+ if (nextfileaddr & 0xf)
+ nextfileaddr = (nextfileaddr | 0xf) + 1;
+
+ fp->next = (TFILE *)nextfileaddr;
+
+ printf(" writing %s...\n",arg2);
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+
+ if ((rc = nandWriteChunk(addr+TFSHDRSIZ,src,size)) < 0)
+ printf(" write_file failed %d\n",rc);
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ printf(" removing %s...\n",arg2);
+ fp->flags &= ~TFS_ACTIVE;
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsstat") == 0) {
+ char *addr, *oaddr;
+ TFILE tfshdr, *fp;
+ unsigned long meminuse, memdead;
+
+ fp = &tfshdr;
+ meminuse = memdead = 0;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+
+ oaddr = addr;
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+
+ if (TFS_FILEEXISTS(fp))
+ meminuse += addr - oaddr;
+ else
+ memdead += addr - oaddr;
+ }
+ printf("Total: 0x%x, used: 0x%x, dead: 0x%x, avail: 0x%x\n",
+ SIZE_OF_NAND, meminuse, memdead,
+ SIZE_OF_NAND - (meminuse + memdead));
+ }
+#endif
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/nand.h b/main/common/nand.h
new file mode 100644
index 0000000..d3ee697
--- /dev/null
+++ b/main/common/nand.h
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * nand.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+extern int nandVerbose;
+extern int nandInit(void);
+extern int nandInfo(void);
+extern int nandEraseChunk(char *addr, int len);
+extern int nandReadChunk(char *src, char *dest, int len);
+extern int nandWriteChunk(char *src, char *dest, int len);
+
+
diff --git a/main/common/password.c b/main/common/password.c
new file mode 100644
index 0000000..94f8f9c
--- /dev/null
+++ b/main/common/password.c
@@ -0,0 +1,289 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * password:
+ *
+ * Code that supports the use of a password in the monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+
+#if INCLUDE_USRLVL
+
+extern char *crypt(char *,char *,char *);
+
+/* PASSWORD_FILE:
+ * The name of the file that is used to store passwords.
+ */
+#ifndef PASSWORD_FILE
+#define PASSWORD_FILE ".monpswd"
+#endif
+
+#define SALT0 'T'
+#define SALT1 'J'
+
+int
+passwordFileExists(void)
+{
+ if (tfsstat(PASSWORD_FILE))
+ return(1);
+ return(0);
+}
+
+/* backdoor():
+ * A mechanism that allows a password to be generated based on the
+ * MAC address of the board...
+ *
+ * Return 1 if the password matches the return of crypt(KEY,SALT).
+ * Where:
+ * KEY is an 8-character string created from the MAC address
+ * stored in the ETHERADD environment variable;
+ * SALT is a 2-character string made up of the first and last
+ * character of the ETHERADD env var;
+ */
+int
+backdoor(char *password)
+{
+ int i;
+ char *etherstr, salt[3], encryption[32];
+ unsigned char etherbin[9];
+
+ etherstr = getenv("ETHERADD");
+ if (!etherstr) /* just in case... */
+ etherstr = "00:00:00:00:00:00";
+
+ /* 2 salt characters are the first and last characters of etherstr: */
+ salt[0] = etherstr[0];
+ salt[1] = etherstr[strlen(etherstr)-1];
+ salt[2] = 0;
+
+ EtherToBin(etherstr,etherbin);
+ etherbin[6] = 'A';
+ etherbin[7] = 'a';
+ etherbin[8] = 0;
+
+ for(i=0;i<6;i++) {
+ while (etherbin[i] > 0x7e) {
+ etherbin[i] -= 0x20;
+ etherbin[6]++;
+ }
+ while (etherbin[i] < 0x20) {
+ etherbin[i] += 0x8;
+ etherbin[7]++;
+ }
+ }
+
+ crypt((char *)etherbin,salt,encryption);
+
+ /* Note that the first two characters of the return from crypt() */
+ /* are not used in the comparison... */
+ if (!strcmp(password,encryption+2))
+ return(1);
+ else
+ return(0);
+}
+
+/* validPassword():
+ * Called with a password and user level. There are a few different ways
+ * in which this can pass...
+ * 1. If there is no PASSWORD_FILE in TFS, return true.
+ * 2. If the password matches the backdoor entry, return true.
+ * 3. If the password matches appropriate entry in the password file,
+ * return true.
+ */
+
+int
+validPassword(char *password, int ulvl)
+{
+ char line[80];
+ int (*fptr)(void);
+ int tfd, lno, pass, lsize;
+
+ /* If there is a password file, then use it.
+ * If there is no password file, then call extValidPassword() to
+ * support systems that store the password some other way.
+ * The extValidPassword() function should return 0 if password check
+ * failed, 1 if the check succeeded and -1 if there is no external
+ * password storage hardware.
+ * Finally, if there is no password file, AND there is no external
+ * password storage hardware, then just return 1 to
+ * indicate that ANY password is a valid password. In other words...
+ * the password protection stuff is only enabled if you have a password
+ * stored away somewhere.
+ */
+ if (!passwordFileExists()) {
+ static int warning;
+
+ switch(extValidPassword(password,ulvl)) {
+ case 0: /* Password check failed. */
+ return(0);
+ case 1: /* Password check passed. */
+ return(1);
+ default: /* No external password check in use. */
+ break;
+ }
+ if (!warning) {
+ printf("WARNING: no %s file, security inactive.\n",PASSWORD_FILE);
+ warning = 1;
+ }
+ return(1);
+ }
+
+ /* First check for backdoor entry... */
+ if (backdoor(password))
+ return(1);
+
+ /* Incoming user level must be in valid range... */
+ if ((ulvl < MINUSRLEVEL) || (ulvl > MAXUSRLEVEL))
+ return(0);
+
+ /* If user level is MINUSRLEVEL, there is no need for a password. */
+ if (ulvl == MINUSRLEVEL)
+ return(1);
+
+ /* Check for a match in the password file...
+ * The PASSWORD_FILE dedicates one line for each user level.
+ * Line1 is password for user level 1.
+ * Line2 is password for user level 2.
+ * Line3 is password for user level 3.
+ * User level 0 doesn't require a password.
+ */
+
+ /* Force the getUsrLvl() function to return MAX: */
+ fptr = (int(*)(void))setTmpMaxUsrLvl();
+
+ tfd = tfsopen(PASSWORD_FILE,TFS_RDONLY,0);
+ if (tfd < 0) {
+ /* Restore the original getUsrLvl() functionality: */
+ clrTmpMaxUsrLvl(fptr);
+ printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,tfd,0));
+ return(0);
+ }
+
+ lno = 1;
+ pass = 0;
+ while((lsize=tfsgetline(tfd,line,sizeof(line)))) {
+ char encryption[32], salt[3];
+
+ if (lno != ulvl) {
+ lno++;
+ continue;
+ }
+
+ line[lsize-1] = 0; /* Remove the newline */
+
+ salt[0] = SALT0;
+ salt[1] = SALT1;
+ salt[2] = 0;
+
+ crypt(password,salt,encryption);
+
+ if (!strncmp(line,encryption+2,strlen(line)-2))
+ pass = 1;
+ break;
+ }
+ tfsclose(tfd,0);
+
+ /* Restore the original getUsrLvl() functionality: */
+ clrTmpMaxUsrLvl(fptr);
+
+ return(pass);
+}
+
+/* newPasswordFile():
+ * Prompt the user for three passwords. One for each user level.
+ * Then, after retrieving them, make sure the user wants to update
+ * the password file; if yes, do it; else abort.
+ */
+int
+newPasswordFile(void)
+{
+ int err, i;
+ char pswd1[16], pswd2[16];
+ char salt[3], *epwp, buf[32], epswd[34*3], flags[8];
+
+ /* For each of the three levels (1,2&3), get the password, encrypt it
+ * and concatenate newline for storate into the password file.
+ */
+
+ epwp = epswd;
+ for(i=1;i<4;i++) {
+ while(1) {
+ printf("Lvl%d ",i);
+ getpass("passwd: ",pswd1,sizeof(pswd1)-1,0);
+ if (strlen(pswd1) < 8) {
+ printf("password must be >= 8 chars.\n");
+ continue;
+ }
+ getpass("verify: ",pswd2,sizeof(pswd2)-1,0);
+ if (strcmp(pswd1,pswd2))
+ printf("Entries do not match, try again...\n");
+ else
+ break;
+ }
+ salt[0] = SALT0;
+ salt[1] = SALT1;
+ salt[2] = 0;
+ crypt(pswd1,salt,buf);
+ sprintf(epwp,"%s\n",&buf[2]);
+ epwp += strlen(epwp);
+ }
+
+ if (!askuser("Are you sure?"))
+ return(0);
+
+ err = tfsunlink(PASSWORD_FILE);
+ if ((err != TFS_OKAY) && (err != TFSERR_NOFILE)) {
+ printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,err,0));
+ return(-1);
+ }
+
+ sprintf(flags,"u%d",MAXUSRLEVEL);
+ err = tfsadd(PASSWORD_FILE,0, flags, (uchar *)epswd, strlen(epswd));
+ if (err != TFS_OKAY) {
+ printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,err,0));
+ return(-1);
+ }
+ return(0);
+}
+
+
+#ifndef EXT_VALID_PASSWORD
+/* extValidPassword():
+ * See validPassword() above for notes on the purpose of this function.
+ *
+ * This is the default stub, if a real extValidPassword() function is
+ * provided by the port, then EXT_VALID_PASSWORD should be defined in
+ * that port's config.h file.
+*/
+int
+extValidPassword(char *password, int ulvl)
+{
+ return(-1);
+}
+#endif /* EXT_VALID_PASSWORD */
+#endif /* INCLUDE_USRLVL */
diff --git a/main/common/pci.c b/main/common/pci.c
new file mode 100644
index 0000000..2dddb0f
--- /dev/null
+++ b/main/common/pci.c
@@ -0,0 +1,747 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * pci.c:
+ *
+ * This file provides the monitor with a reusable mechanism for
+ * interfacing with a PCI bus. Four target-specific functions are
+ * required:
+ *
+ * pciCtrl(), pciCfgRead(), pciCfgWrite(), pciShow()
+ *
+ * The two most important are pciCfgRead() and pciCfgWrite(). Refer to
+ * the bottom of pci.h for further details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "pci.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "cli.h"
+
+#if INCLUDE_PCI
+int pciVerbose;
+int pciBusNum;
+
+#define IMPLEMENTED 0x80000000
+
+#ifdef USE_DEFAULT_PCISHOW
+void
+pciShow(int interface)
+{
+ printf("No fixed devices on this platform\n");
+}
+#endif
+
+/* pciCfgAddress():
+ * Return a 32-bit value based on the input
+ * bus number, device number, function number and register
+ * number:
+ *
+ * 31 30 .... 24 23 ... 16 15 ... 11 10 .... 8 7 ... 2 1 0
+ * --------------------------------------------------------------
+ * | | | Bus | Device | Function | Register |0|T|
+ * |En| Reserved | Number | Number | Number | Number | | |
+ * --------------------------------------------------------------
+ * ^ ^
+ * |---- Enable bit 1=enabled, 0=disabled |
+ * |
+ * Type0: 0 --------------------------------------------|
+ * Type1: 1 --------------------------------------------|
+ *
+ * See pg 32 of the PCI2.2 spec for more details.
+ */
+
+unsigned long
+pciCfgAddress(int busno,int devno,int fncno,int regno)
+{
+ int type;
+
+ if (busno > 0)
+ type = 1;
+ else
+ type = 0;
+
+ return((type | PCICFG_ENABLE_BIT |
+ ((busno & PCICFG_BUSNO_MASK) << PCICFG_BUSNO_SHIFT) |
+ ((devno & PCICFG_DEVNO_MASK) << PCICFG_DEVNO_SHIFT) |
+ ((fncno & PCICFG_FNCNO_MASK) << PCICFG_FNCNO_SHIFT) |
+ ((regno & PCICFG_REGNO_MASK) << PCICFG_REGNO_SHIFT)));
+}
+
+/* pciBaseClass():
+ * Based on appendix D of spec, return a simple string that describes
+ * the base class of the incoming class code.
+ */
+char *
+pciBaseClass(unsigned long classcode)
+{
+ unsigned long baseclass;
+ unsigned long subclass_progif;
+
+ baseclass = (classcode >> 16) & 0xff;
+ subclass_progif = classcode & 0xffff;
+
+ switch(baseclass) {
+ case 0:
+ return("pre-class-code-definitions");
+ case 1:
+ return("mass storage ctrlr");
+ case 2:
+ return("network ctrlr");
+ case 3:
+ return("display ctrlr");
+ case 4:
+ return("multimedia device");
+ case 5:
+ return("memory ctrlr");
+ case 6: /* Supply additional information for bridge class...
+ */
+ switch(subclass_progif) {
+ case 0x0000:
+ return("host/pci bridge");
+ case 0x0100:
+ return("pci/isa bridge");
+ case 0x0200:
+ return("pci/eisa bridge");
+ case 0x0300:
+ return("pci/microchannel bridge");
+ case 0x0400:
+ return("pci/pci bridge");
+ case 0x0500:
+ return("pci/pcmcia bridge");
+ case 0x0600:
+ return("pci/nubus bridge");
+ case 0x0700:
+ return("pci/cardbus bridge");
+ case 0x8000:
+ return("other bridge type");
+ default:
+ return("bridge device");
+ }
+ case 7:
+ return("simple communication ctrlr");
+ case 8:
+ return("base system peripheral");
+ case 9:
+ return("input device");
+ case 10:
+ return("docking station");
+ case 11:
+ return("processor");
+ case 12:
+ return("serial bus ctrlr");
+ case 13:
+ return("wireless ctrlr");
+ case 14:
+ return("intelligent io ctrlr");
+ case 15:
+ return("satellite communication ctrlr");
+ case 16:
+ return("encrypt/decrypt ctrlr");
+ case 17:
+ return("data acquisition ctrlr");
+ case 256:
+ return("no fit");
+ default:
+ return("reserved");
+ }
+}
+
+/* pciscan():
+ * This function is used by "pci scan" and "pci enum" to look
+ * at the devices on the pci bus. When the enumerate flag is set,
+ * this function will recursively nest itself each time it sees a
+ * PCI-to-PCI bridge device on the bus, and while doing this, it will
+ * assign bus numbers to each bridge appropriately. This function does
+ * not assign address ranges or anything else, it simply provides a quick
+ * means of scanning all devices on the bus(es).
+ *
+ * NOTE: This has only been tested with simple PCI bus configurations (one
+ * bridge deep) so deeper configurations (bridges on bridges on bridges...)
+ * are untested as far as I know.
+ */
+void
+pciscan(long interface, long bus, long func, int showhdr, int enumerate)
+{
+ long device;
+ uchar hdr_type, rev_id;
+ ushort vendor_id, device_id;
+ ulong value, class_code;
+
+ if (showhdr) {
+ printf("\nInterface %ld...\n",interface);
+ printf("Bus Dev Vndr Dev Rev Hdr Class\n");
+ printf("Num Num Id Id Id Type Code\n");
+ }
+
+ if ((enumerate == 1) && (bus == 0))
+ pciBusNum = 0;
+
+ for(device=0;device<=31;device++) {
+ /* Retrieve portions of the configuration header that
+ * are required by all PCI compliant devices...
+ * Vendor, Device and Revision IDs, Class Code and Header Type
+ * (see pg 191 of spec).
+ */
+
+ /* Read reg_0 for vendor and device ids:
+ */
+ value = pciCfgRead(interface,bus,device,func,0);
+ if (value == NO_DEVICE)
+ continue;
+
+ vendor_id = (ushort)(value & 0xffff);
+ device_id = (ushort)((value>>16) & 0xffff);
+
+ /* Read reg_2 for class code and revision id:
+ */
+ value = pciCfgRead(interface,bus,device,func,2);
+ rev_id = (uchar)(value & 0xff);
+ class_code = (ulong)((value>>8) & 0xffffff);
+
+ /* Read reg_3: header type:
+ */
+ value = pciCfgRead(interface,bus,device,func,3);
+ hdr_type = (uchar)((value>>16) & 0xff);
+
+ printf("%2ld %02ld x%04x x%04x",bus,
+ device,vendor_id,device_id);
+ printf(" x%02x x%02x x%06lx (%s)\n",rev_id,
+ hdr_type,class_code,pciBaseClass(class_code));
+
+ /* If enumeration is enabled, see if this is a PCI-to-PCI
+ * bridge. If it is, then nest into pciscan...
+ */
+ if ((enumerate) && (class_code == 0x060400)) {
+ ulong pribus, secbus, subbus;
+
+ pribus = pciBusNum & 0x0000ff;
+ pciBusNum++;
+ secbus = ((pciBusNum << 8) & 0x00ff00);
+ subbus = ((pciBusNum << 16) & 0xff0000);
+
+ value = pciCfgRead(interface,bus,device,func,6);
+ value &= 0xffff0000;
+ value |= (pribus | secbus);
+ pciCfgWrite(interface,bus,device,func,6,value);
+
+ pciscan(interface,pciBusNum,func,0,1);
+
+ value = pciCfgRead(interface,bus,device,func,6);
+ value &= 0xff000000;
+ value |= (subbus | pribus | secbus);
+ pciCfgWrite(interface,bus,device,func,6,value);
+ }
+ }
+}
+
+/* getBarInfo():
+ * Apply the algorithm as specified in PCI spec...
+ * Place size information in sizehi & sizelo (to support 64-bit).
+ * Return 0 if not implemented; else return value to indicate
+ * size (32 or 64 bit) and type (mem or io).
+ */
+ulong
+getBarInfo(long interface,long bus,long device,long func,int barnum,
+ ulong *sizehi, ulong *sizelo)
+{
+ int barregno;
+ ulong implemented, barval1, barval2, barinfo1, barinfo2, cmd;
+
+ /* Translate the incoming bar number to a register number
+ * in PCI config space:
+ */
+ barregno = barnum + 4;
+
+ /* Disable decoding through the command register:
+ */
+ cmd = pciCfgRead(interface,bus,device,func,1);
+ pciCfgWrite(interface,bus,device,func,1,
+ cmd & ~(IO_SPACE | MEMORY_SPACE));
+
+ /* Read the BAR:
+ */
+ barval1 = pciCfgRead(interface,bus,device,func,barregno);
+
+ /* Write 0xffffffff to the BAR:
+ */
+ pciCfgWrite(interface,bus,device,func,barregno,0xffffffff);
+
+ /* Read the value returned as a result of writing
+ * 0xffffffff to the BAR:
+ */
+ barinfo1 = pciCfgRead(interface,bus,device,func,barregno);
+
+ /* Restore original bar:
+ */
+ pciCfgWrite(interface,bus,device,func,barregno,barval1);
+
+ if (barinfo1 == 0) {
+ implemented = 0;
+ }
+ else {
+ implemented = IMPLEMENTED;
+
+ if (barval1 & BASEADDRESS_IO) {
+ implemented |= BASEADDRESS_IO;
+
+ if (sizelo) {
+ /* Clear encoding bits:
+ */
+ barinfo1 &= 0xfffffffe;
+ /* Invert and add 1:
+ */
+ *sizelo = (~barinfo1 + 1) & 0xffff;
+
+ if (sizehi)
+ *sizehi = 0;
+ }
+ }
+ else {
+ implemented |= (barinfo1 & PREFETCHABLE);
+
+ if (barval1 & TYPE_64) {
+ implemented |= TYPE_64;
+
+ /* Apply same sequence as above to the next bar...
+ */
+ barregno++;
+ barval2 = pciCfgRead(interface,bus,device,func,barregno);
+ pciCfgWrite(interface,bus,device,func,barregno,0xffffffff);
+ barinfo2 = pciCfgRead(interface,bus,device,func,barregno);
+ pciCfgWrite(interface,bus,device,func,barregno,barval2);
+
+
+ if (sizelo) {
+ barinfo1 &= 0xfffffff0;
+ *sizelo = ~barinfo1 + 1;
+ if (sizehi)
+ *sizehi = ~barinfo2 + 1;
+ }
+ }
+ else {
+ if (sizelo) {
+ barinfo1 &= 0xfffffff0;
+ *sizelo = ~barinfo1 + 1;
+
+ if (sizehi)
+ *sizehi = 0;
+ }
+ }
+ }
+ }
+
+ /* Now that we've completed messing with the BARS,
+ * restore original cmd:
+ */
+ pciCfgWrite(interface,bus,device,func,1,cmd);
+
+ return(implemented);
+}
+
+int
+showBar(int barnum,long interface,long bus,long device,long func)
+{
+ int rtot;
+ ulong bar, barnext, sizehi, sizelo, implemented;
+
+ if ((barnum < 0) || (barnum > 5))
+ return(-1);
+
+ bar = pciCfgRead(interface,bus,device,func,barnum+4);
+
+ implemented = getBarInfo(interface,bus,device,func,
+ barnum,&sizehi,&sizelo);
+
+ if (!implemented) {
+ printf("%02d BAR%d : not implemented\n",barnum+4,barnum);
+ return(0);
+ }
+
+ printf("%02d BAR%d",barnum+4,barnum);
+ if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) {
+ barnext = pciCfgRead(interface,bus,device,func,barnum+5);
+ printf("-%d: 0x%08lx 0x%08lx", barnum+1,bar,barnext);
+ }
+ else {
+ printf(" : 0x%08lx",bar);
+ }
+
+ printf(" Size: 0x");
+ if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) {
+ printf("%08lx%08lx ",sizehi,sizelo);
+ rtot = 2;
+ }
+ else {
+ printf("%08lx ",sizelo);
+ rtot = 1;
+ }
+
+ if (bar & BASEADDRESS_IO) {
+ printf("IO");
+ }
+ else {
+ printf("MEM %sbit",bar & TYPE_64 ? "64" : "32");
+ }
+
+ if (bar & PREFETCHABLE)
+ printf(" prefetchable");
+
+ putchar('\n');
+ return(rtot);
+}
+
+void
+dumpRawCfg(long interface,long bus,long device,long func,char *range,
+ char* varname)
+{
+ int gotone;
+ long regno;
+ ulong value;
+
+ value = 0;
+ gotone = 0;
+ for(regno=0;regno<64;regno++) {
+ if (inRange(range,regno)) {
+ value = pciCfgRead(interface,bus,device,func,regno);
+ printf("Cfg reg #%02ld: 0x%08lx\n",regno,value);
+ gotone = 1;
+ }
+ }
+ if ((varname) && (gotone))
+ shell_sprintf(varname,"0x%08lx",value);
+}
+
+void
+dumpConfig(long interface,long bus,long device,long func)
+{
+ int i;
+ char *multifunc, *type;
+ ulong hdrtype, values[16];
+
+ for(i=0;i<16;i++)
+ values[i] = pciCfgRead(interface,bus,device,func,i);
+
+ hdrtype = values[3] & HDR_MASK;
+
+ if (hdrtype & HDR_MULTIFUNC) {
+ multifunc = "multi-function ";
+ hdrtype &= ~HDR_MULTIFUNC;
+ }
+ else {
+ multifunc = "";
+ }
+
+ switch(hdrtype) {
+ case HDR_PCI2PCI:
+ type = "PCI-to-PCI";
+ break;
+ case HDR_CARDBUS:
+ type = "CardBus";
+ break;
+ case HDR_STANDARD:
+ type = "Standard";
+ break;
+ default:
+ printf("dumpConfig(): hdrtype 0x%08lx not supported\n",hdrtype);
+ return;
+ }
+ printf("%s %sconfig...\n",type,multifunc);
+
+ printf("00 DevId/VendorId: 0x%04lx/%04lx\n",
+ (values[0] & 0xffff0000) >> 16,values[0] & 0xffff);
+
+ printf("01 Status/Command: 0x%04lx/%04lx\n",
+ (values[1] & 0xffff0000) >> 16,values[1] & 0xffff);
+
+ printf("02 ClassCode/RevId: 0x%06lx/%02lx\n",
+ (values[2] & 0xffffff00) >> 8,values[2] & 0xff);
+
+
+ printf("03 BIST/HdrType/LatencyTmr/CacheLnSz: 0x%02lx/%02lx/%02lx/%02lx\n",
+ (values[3] & 0xff000000) >> 24, (values[3] & 0xff0000) >> 16,
+ (values[3] & 0xff00) >> 8,values[3] & 0xff);
+
+ if (showBar(0,interface,bus,device,func) == 1)
+ showBar(1,interface,bus,device,func);
+
+ if (hdrtype == HDR_STANDARD) {
+ if (showBar(2,interface,bus,device,func) == 1)
+ showBar(3,interface,bus,device,func);
+ if (showBar(4,interface,bus,device,func) == 1)
+ showBar(5,interface,bus,device,func);
+
+ printf("10 Cardbus CIS Ptr: 0x%08lx\n",values[10]);
+ printf("11 SubSysId/SubVendorId: 0x%04lx/%04lx\n",
+ (values[11] & 0xffff0000) >> 16,values[11] & 0xffff);
+ printf("12 Expansion ROM BaseAddr: 0x%08lx\n",values[12]);
+ }
+ else if (hdrtype == HDR_PCI2PCI) {
+ printf("06 Secondary Latency Tmr: 0x%02lx\n",
+ (values[6] & 0xff000000) >> 24);
+ printf("06 BusNum Subordinate/Secondary/Primary: 0x%02lx/%02lx/%02lx\n",
+ (values[6] & 0xff0000) >> 16,
+ (values[6] & 0xff00) >> 8,values[6] & 0xff);
+
+ printf("07 Secondary Status: 0x%04lx\n",
+ (values[7] & 0xffff0000) >> 16);
+ printf("07 IO Limit/Base: 0x%02lx/%02lx\n",
+ (values[7] & 0xff00) >> 8,(values[7] & 0xff));
+
+ printf("08 Memory Limit/Base: 0x%04lx/%04lx\n",
+ (values[8] & 0xffff0000) >> 16,values[8] & 0xffff);
+
+ printf("09 Prefetchable Memory Limit/Base: 0x%04lx/%04lx\n",
+ (values[9] & 0xffff0000) >> 16,values[9] & 0xffff);
+
+ printf("10 Prefetchable Base Upper 32 bits: 0x%08lx\n",values[10]);
+ printf("11 Prefetchable Limit Upper 32 bits: 0x%08lx\n",values[11]);
+
+ printf("12 IO Upper 16 Bits Limit/Base: 0x%04lx/%04lx\n",
+ (values[12] & 0xffff0000) >> 16,values[12] & 0xffff);
+ }
+
+ printf("13 Capabilities Ptr: 0x%02lx\n",values[13] & 0xff);
+
+ if (hdrtype == HDR_STANDARD) {
+ printf("15 MaxLat/MinGnt: 0x%02lx/%02lx\n",
+ (values[15] & 0xff000000) >> 24, (values[15] & 0xff0000) >> 16);
+ }
+ else {
+ printf("14 Expansion ROM BaseAddr: 0x%08lx\n",
+ values[14]);
+ printf("15 BridgeControl: 0x%04lx\n",
+ (values[15] & 0xffff0000) >> 16);
+ }
+
+ printf("15 Interrupt Pin/Line: 0x%02lx/%02lx\n",
+ (values[15] & 0xff00) >> 8, values[15] & 0xff);
+}
+
+char *PciHelp[] = {
+ "PCI Config Interface",
+ "-[b:d:f:i:v] {operation} [args]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -b{###} bus #",
+ " -d{###} device #",
+ " -f{###} function #",
+ " -i{###} interface #",
+ " -v verbose",
+ "Operations:",
+ " scan, enum, bist, show, size {bar#}",
+ " crd [reg#] [varname], cwr {reg#} {value}",
+ "Note:",
+ " bus, device, function & interface default to zero",
+#endif
+ 0
+};
+
+/* PciCmd():
+ * General purpose command to provide access to the config portion of
+ * a PCI interface.
+ *
+ * Notice that there is reference to an "interface number" as well as a
+ * "bus number". In most systems, there will be one host-to-pci interface.
+ * and one pci bus. Some targets will have more than one host-to-pci
+ * interface (galileo 64260A, for example, has 2 distinct host-to-PCI
+ * interface). Some targets will have more than one bus (depends on whether
+ * or not there is a pci-to-pci bridge hanging off the bus).
+ *
+ */
+int
+PciCmd(int argc, char *argv[])
+{
+ ulong value, bar;
+ long bus, device, interface, regno, func;
+ int enumerate, opt;
+
+ bus = 0;
+ func = 0;
+ device = 0;
+ enumerate = 0;
+ interface = 0;
+ pciVerbose = 0;
+ while ((opt=getopt(argc,argv,"b:d:f:i:v")) != -1) {
+ switch(opt) {
+ case 'b':
+ bus = strtol(optarg,0,0);
+ break;
+ case 'd':
+ device = strtol(optarg,0,0);
+ break;
+ case 'f':
+ func = strtol(optarg,0,0);
+ break;
+ case 'i': /* Most systems will only have 1 interface */
+ interface = strtol(optarg,0,0);
+ break;
+ case 'v':
+ pciVerbose = 1;
+ break;
+ default:
+ return(CMD_FAILURE);
+ }
+ }
+
+ if (argc < optind+1)
+ return(CMD_PARAM_ERROR);
+
+ /* The "scan" and "enum" commands are very similar. They both use
+ * the pciscan() function.
+ *
+ * Scan: look at the devices on the specified bus.
+ * Enum: a recursive scan... start with bus 0 and attempt to query
+ * all devices on all busses, making the necessary bus-number assignments
+ * along the way.
+ */
+
+ /* For scan, the device number is ignored, all devices on a particular
+ * interface/bus are checked. If ths bus number is something other than
+ * zero, then this function assumes that the appropriate pci-to-pci
+ * bridge device has already had its bus numbers assigned.
+ */
+ if (!strcmp(argv[optind],"scan")) {
+ if (argc != optind+1)
+ return(CMD_PARAM_ERROR);
+
+ pciscan(interface,bus,func,1,0);
+ return(CMD_SUCCESS);
+ }
+
+ /* For enum, we start with bus 0, and attempt to enumerate all busses...
+ */
+ if (!strcmp(argv[optind],"enum")) {
+ if (argc != optind+1)
+ return(CMD_PARAM_ERROR);
+
+ pciscan(interface,0,func,1,1);
+ return(CMD_SUCCESS);
+ }
+
+ if (!strcmp(argv[optind],"size")) { /* See pg 204 of PCI2.2 spec */
+ int barnum;
+ ulong implemented, sizehi, sizelo;
+
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ /* The argument to size is the BAR #. The value can be a single
+ * digit or a range specification...
+ */
+ printf(" Bar Type Value Size\n");
+ for(barnum=0;barnum<6;barnum++) {
+ setenv("PCISIZE",0);
+ if (inRange(argv[optind+1],barnum)) {
+ /* Disable decoding through the command register:
+ * See section 6.2.2, pg 193.
+ */
+ value = pciCfgRead(interface,bus,device,func,1);
+ pciCfgWrite(interface,bus,device,0,1,
+ value & ~(IO_SPACE | MEMORY_SPACE));
+
+ bar = pciCfgRead(interface,bus,device,func,barnum+4);
+ implemented = getBarInfo(interface,bus,device,func,
+ barnum,&sizehi,&sizelo);
+
+ printf(" %d ",barnum);
+
+ if (implemented) {
+ shell_sprintf("PCISIZE","0x%08lx",bar);
+ printf("%s 0x%08lx ",
+ implemented & BASEADDRESS_IO ? "io " : "mem", bar);
+ if (implemented & TYPE_64)
+ printf("0x%08lx%08lx",sizehi,sizelo);
+ else
+ printf("0x%08lx",sizelo);
+ if (implemented & PREFETCHABLE)
+ printf(" (prefetchable)");
+ putchar('\n');
+ }
+ else
+ printf("not implemented\n");
+ }
+ }
+ }
+ else if (!strcmp(argv[optind],"bist")) {
+ if (argc != optind+1)
+ return(CMD_PARAM_ERROR);
+
+ value = pciCfgRead(interface,bus,device,func,3);
+
+ if (value & BIST_CAPABLE) {
+ /* Set the BIST_START bit to begin the test, then wait for
+ * the BIST_START bit to clear as an indication that the
+ * test has completed.
+ */
+ pciCfgWrite(interface,bus,device,func,3,value | BIST_START);
+ while(1) {
+ value = pciCfgRead(interface,bus,device,func,3);
+ if ((value & BIST_START) != BIST_START)
+ break;
+ }
+ if ((value & BIST_COMPCODE_MASK) != 0)
+ printf("BIST failed: 0x%lx\n",value & BIST_COMPCODE_MASK);
+ else
+ printf("BIST passed\n");
+ }
+ else {
+ printf("Device %ld is not BIST-capable\n",device);
+ }
+ }
+ else if (!strcmp(argv[optind],"crd")) {
+ char *varname = (char *)0;
+
+ if (argc == optind+3) { /* varname specified ? */
+ varname = argv[optind+2];
+ argc--;
+ }
+
+ if (argc == optind+2) {
+ dumpRawCfg(interface,bus,device,func,argv[optind+1],varname);
+ }
+ else if (argc == optind+1) {
+ dumpConfig(interface,bus,device,func);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ }
+ else if (!strcmp(argv[optind],"cwr")) {
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+
+ regno = strtol(argv[optind+1],0,0);
+ value = strtol(argv[optind+2],0,0);
+ pciCfgWrite(interface,bus,device,func,regno,value);
+ }
+ else if (!strcmp(argv[optind],"init")) {
+ pciCtrl(interface,PCICTRL_INIT,0,0);
+ }
+ else if (!strcmp(argv[optind],"show")) {
+ pciShow(interface);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/pci.h b/main/common/pci.h
new file mode 100644
index 0000000..dbb225b
--- /dev/null
+++ b/main/common/pci.h
@@ -0,0 +1,363 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * pci.h:
+ *
+ * GENERAL PCI Definitions.
+ * The majority of this is extracted from the PCI Local Bus Specification
+ * Revision 2.2.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ */
+
+/* Layout of configuration address register:
+ * See section 3.2.2.3.2 (Software Generation of Configuration
+ * Transactions, pg 32).
+ */
+#ifndef _PCI_H_
+#define _PCI_H_
+
+#define PCICFG_ENABLE_BIT 0x80000000
+#define PCICFG_BUSNO_MASK 0x000000ff
+#define PCICFG_BUSNO_SHIFT 16
+#define PCICFG_DEVNO_MASK 0x0000001f
+#define PCICFG_DEVNO_SHIFT 11
+#define PCICFG_FNCNO_MASK 0x00000007
+#define PCICFG_FNCNO_SHIFT 8
+#define PCICFG_REGNO_MASK 0x0000003f
+#define PCICFG_REGNO_SHIFT 2
+
+/* Command register layout (as it would be in the 32-bit register)
+ * See section 6.2.2 (Device Control, pg 193).
+ */
+#define FAST_BKTOBK_ENABLE 0x00000200
+#define SERR_ENABLE 0x00000100
+#define STEPPING_CTRL 0x00000080
+#define PARITY_ERROR_RESP 0x00000040
+#define VGA_PALETTE_SNOOP 0x00000020
+#define MEM_WRITE_INV_ENABLE 0x00000010
+#define SPECIAL_CYCLES 0x00000008
+#define BUS_MASTER 0x00000004
+#define MEMORY_SPACE 0x00000002
+#define IO_SPACE 0x00000001
+
+/* Status register layout (as it would be in the 32-bit register)
+ * See section 6.2.3 (Device Status, pg 196).
+ */
+#define DETECTED_PARITY_ERR 0x80000000
+#define SIGNALED_SYSTEM_ERR 0x40000000
+#define RECVD_MASTER_ABORT 0x20000000
+#define RECVD_TARGET_ABORT 0x10000000
+#define SIGNALED_TARGET_ABORT 0x08000000
+#define DEV_SEL_TIMING_MASK 0x06000000
+#define DEV_SEL_TIMING_FAST 0x00000000
+#define DEV_SEL_TIMING_MEDIUM 0x02000000
+#define DEV_SEL_TIMING_SLOW 0x04000000
+#define MASTER_DATA_PARITY_ERR 0x01000000
+#define FAST_BKTOBK_CAPABLE 0x00800000
+#define CAPABLE_66MHZ 0x00200000
+#define CAPABILITIES_LIST 0x00100000
+
+/* BaseAddressMapping
+ * See section 6.2.5.1 (Address Maps, pg 202).
+ */
+#define IMPLEMENTED 0x80000000
+#define BASEADDRESS_IO 0x00000001
+#define BASEADDRESS_MEM 0x00000000
+#define PREFETCHABLE 0x00000008
+#define TYPE_MASK 0x00000006
+#define TYPE_32 0x00000000
+#define TYPE_64 0x00000004
+
+/* HeaderType definitions, as they would be in the 32-bit register.
+ * See section 6.2.1, pg 192.
+ */
+#define HDR_MASK 0x00ff0000
+#define HDR_STANDARD 0x00000000
+#define HDR_PCI2PCI 0x00010000
+#define HDR_CARDBUS 0x00020000
+#define HDR_MULTIFUNC 0x00800000
+
+/* BIST bits, as they would be in the 32-bit register.
+ * See section 6.2.4 pg 199.
+ */
+#define BIST_CAPABLE 0x80000000
+#define BIST_START 0x40000000
+#define BIST_COMPCODE_MASK 0x0f000000
+
+/*-----------------------------------------------------------------------------
+ * Mappings for PCI memory and IO spaces
+ */
+
+/* Macros for getting an individual device or function from a combined
+ * device/function number
+ */
+#define PCI_MAKE_DEV_FUNC(_dev_, _func_) (((_dev_)<<3)|(_func_))
+#define PCI_GET_DEV(_dev_func_) ((_dev_func_ >> 3) & 0x1f)
+#define PCI_GET_FUNC(_dev_func_) (_dev_func_ & 0x7)
+
+/* Macros for BUS, FUNC and DEV in PCI_CFG_ADD
+ */
+#define PCI_CFG_BUS(_x_) ((_x_ & 0xff) << 16) /* Bus Number */
+#define PCI_CFG_DEV(_x_) ((_x_ & 0xf8) << 11) /* Device Number */
+#define PCI_CFG_FUNC(_x_) ((_x_ & 0x07) << 8) /* Function Number */
+#define PCI_CFG_REG(_x_) ((_x_ & 0xfc) << 0) /* Register Number */
+
+/*-----------------------------------------------------------------------------
+ * Configuration header offsets
+ *-----------------------------------------------------------------------------
+ */
+#define PCI_CFG_VEN_ID_REG 0x0
+#define PCI_CFG_DEV_ID_REG 0x2
+#define PCI_CFG_CMD_REG 0x4
+#define PCI_CFG_STAT_REG 0x6
+#define PCI_CFG_REV_REG 0x8
+#define PCI_CFG_IF_REG 0x9
+#define PCI_CFG_SUBCLASS_REG 0xa
+#define PCI_CFG_CLASS_REG 0xb
+#define PCI_CFG_HDR_TYPE_REG 0xe
+#define PCI_CFG_BIST_REG 0xf
+#define PCI_CFG_BAR0_REG 0x10
+#define PCI_CFG_BAR1_REG 0x14
+#define PCI_CFG_BAR2_REG 0x18
+#define PCI_CFG_BAR3_REG 0x1c
+#define PCI_CFG_BAR4_REG 0x20
+#define PCI_CFG_BAR5_REG 0x24
+#define PCI_CFG_CIS_REG 0x28 /* Cardbus only */
+#define PCI_CFG_SUB_VEN_ID_REG 0x2c
+#define PCI_CFG_SUB_DEV_ID_REG 0x2e
+#define PCI_CFG_ROM_BASE_REG 0x30
+#define PCI_CFG_RES0_REG 0x34
+#define PCI_CFG_RES1_REG 0x38
+#define PCI_CFG_INT_REG 0x3c
+#define PCI_CFG_CACHE_REG 0x3d
+#define PCI_CFG_GNT_REG 0x3e
+#define PCI_CFG_LAT_REG 0x3f
+
+/* bridge devices only
+ */
+#define PCI_CFG_BAR0_REG 0x10
+#define PCI_CFG_BAR1_REG 0x14
+#define PCI_CFG_PRI_BUS_REG 0x18
+#define PCI_CFG_SEC_BUS_REG 0x19
+#define PCI_CFG_SUB_BUS_REG 0x1a
+#define PCI_CFG_SEC_LAT_REG 0x1b
+#define PCI_CFG_IO_BASE_LO_REG 0x1c
+#define PCI_CFG_IO_LIMIT_LO_REG 0x1d
+#define PCI_CFG_MEM_BASE_REG 0x20
+#define PCI_CFG_MEM_LIMIT_REG 0x22
+#define PCI_CFG_PREFETCH_BASE_REG 0x24
+#define PCI_CFG_PREFETCH_LIMIT_REG 0x26
+#define PCI_CFG_IO_BASE_HI_REG 0x30
+#define PCI_CFG_IO_LIMIT_HI_REG 0x32
+
+/* CLASS Codes
+ */
+#define PCI_CLASS_OLD 0x00
+#define PCI_CLASS_MASS 0x01
+#define PCI_CLASS_NET 0x02
+#define PCI_CLASS_DISPLAY 0x03
+#define PCI_CLASS_MULTIMEDIA 0x04
+#define PCI_CLASS_MEMORY 0x05
+#define PCI_CLASS_BRIDGE 0x06
+#define PCI_CLASS_SIMPLE_COMM 0x07
+#define PCI_CLASS_BASE_PERIPH 0x08
+#define PCI_CLASS_INPUT 0x09
+#define PCI_CLASS_DOCK 0x0a
+#define PCI_CLASS_CPU 0x0b
+#define PCI_CLASS_SERIAL_BUS 0x0c
+#define PCI_CLASS_UNKNOWN 0xff
+
+/* BRIDGE SUBCLASS Codes
+ */
+#define PCI_SUBCLASS_BRIDGE_PCI_PCI 0x04
+
+/* BAR types
+ */
+#define PCI_MEM_BAR_TYPE_32BIT 0x00
+#define PCI_MEM_BAR_TYPE_1M 0x01
+#define PCI_MEM_BAR_TYPE_64BIT 0x02
+
+/* PCI Command Register bit defines
+ */
+#define PCI_CFG_CMD_IO 0x0001
+#define PCI_CFG_CMD_MEM 0x0002
+#define PCI_CFG_CMD_MASTER 0x0004
+#define PCI_CFG_CMD_SPECIAL 0x0008
+#define PCI_CFG_CMD_INVALIDATE 0x0010
+#define PCI_CFG_CMD_VGA_SNOOP 0x0020
+#define PCI_CFG_CMD_PARITY 0x0040
+#define PCI_CFG_CMD_WAIT 0x0080
+#define PCI_CFG_CMD_SERR 0x0100
+#define PCI_CFG_CMD_FAST_BACK 0x0200
+
+/* PCI Status Register bit defines
+ */
+#define PCI_CFG_STAT_PERR 0x8000 /* 1 = MPC8245 detected an */
+ /* addr or data parity error */
+#define PCI_CFG_STAT_SERR 0x4000 /* 1 = MPC8245 asserted SERR.*/
+#define PCI_CFG_STAT_MST_ABRT 0x2000 /* 1 = MPC8245 asserted */
+ /* master-abort. */
+#define PCI_CFG_STAT_TGT_ABRT_MST 0x1000 /* 1 = MPC8245 received a */
+ /* target-abort while acting */
+ /* as a PCI master. */
+#define PCI_CFG_STAT_TGT_ABRT_TGT 0x0800 /* 1 = MPC8245 asserted a */
+ /* target-abort while acting */
+ /* as a PCI target. */
+#define PCI_CFG_STAT_PERR_DAT 0x0100 /* 1 = MPC8245 detected a */
+ /* data parity error while */
+ /* acting as a PCI master. */
+
+/*--------------------------------------------------------------------------
+ * Error messages from pci_probe_bus
+ */
+#define PCI_DEV_MAX_ERR 0x01 /* Ran out of space in */
+ /* static structure, is this */
+ /* really an error? */
+#define PCI_IO_BAR_MAX_ERR 0x02 /* IO Dev asked for too much space */
+#define PCI_IO_SPACE_ERR 0x03 /* We ran out of IO space to give */
+#define PCI_MEM_BAR_TYPE_ERR 0x04 /* Unsupported BAR type */
+#define PCI_MEM_BAR_MAX_ERR 0x05 /* MEM Dev asked for too much space */
+#define PCI_MEM_SPACE_ERR 0x06 /* We ran out of MEM space to give */
+#define PCI_BRIDGE_TYPE_ERR 0x07 /* Unsupported PCI Bridge type */
+
+/* Probe limits
+ */
+#define PCI_IO_BAR_MAX 0x00100000 /* 1Mbyte IO Space per device */
+#define PCI_MEM_BAR_MAX 0x01000000 /* 16Mbyte MEM Space per device */
+#define PCI_DEV_MAX 31 /* 32 devices total */
+
+/*--------------------------------------------------------------------------
+ * Structure that gets filled in by pci_bus_probe
+ */
+typedef struct /* PCI device data */
+{
+ unsigned short ven_id; /* vendor ID */
+ unsigned short dev_id; /* device ID */
+ unsigned char class; /* device Class */
+ unsigned char subclass; /* device Subclass */
+ unsigned long bar_size[6]; /* Memory size for each base address, */
+ /* 0 for unused BAR's */
+ unsigned long bar_map[6]; /* Physical address mapped - */
+ /* 0 for unused BAR's */
+ unsigned long func; /* The function number - usually 0 */
+ unsigned long dev; /* The device number */
+ unsigned long bus; /* The bus this device resides on. */
+ /* Non-0 means it's across a bridge */
+} pci_device_structure;
+
+
+/* See text of section 6.1 (Configuration Space Organization, pg 190) for an
+ * explanation of why 0xffff is used to indicate "no device" in a
+ * particular PCI slot. For all configuration space of a slot that is
+ * unoccupied, the PCI bridge device must return all ones.
+ *
+ * (Note that read accesses to unused registers within a valid PCI device
+ * should return 0).
+ */
+#define NO_DEVICE 0xffffffff
+
+
+/* Commands used by pciCtrl():
+ */
+#define PCICTRL_INIT 1
+
+/* Functions in pci.c:
+ */
+extern int pciVerbose;
+extern unsigned long pciCfgAddress(int busno,int devno,int fncno,int regno);
+extern char *pciBaseClass(unsigned long classcode);
+
+/****************************************************************************
+ *
+ * Functions needed by pci.c, that must be defined in the target
+ * specific source code:
+ */
+/* pciCtrl()
+ * Parameters:
+ * int interface-
+ * This parameter supports the case where the target hardware has more
+ * than one pci controller. The interface number would correspond to
+ * one of potentially several different controllers.
+ * int cmd-
+ * Command to be carried out by the control function.
+ * ulong arg1-
+ * First command-specific argument.
+ * ulong arg2-
+ * Second command-specific argument.
+ */
+extern int pciCtrl(int interface,int cmd,unsigned long arg1,unsigned long arg2);
+
+/* pciCfgWrite()
+ * Parameters:
+ * int interface-
+ * Refer to description in pciCtrl() above.
+ * int bus-
+ * Bus number.
+ * int dev-
+ * Device number on bus.
+ * int func-
+ * Function number on device.
+ * int reg-
+ * Register number to be written. Each reg number represents one 32-bit
+ * chunk of space in the configuration; hence, reg0 is offset 0, reg1 is
+ * offset 4, reg2 is offset 8, etc...
+ * ulong val-
+ * Value to be written into the specified config location.
+ * Return:
+ * int
+ * Return negative if failure, else 0.
+ */
+extern int pciCfgWrite(int interface,int bus,int dev,int func,int reg,
+ unsigned long val);
+
+/* pciCfgRead()
+ * Parameters:
+ * int interface-
+ * Refer to description in pciCtrl() above.
+ * int bus-
+ * Bus number.
+ * int dev-
+ * Device number on bus.
+ * int func-
+ * Function number on device.
+ * int reg-
+ * Register number to be written. Each reg number represents one 32-bit
+ * chunk of space in the configuration; hence, reg0 is offset 0, reg1 is
+ * offset 4, reg2 is offset 8, etc...
+ * Return:
+ * ulong
+ * Return the value stored in the specified config location.
+ */
+extern unsigned long pciCfgRead(int interface,int bus,int dev,
+ int func,int reg);
+
+/* pciShow()
+ * If appropriate, dump text to the user that verbosely describes the
+ * devices on the PCI bus. If the devices on the bus are not fixed, then
+ * this function should return a message indicating that.
+ *
+ * Parameters:
+ * int interface-
+ * Refer to description in pciCtrl() above.
+ */
+extern void pciShow(int interface);
+
+#endif
diff --git a/main/common/redirect.c b/main/common/redirect.c
new file mode 100644
index 0000000..f9de297
--- /dev/null
+++ b/main/common/redirect.c
@@ -0,0 +1,265 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * redirect:
+ *
+ * This code supports the monitor's ability to redirect what was destined for
+ * the console to a block of memory in RAM. Enough data is maintained so
+ * that the block of memory can be transferred to a file using tfsadd().
+ *
+ * Description of redirection CLI syntax:
+ * > buffer_addr,buffer_size[,filename]
+ * >> [filename]
+ *
+ * - Single arrow starts up a redirection to some specified block of memory
+ * with a specified size. If the filename is specified, then the output
+ * of that single command is redirected to the buffer then transferred to
+ * the specified file in TFS. Any previously existent file of the same
+ * name is overwritten.
+ *
+ * - Double arrow with no argument says append output of this command to
+ * the previously established buffer.
+ *
+ * - Double arrow with an argument says append output of this command to
+ * the previously established buffer and then write that buffer to the
+ * specified filename. Once again, any previously existent file of the
+ * same name is overwritten.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include <ctype.h>
+#include "tfs.h"
+#include "tfsprivate.h"
+
+#if INCLUDE_REDIRECT
+
+/* Redirect states:
+ * ACTIVE: the current command has issued some redirection, so
+ * when RedirectCharacter() is called, it should copy the
+ * character to the redirect buffer.
+ * IDLE: the current command has not issued any redirection, so
+ * when RedirectCharacter() is called, it simply returns.
+ * UNINITIALIZED: the first call to >base,size[,file] has not been
+ * made so we don't have a buffer; hence we can't redirect anything.
+ */
+#define REDIRECT_UNINITIALIZED 0
+#define REDIRECT_ACTIVE 0x12345678
+#define REDIRECT_IDLE 0x87654321
+
+static int RedirectSize, RedirectState;
+static char *RedirectBase, *RedirectPtr, *RedirectEnd;
+static char RedirectFile[TFSNAMESIZE];
+
+/* getEnvVal():
+ * This function is used under the context of the redirection code
+ * because of the fact that the docommand() function processes the
+ * redirection arrow prior to converting shell variables.
+ * This is important because we want to support the ability to do
+ * something like...
+ *
+ * echo hello >$APPRAMBASE,100
+ *
+ * but we also want to allow a shell variable to contain a right
+ * arrow that is NOT processed by this redirection code.
+ */
+static ulong
+getEnvVal(char *ptr)
+{
+#if INCLUDE_SHELLVARS
+ char *v;
+
+ /* If the incoming string starts with a '$', then retrieve the
+ * value and then convert that to a long; otherwise, just convert
+ * the string to a long immediately.
+ */
+ if (*ptr == '$') {
+ v = shellsym_chk(*ptr,ptr+1,0,0,0);
+ if (!v)
+ return(0);
+ }
+ else
+ v = ptr;
+ return(strtoul(v,0,0));
+#else
+ return(0);
+#endif
+}
+
+int
+RedirectionCheck(char *cmdcpy)
+{
+ int inquote;
+ char *arrow, *base, *comma, *space;
+
+ base = cmdcpy;
+ arrow = (char *)0;
+
+ /* Parse the incoming command line looking for a right arrow.
+ * This parsing assumes that there will be no negated arrows
+ * (preceding backslash) after a non-negated arrow is detected.
+ * Note that a redirection arrow within a double-quote set is
+ * ignored. This allows a shell variable that contains a right arrow
+ * to be printed properly if put in double quotes.
+ * For example...
+ * set PROMPT "maint> "
+ * echo $PROMPT # This will generate a redirection syntax error
+ * echo "$PROMPT" # This won't.
+ */
+ inquote = 0;
+ while(*cmdcpy) {
+ if ((*cmdcpy == '"') && ((cmdcpy == base) || (*(cmdcpy-1) != '\\'))) {
+ inquote = inquote == 1 ? 0 : 1;
+ cmdcpy++;
+ continue;
+ }
+ if (inquote == 1) {
+ cmdcpy++;
+ continue;
+ }
+ if (*cmdcpy == '>') {
+ arrow = cmdcpy;
+ if (*(arrow-1) == '\\') {
+ strcpy(arrow-1,arrow);
+ cmdcpy = arrow+1;
+ arrow = (char *)0;
+ continue;
+ }
+ break;
+ }
+ cmdcpy++;
+ }
+ if (arrow == (char *)0)
+ return(0);
+
+ /* Remove the remaining text from the command line because it is to
+ * be used only by the redirection mechanism.
+ */
+ *arrow = 0;
+
+ /* Now parse the text after the first non-negated arrow. */
+ if (*(arrow+1) == '>') {
+ if (RedirectState == REDIRECT_UNINITIALIZED) {
+ printf("Redirection not initialized\n");
+ return(-1);
+ }
+ arrow += 2;
+ while(isspace(*arrow))
+ arrow++;
+ if (*arrow != 0) {
+ strncpy(RedirectFile,*arrow == '$' ? getenv(arrow+1) : arrow,
+ TFSNAMESIZE);
+ }
+ }
+ else {
+ RedirectPtr = RedirectBase = (char *)getEnvVal(arrow+1);
+ comma = strchr(arrow+1,',');
+ if (comma) {
+ RedirectSize = (int)getEnvVal(comma+1);
+ comma = strchr(comma+1,',');
+ if (RedirectSize <= 0) {
+ printf("Redirection size error: %d\n",RedirectSize);
+ return(-1);
+ }
+ RedirectEnd = RedirectBase + RedirectSize;
+ if (comma) {
+ space = strpbrk(comma," \t\r\n");
+ if (space)
+ *space = 0;
+ if (*(comma+1) == '$') {
+ if (getenv(comma+2))
+ strncpy(RedirectFile,getenv(comma+2),TFSNAMESIZE);
+ else
+ RedirectFile[0] = 0;
+ }
+ else
+ strncpy(RedirectFile,comma+1,TFSNAMESIZE);
+ }
+ else
+ RedirectFile[0] = 0;
+ }
+ else {
+ printf("Redirection syntax error\n");
+ return(-1);
+ }
+ }
+ RedirectState = REDIRECT_ACTIVE;
+ return(0);
+}
+
+/* RedirectCmdDone():
+ * As each command completes, this redirection mechanism must be notified.
+ * When this function is called (by docmd() after the command function has
+ * completed), if the RedirectFile[] array is populated, it transfers the
+ * buffer to the specified file; if the array is empty, then no TFS action
+ * is taken.
+ * The file specified in RedirectFile[] may have additional commas in it.
+ * They allow the filename to contain flags and info field.
+ */
+void
+RedirectionCmdDone(void)
+{
+
+ if (RedirectState != REDIRECT_UNINITIALIZED) {
+ RedirectState = REDIRECT_IDLE;
+ if (RedirectFile[0]) {
+ char *comma, *info, *flags;
+
+ comma = info = flags = (char *)0;
+ comma = strchr(RedirectFile,',');
+ if (comma) {
+ *comma = 0;
+ flags = comma+1;
+ comma = strchr(flags,',');
+ if (comma) {
+ *comma = 0;
+ info = comma+1;
+ }
+ }
+ tfsadd(RedirectFile,info,flags,(uchar *)RedirectBase,
+ (int)(RedirectPtr-RedirectBase));
+ RedirectFile[0] = 0;
+ RedirectPtr = RedirectBase;
+ }
+ }
+}
+
+/* RedirectCharacter():
+ * This function is called from putchar() in chario.c. It simply
+ * copies the incoming character to the redirection buffer.
+ */
+void
+RedirectCharacter(char c)
+{
+ if (RedirectState == REDIRECT_ACTIVE) {
+ if (RedirectPtr < RedirectEnd)
+ *RedirectPtr++ = c;
+ }
+}
+#else
+int
+RedirectionCheck(char *cmdcpy)
+{
+ return(0);
+}
+#endif
diff --git a/main/common/reg_cache.c b/main/common/reg_cache.c
new file mode 100644
index 0000000..1c6c794
--- /dev/null
+++ b/main/common/reg_cache.c
@@ -0,0 +1,218 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * reg_cache.c:
+ *
+ * Allow the user to display CPU registers that are locally cached
+ * when an exception is hit. These registers are not the currently
+ * active registers in the CPU context; rather, a copy of the context at
+ * the time of the most recent breakpoint or exception.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "genlib.h"
+#include <ctype.h>
+#include "stddefs.h"
+#include "regnames.c"
+#include "cli.h"
+
+/* The file regnames.c will contain a table of character pointers that
+ * corresond to registers that are stored away by the target's exception
+ * handler. The table of names and the order in which the registers are
+ * stored by the exception handler must be synchronized.
+ * An example table is as follows (taken from FADS-MPC860 target)...
+ *
+ * static char *regnames[] = {
+ * "R0", "R1", "R2", "R3",
+ * "R4", "R5", "R6", "R7",
+ * "R8", "R9", "R10", "R11",
+ * "R12", "R13", "R14", "R15",
+ * "R16", "R17", "R18", "R19",
+ * "R20", "R21", "R22", "R23",
+ * "R24", "R25", "R26", "R27",
+ * "R28", "R29", "R30", "R31",
+ * "MSR", "CR", "LR", "XER",
+ * "DAR", "DSISR", "SRR0", "SRR1",
+ * "CTR", "DEC", "TBL", "TBU",
+ * "SPRG0", "SPRG1", "SPRG2", "SPRG3",
+ * };
+ *
+ * The real definition of this array would be in the file regnames.c in
+ * the target-specific directory.
+ */
+
+#define REGTOT (sizeof regnames/sizeof(char *))
+
+/* regtbl[]:
+ * This array is used to store the actual register values. Storage
+ * is done by the target's exception handler and must match the order
+ * of the register names in the regnames[] array.
+ */
+ulong regtbl[REGTOT];
+
+void
+flushRegtbl(void)
+{
+ flushDcache((char *)regtbl,sizeof(regtbl));
+}
+
+/* regidx():
+ * Return an index into the regnames[] array that matches the
+ * incoming register name.
+ * If no match is found, print an error message and return -1.
+ */
+static int
+regidx(char *name)
+{
+ int i;
+
+ strtoupper(name);
+ for(i=0;i<REGTOT;i++) {
+ if (!strcmp(name,regnames[i])) {
+ return(i);
+ }
+ }
+ printf("Bad reg: '%s'\n",name);
+ return(-1);
+}
+
+/* putreg():
+ * Put the specified value into the specified register
+ * storage location.
+ */
+int
+putreg(char *name,ulong value)
+{
+ int idx;
+
+ if ((idx = regidx(name)) == -1)
+ return(-1);
+
+ regtbl[idx] = value;
+ return(0);
+}
+
+/* getreg():
+ * Retrieve the value of the specified register.
+ */
+int
+getreg(char *name,ulong *value)
+{
+ int idx;
+
+ if ((idx = regidx(name)) == -1)
+ return(-1);
+
+ *value = regtbl[idx];
+ return(0);
+}
+
+/* showregs():
+ * Dump the content of the register cache in a tabular format
+ * showing the entry in the regnames[] array and the corresponding
+ * entry in the regtbl[] array.
+ */
+void
+showregs(void)
+{
+ int i, j;
+
+ for(i=0;i<REGTOT;) {
+ for(j=0;((j<4) && (i<REGTOT));j++,i++)
+ printf("%6s=0x%08lx ",regnames[i],regtbl[i]);
+ printf("\n");
+ }
+}
+
+/* reginit():
+ * Clear the register cache.
+ */
+void
+reginit(void)
+{
+ int i;
+
+ for(i=0;i<REGTOT;i++)
+ regtbl[i] = 0;
+}
+
+#if INCLUDE_STRACE
+char *RegHelp[] = {
+ "Display/modify content of monitor's register cache",
+ "-[v:] [regname] [value]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -v {var} quietly load 'var' with register content",
+#endif
+ 0,
+};
+
+int
+Reg(int argc,char *argv[])
+{
+ ulong reg;
+ int opt, i, forscript;
+ char *varname, buf[32];
+
+ forscript = 0;
+ varname = (char *)0;
+ while((opt=getopt(argc,argv,"sv:")) != -1) {
+ switch(opt) {
+ case 's':
+ forscript = 1;
+ break;
+ case 'v':
+ varname = optarg;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc == optind) {
+ if (forscript) {
+ for(i=0;i<REGTOT;i++)
+ printf("reg %s 0x%lx\n",regnames[i],regtbl[i]);
+ }
+ else
+ showregs();
+ return(CMD_SUCCESS);
+ }
+ else if (argc == optind + 1) {
+ if (getreg(argv[optind],&reg) != -1) {
+ sprintf(buf,"0x%lx",reg);
+ if (varname)
+ setenv(varname,buf);
+ else
+ printf("%s = %s\n",argv[optind],buf);
+ }
+ }
+ else if (argc == optind + 2) {
+ putreg(argv[1],strtol(argv[optind+1],(char **)0,0));
+ }
+ else {
+ return(CMD_PARAM_ERROR);
+ }
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/sbrk.c b/main/common/sbrk.c
new file mode 100644
index 0000000..8d55679
--- /dev/null
+++ b/main/common/sbrk.c
@@ -0,0 +1,144 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * sbrk.c:
+ *
+ * Used by malloc to get memory from "somewhere".
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_MALLOC
+#include "genlib.h"
+#define NULL 0
+
+extern int releaseExtendedHeap(int);
+
+static long allocbuf[ALLOCSIZE/sizeof(long)];
+static char *allocp1;
+static char *ext_heapbase, *ext_heapspace, *ext_heapend;
+
+/* GetMemory():
+ * This function is called by the guts of malloc when it needs to expand
+ * the size of the heap. Initially, GetMemory() will allocate memory
+ * from a static array (allocbuf[]) that is allocated memory space when the
+ * monitor is built. If the variable ext_heapbase is non-zero
+ * at the point when GetMemory() runs out of space in allocbuf[], it
+ * will start allocating memory from the block pointed to by ext_heapspase
+ * and ext_heapsize.
+ * WARNING: this feature can only be used if the malloc()/free() code
+ * can handle the fact that memory within its heap will be different
+ * blocks of non-contiguous space.
+*/
+char *
+GetMemory(int n)
+{
+ if (!allocp1)
+ allocp1 = (char *)allocbuf;
+
+ /* First try to allocate from allocbuf[]... */
+ if (allocp1 + n <= (char *)allocbuf + ALLOCSIZE) {
+ allocp1 += n;
+ return (allocp1 - n);
+ }
+ /* Else try to allocated from the extended heap (if one)... */
+ else if (ext_heapbase) {
+ if (ext_heapspace + n <= ext_heapend) {
+ ext_heapspace += n;
+ return(ext_heapspace - n);
+ }
+ else {
+ return(NULL);
+ }
+ }
+ /* Else, no space left to allocate from. */
+ else {
+ return (NULL);
+ }
+}
+
+/* ExtendHeap():
+ * Called by the heap command to provide GetMemory() with more space.
+ * This function can be called through the monitor API.
+ */
+int
+extendHeap(char *start, int size)
+{
+ /* If the size is -1, then assume this is a release request. */
+ if (size == -1)
+ return(releaseExtendedHeap(0));
+
+ /* If extension is already loaded, then return -1 for failure. */
+ if (ext_heapbase)
+ return(-1);
+
+ if (inUmonBssSpace(start,start+size-1))
+ return(-2);
+
+ ext_heapbase = ext_heapspace = start;
+ ext_heapend = start + size;
+ return(0);
+}
+
+/* UnextendHeap():
+ * Called by the heap command to "undo" the memory extension.
+ */
+void
+unExtendHeap(void)
+{
+ ext_heapbase = ext_heapspace = ext_heapend = 0;
+}
+
+char *
+getExtHeapBase(void)
+{
+ return(ext_heapbase);
+}
+
+/* GetMemoryLeft():
+ * Return the amount of memory that has yet to be allocated from
+ * the static and extended heap (if one).
+*/
+int
+GetMemoryLeft(void)
+{
+ int spaceleft;
+
+ if (!allocp1)
+ allocp1 = (char *)allocbuf;
+
+ spaceleft = ((char *)allocbuf + ALLOCSIZE) - allocp1;
+
+ if (ext_heapbase)
+ spaceleft += (ext_heapend - ext_heapspace);
+
+ return(spaceleft);
+}
+
+#else
+
+int
+extendHeap(char *start, int size)
+{
+ return(-1);
+}
+
+#endif
diff --git a/main/common/sd.c b/main/common/sd.c
new file mode 100644
index 0000000..6d2857d
--- /dev/null
+++ b/main/common/sd.c
@@ -0,0 +1,561 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * sd.c:
+ *
+ * This code is the user interface portion of the sd (compact flash)
+ * command for uMon.
+ * This command is intended to be the "interface" portion of some
+ * other command (for example "fatfs"). Refer to the discussion in
+ * fatfs.c for more details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#if INCLUDE_SD
+#include "stddefs.h"
+#include "genlib.h"
+#include "cli.h"
+#include "timer.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "sd.h"
+
+struct sdinfo sdInfoTbl[SD_DEVTOT];
+char sdVerbose;
+static int sdInum; /* Interface number: to support multiple SD interfaces.
+ * Typically this will always be zero.
+ */
+
+
+static struct sdcmd sdCardCmdTbl[] = {
+ { GO_IDLE_STATE, R1_RLEN, R1 },
+ { SEND_OP_COND, R1_RLEN, R1 },
+ { SWITCH_FUNC, R1_RLEN, R1 },
+ { SEND_IF_COND, R7_RLEN, R7 },
+ { SEND_CSD, R1_RLEN, R1 },
+ { SEND_CID, R1_RLEN, R1 },
+ { STOP_TRANSMISSION, R1_RLEN, R1B },
+ { SEND_STATUS, R2_RLEN, R2 },
+ { SET_BLOCKLEN, R1_RLEN, R1 },
+ { READ_SINGLE_BLK, R1_RLEN, R1 },
+ { READ_MULTIPLE_BLK, R1_RLEN, R1 },
+ { WRITE_BLK, R1_RLEN, R1B },
+ { WRITE_MULTIPLE_BLK, R1_RLEN, R1B },
+ { PROGRAM_CSD, R1_RLEN, R1 },
+ { SET_WRITE_PROT, R1_RLEN, R1B },
+ { CLR_WRITE_PROT, R1_RLEN, R1B },
+ { SEND_WRITE_PROT, R1_RLEN, R1 },
+ { ERASE_WR_BLK_START_ADDR, R1_RLEN, R1 },
+ { ERASE_WR_BLK_END_ADDR, R1_RLEN, R1 },
+ { ERASE, R1_RLEN, R1B },
+ { LOCK_UNLOCK, R1_RLEN, R1 },
+ { APP_CMD, R1_RLEN, R1 },
+ { GEN_CMD, R1_RLEN, R1 },
+ { READ_OCR, R3_RLEN, R3 },
+ { CRC_ON_OFF, R1_RLEN, R1 },
+ { SD_SEND_OP_COND, R1_RLEN, R1 },
+ { -1,-1,-1 }
+};
+
+char *SdHelp[] = {
+ "Secure Digital Flash Interface",
+ "[options] {operation} [args]...",
+#if INCLUDE_VERBOSEHELP
+ "",
+ "Options:",
+ " -i ## interface # (default is 0)",
+ " -v additive verbosity",
+ "",
+ "Operations:",
+ " init [prefix]",
+ " cmd {cmdnum} [arg]",
+ " read {dest} {blk} {blktot}",
+ " write {blk} {dest} {blktot}",
+#endif
+ 0
+};
+
+int
+SdCmd(int argc, char *argv[])
+{
+ char *cmd, *buf, *prefix, varname[16];
+ int opt, verbose, sdret, blknum, blkcnt;
+
+ verbose = 0;
+ while ((opt=getopt(argc,argv,"i:v")) != -1) {
+ switch(opt) {
+ case 'i':
+ sdInum = atoi(optarg); /* sticky */
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind + 1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (sdInum >= SD_DEVTOT) {
+ printf("Configured to support %d SD interface%s\n",
+ SD_DEVTOT,SD_DEVTOT == 1 ? "" : "s");
+ return(CMD_FAILURE);
+ }
+
+ if (sdInstalled(sdInum) == 0) {
+ printf("SDCard not installed\n");
+ return(CMD_FAILURE);
+ }
+
+ if (strcmp(cmd,"init") == 0) {
+ sdret = sdInit(sdInum, verbose);
+ if (sdret < 0) {
+ printf("sdInit returned %d\n",sdret);
+ return(CMD_FAILURE);
+ }
+
+ // If prefix is specified, then load shell variables:
+ if (argc == optind+2) {
+ prefix = argv[optind+1];
+ if (strlen(prefix)+4 > sizeof(varname)) {
+ printf("prefix %s too long\n",prefix);
+ return(CMD_PARAM_ERROR);
+ }
+
+ sprintf(varname,"%s_RD",prefix);
+ shell_sprintf(varname,"0x%lx",(long)sdRead);
+
+ sprintf(varname,"%s_WR",prefix);
+ shell_sprintf(varname,"0x%lx",(long)sdWrite);
+ }
+
+ shell_sprintf("SD_BLKSIZE","0x%lx",SD_BLKSIZE);
+ }
+ else if (strcmp(cmd,"cmd") == 0) {
+ ulong cmdarg;
+ uchar resp[8];
+ int rtot, i, cmdnum;
+
+ cmdarg = 0;
+ memset((char *)resp,0xff,sizeof(resp));
+
+ if ((argc != (optind+2)) && (argc != (optind+3)))
+ return(CMD_PARAM_ERROR);
+
+ cmdnum = (uchar)strtoul(argv[optind+1],0,0);
+ if (argc == optind+3)
+ cmdarg = strtoul(argv[optind+2],0,0);
+ sdret = sdCardCmd(sdInum, cmdnum , cmdarg ,resp);
+ if (sdret < 0) {
+ printf("sdCardCmd returned %d\n",sdret);
+ return(CMD_FAILURE);
+ }
+
+ rtot = sdCmdrlen(cmdnum);
+
+ printf("CMD_%d resp: ",cmdnum);
+ for(i=0;i<rtot;i++)
+ printf("%02x ",resp[i]);
+ printf("\n");
+ }
+ else if (strcmp(cmd,"read") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+
+ buf = (char *)strtoul(argv[optind+1],0,0);
+ blknum = strtoul(argv[optind+2],0,0);
+ blkcnt = strtoul(argv[optind+3],0,0);
+
+ sdret = sdRead(sdInum,buf,blknum,blkcnt);
+ if (sdret < 0) {
+ printf("sdRead returned %d\n",sdret);
+ return(CMD_FAILURE);
+ }
+ }
+ else if (strcmp(cmd,"write") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ buf = (char *)strtoul(argv[optind+1],0,0);
+ blknum = strtoul(argv[optind+2],0,0);
+ blkcnt = strtoul(argv[optind+3],0,0);
+
+ sdret = sdWrite(sdInum,buf,blknum,blkcnt);
+ if (sdret < 0) {
+ printf("sdWrite returned %d\n",sdret);
+ return(CMD_FAILURE);
+ }
+ }
+ else {
+ printf("sd op <%s> not found\n",cmd);
+ return(CMD_FAILURE);
+ }
+
+ return(CMD_SUCCESS);
+}
+
+/* sdCmdrlen():
+ * Given the command number, return the response length.
+ */
+int
+sdCmdrlen(int cmd)
+{
+ struct sdcmd *sdp = sdCardCmdTbl;
+
+ while(sdp->cmd != -1) {
+ if (cmd == sdp->cmd)
+ return(sdp->rlen);
+ sdp++;
+ }
+ return(-1);
+}
+
+/* sdCmdrtype():
+ * Given the command number, return the response type.
+ */
+int
+sdCmdrtype(int cmd)
+{
+ struct sdcmd *sdp = sdCardCmdTbl;
+
+ while(sdp->cmd != -1) {
+ if (cmd == sdp->cmd)
+ return(sdp->rtype);
+ sdp++;
+ }
+ return(-1);
+}
+
+static char *months[] = {
+ "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+};
+
+void
+sdShowCID(uchar *cid)
+{
+ int year, mon;
+
+ printf(" Manufacturer ID: x%02x\n", cid[0]);
+ printf(" OEM/Application ID: x%02x%02x\n", cid[1],cid[2]);
+ printf(" Product name: %c%c%c%c%c\n",
+ cid[3],cid[4],cid[5],cid[6],cid[7]);
+ printf(" Product rev: x%02x\n", cid[8]);
+ printf(" Product serialno: x%02x%02x%02x%02x\n",
+ cid[9],cid[10],cid[11],cid[12]);
+
+ year = (((cid[13] & 0x0f) << 4) | ((cid[14] & 0xf0) >> 4));
+ mon = (cid[14] & 0x0f);
+ if ((mon < 1) || (mon > 12))
+ mon = 0;
+ printf(" Manufactured: %s/%d\n",months[mon],2000+year);
+}
+
+void
+sdShowCSD(uchar *csd)
+{
+ uchar csdver;
+ long long capacity;
+ int mult, csize, csm, rbl;
+ int blocknr, blocklen, i;
+
+ printf(" CSD Response: ");
+ for(i=0;i<16;i++)
+ printf("%02x ",csd[i]);
+ printf("\n");
+
+ mult = csize = csm = rbl = 0;
+
+ if ((csd[0] & 0xc0) == 0)
+ csdver = 1;
+ else if ((csd[0] & 0xc0) == 0x40)
+ csdver = 2;
+ else {
+ printf("Invalid CSD structure type\n");
+ return;
+ }
+
+ printf(" CSD version %d.0\n",csdver);
+ if (csdver == 1) {
+ rbl = csd[5] & 0x0f;
+ csize = ((csd[8] & 0xC0) >> 6);
+ csize |= (csd[7] << 2);
+ csize |= ((csd[6] & 0x03) << 10);
+ csm = (csd[9] & 0x03);
+ csm <<= 1;
+ csm |= ((csd[10] & 0x80) >> 7);
+
+ mult = (1 << (csm+2));
+ blocknr = (csize+1)*mult;
+ blocklen = (1 << rbl);
+ capacity = (long long)((long long)blocknr * (long long)blocklen);
+ //printf(" (csm=%d, csize=%d, rbl=%d, mult=%d, blknr=%d, blkln=%d)\n",
+ // csm, csize, rbl, mult, blocknr, blocklen);
+ }
+ else if (csdver == 2) {
+ rbl = csd[5] & 0x0f;
+ csize = (csd[7] & 0x3f) << 16;
+ csize |= (csd[8] << 8);
+ csize |= csd[9];
+ capacity = (long long)((long long)(csize + 1) * 512LL * 1024LL);
+ }
+ else {
+ printf(" Unrecognized CSD version.\n");
+ return;
+ }
+ printf(" Card capacity: %lld bytes\n",capacity);
+}
+
+/* sdGenericStartup():
+ * Called by the interface-specific sdInit() code to do the generic
+ * portion of the SD-Card initialization.
+ *
+ * Refer to the flowchart shown in figure 7.2 of the Simplified
+ * Physical Layer Specification for an overview of the initialization.
+ *
+ * The card wakes up in SD bus mode, so the first thing we need to d
+ * here (after the very basic initialization of the SPI pin config) is
+ * to get the card into SPI mode.
+ * By default, the card assumes CRC checking is disabled. The field used
+ * to hold the CRC is still part of the protocol, but it is ignored. If
+ * needed, the master can turn it on with CMD59.
+ */
+int
+sdGenericStartup(int interface)
+{
+ ulong hcs;
+ uchar resp[16], cid[16], csd[16];
+ int retry, rc, version;
+ struct elapsed_tmr tmr;
+ int check_pattern_retry = 2;
+
+ sdInfoTbl[interface].initialized = 0;
+
+ rc = 0;
+ check_pattern_retry = 2;
+
+ // Start with at least 74 clocks to powerup the card...
+ sdPowerup(10);
+
+ // Put card in SPI mode:
+
+ // This command always seems to fail on the first try after a
+ // powerup, so give it a few attempts...
+ for(retry=0;retry<3;retry++) {
+ if ((rc = sdCardCmd(interface,GO_IDLE_STATE,0,resp)) != -1)
+ break;
+ }
+
+ if (retry == 3) {
+ printf("\nSD GO_IDLE_STATE failed, card installed?\n");
+ return(-1);
+ }
+
+ // According to Physical Layer Simplified Spec (PLSS), it is mandatory
+ // for the host compliant to Version 2.00 to send CMD8 (SEND_IF_COND).
+ // If CMD8 is not recognized (illegal command), then we can assume that
+ // the card is version 1.00.
+ // The argument sent with the command is defined in section 4.3.13
+ // of the PLSS.
+ // The spec says that if the check-patter test fails, to retry...
+ do {
+ if ((rc = sdCardCmd(interface,SEND_IF_COND,SEND_IF_COND_ARG,resp)) == -1)
+ return(-1);
+
+ if (resp[0] & R1_ILLEGAL_CMD) {
+ version = VERSION_10;
+ hcs = 0;
+ break; // Check pattern only applies to V2 and later
+ }
+ else {
+ // The card should echo back the VHS and check pattern...
+ if (resp[3] != VHS27_36) {
+ if (sdVerbose & 2)
+ printf("SDCARD not 3.3v compliant!\n");
+ return(-1);
+ }
+ if (resp[4] != CHECK_PATTERN) {
+ if (--check_pattern_retry <= 0) {
+ if (sdVerbose & 2)
+ printf("SDCARD check-pattern failed.\n");
+ return(-1);
+ }
+ }
+ version = VERSION_20;
+ hcs = HCS;
+ }
+ } while(resp[4] != CHECK_PATTERN);
+
+ // Read OCR to make sure the card will run at 3.3v...
+ if ((rc = sdCardCmd(interface,READ_OCR,hcs,resp)) == -1)
+ return(-1);
+
+ if ((resp[2] & MSK_OCR_33) != MSK_OCR_33) {
+ if (sdVerbose & 2)
+ printf("SDCARD: OCR_33 failed, card isn't 3.3v capable\n");
+ return(-1);
+ }
+
+ // Wait for card to complete initialization:
+ startElapsedTimer(&tmr,1000);
+ while(1) {
+ if ((rc = sdCardCmd(interface,SD_SEND_OP_COND,HCS,resp)) == -1)
+ return(-1);
+ if ((resp[0] & R1_IDLE) == 0)
+ break;
+ if(msecElapsed(&tmr)) {
+ printf("SDCARD: gaveup waiting for init to complete.\n");
+ return(-1);
+ }
+ }
+
+ if (version == VERSION_20) {
+ // Get CCS...
+ if ((rc = sdCardCmd(interface,READ_OCR,0,resp)) == -1)
+ return(-1);
+ }
+ else {
+ if ((rc = sdCardCmd(interface,SET_BLOCKLEN,SD_BLKSIZE,resp)) == -1)
+ return(-1);
+ }
+
+ if (sdVerbose) {
+ printf("SD/SPI Initialized (version %s)\n",
+ version == VERSION_10 ? "1.0" : ">=2.0");
+ }
+
+ sdInfoTbl[interface].cardversion = version;
+
+ sdReadCxD(interface,cid,SEND_CID);
+ if (sdVerbose)
+ sdShowCID(cid);
+ sdReadCxD(interface,csd,SEND_CSD);
+ if (sdVerbose)
+ sdShowCSD(csd);
+
+ if ((csd[0] & 0xc0) == 0x00)
+ sdInfoTbl[interface].highcapacity = 0;
+ else
+ sdInfoTbl[interface].highcapacity = 1;
+
+ sdInfoTbl[interface].initialized = 1;
+ return(0);
+}
+
+/* Got this crc7 code off the web...
+ * The original text claimed "use-as-you-wish"...
+ */
+#define POLYNOM (0x9) // polynomical value to XOR when 1 pops out.
+
+static unsigned char
+Encode(uchar seed, uchar input, uchar depth)
+{
+ uchar regval, count, cc;
+
+ regval = seed;
+ cc = input;
+
+ for (count = depth ; count-- ; cc <<= 1) {
+ regval = (regval << 1) + ((cc & 0x80) ? 1 : 0);
+ if (regval & 0x80)
+ regval ^= POLYNOM;
+ }
+ return(regval & 0x7f); // return lower 7 bits of CRC as value to use.
+}
+
+uchar
+crc7(uchar seed, uchar *buf, int len)
+{
+ int i;
+ uchar crc;
+
+ crc = seed;
+ for (i = 0; i < len; i++)
+ crc = Encode(crc, buf[i], 8);
+
+ crc = Encode(crc,0,7);
+ crc = (crc << 1) + 1;
+ return(crc);
+}
+
+#ifdef INCLUDE_SD_DUMMY_FUNCS
+/* This code is included here just for simulating the SD
+ * interface (temporarily if a real one isn't ready. In a real system,
+ * the INCLUDE_SD_DUMMY_FUNCS definition would be off.
+ */
+
+int
+sdInit(int interface, int verbose)
+{
+ if (interface != 0)
+ return(-1);
+
+ return(0);
+}
+
+int
+sdRead(int interface, char *buf, int blk, int blkcnt)
+{
+ char *from;
+ int size;
+
+ if (interface != 0)
+ return(-1);
+
+ from = (char *)(blk * SD_BLKSIZE);
+ size = blkcnt * SD_BLKSIZE;
+ memcpy(buf,from,size);
+ return(0);
+}
+
+int
+sdWrite(int interface, char *buf, int blk, int blkcnt)
+{
+ char *to;
+ int size;
+
+ if (interface != 0)
+ return(-1);
+
+ to = (char *)(blk * SD_BLKSIZE);
+ size = blkcnt * SD_BLKSIZE;
+ memcpy(to,buf,size);
+ return(0);
+}
+
+/* sdInstalled():
+ * Return 1 if installed, 0 if not installed or -1 if
+ * the hardware can't detect installation.
+ */
+int
+sdInstalled(int interface)
+{
+ return(-1);
+}
+
+#endif
+
+#endif
diff --git a/main/common/sd.h b/main/common/sd.h
new file mode 100644
index 0000000..67dcfcc
--- /dev/null
+++ b/main/common/sd.h
@@ -0,0 +1,237 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * sd.h:
+ *
+ * Header file supporting SD card interface command.
+ *
+ * Much of this information is extracted from the Physical Layer Simplified
+ * Specification Version 2.00 (PLSS) document.
+ *
+ * Note that as of this writing, this header file is limited in scope to
+ * SPI-based SD.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#ifndef SD_BLKSIZE
+#define SD_BLKSIZE 512
+#endif
+
+#define SPISD_LO_SPEED 400000
+#define SPISD_HI_SPEED 25000000
+
+#define VERSION_10 1
+#define VERSION_20 2
+
+#ifndef SD_DEVTOT
+#define SD_DEVTOT 1
+#endif
+
+#define MSK_OCR_33 0xC0
+
+// Fields used by SEND_IF_COND command:
+// (refer to section 4.3.13 of PLSS)
+#define VHS27_36 0x01
+#define CHECK_PATTERN 0xAA
+#define SEND_IF_COND_ARG (((long)VHS27_36 << 8) | CHECK_PATTERN)
+
+#define HCS 0x40000000 // High capacity support
+#define CCS 0x40000000 // Card capacity status
+
+
+/* Response type 1 (section 7.3.2.1 of PLSS):
+ */
+#define R1_RLEN 1
+#define R1_STARTBIT 0x80
+#define R1_PARAM_ERR 0x40
+#define R1_ADDRESS_ERR 0x20
+#define R1_ERASESEQ_ERR 0x10
+#define R1_CRC_ERR 0x08
+#define R1_ILLEGAL_CMD 0x04
+#define R1_ERASE_RESET 0x02
+#define R1_IDLE 0x01
+#define R1_ERRMASK (R1_PARAM_ERR | R1_ADDRESS_ERR | R1_ERASESEQ_ERR | R1_CRC_ERR | R1_ILLEGAL_CMD)
+
+
+/* Response type 2 (section 7.3.2.3 of PLSS):
+ */
+#define R2_RLEN 2
+#define R2H_STARTBIT R1_STARTBIT
+#define R2H_PARAM_ERR R1_PARAM_ERR
+#define R2H_ADDRESS_ERR R1_ADDRESS_ERR
+#define R2H_ERASESEQ_ERR R1_ERASESEQ_ERR
+#define R2H_CRC_ERR R1_CRC_ERR
+#define R2H_ILLEGAL_CMD R1_ILLEGAL_CMD
+#define R2H_ERASE_RESET R1_ERASE_RESET
+#define R2H_IDLE R1_IDLE
+#define R2L_OUTOFRANGE 0x80
+#define R2L_ERASEPARAM 0x40
+#define R2L_WPVIOLATION 0x20
+#define R2L_ECCFAILED 0x10
+#define R2L_CCERR 0x08
+#define R2L_ERROR 0x04
+#define R2L_WPES_LKFAIL 0x02
+#define R2L_CARDLOCKED 0x01
+
+/* Response type 3 (section 7.3.2.4 of PLSS):
+ * This is the card's response to the READ_OCR command.
+ * First byte is identical to R1, the remaining 4 bytes
+ * are the card's OCR register.
+ */
+#define R3_RLEN 5
+#define R3_STARTBIT R1_STARTBIT
+#define R3_PARAM_ERR R1_PARAM_ERR
+#define R3_ADDRESS_ERR R1_ADDRESS_ERR
+#define R3_ERASESEQ_ERR R1_ERASESEQ_ERR
+#define R3_CRC_ERR R1_CRC_ERR
+#define R3_ILLEGAL_CMD R1_ILLEGAL_CMD
+#define R3_ERASE_RESET R1_ERASE_RESET
+#define R3_IDLE R1_IDLE
+
+/* Reponsee R4 & R5 are reserved for IO mode.
+ */
+
+/* Response type 7 (section 7.3.2.6 of PLSS):
+ * This is the card's response to the SEND_IF_COND command.
+ * First bytes is identical to R1.
+ */
+#define R7_RLEN 5
+#define R7_STARTBIT R1_STARTBIT
+#define R7_PARAM_ERR R1_PARAM_ERR
+#define R7_ADDRESS_ERR R1_ADDRESS_ERR
+#define R7_ERASESEQ_ERR R1_ERASESEQ_ERR
+#define R7_CRC_ERR R1_CRC_ERR
+#define R7_ILLEGAL_CMD R1_ILLEGAL_CMD
+#define R7_ERASE_RESET R1_ERASE_RESET
+#define R7_IDLE R1_IDLE
+
+#define R7_CMDVSNMSK 0xf8 // upper 5 bits of 2nd byte of response
+#define R7_VAMSK 0x0f // lower 4 bits of 3nd byte of response
+
+
+/* Data response token (7.3.3.1 of PLSS):
+ */
+#define DRT_FIXEDMASK 0x11
+#define DRT_FIXED 0x10
+#define DRT_STATMASK 0x0e
+#define DRT_STATACCEPTED (0x2<<1)
+#define DRT_STATCRCERR (0x5<<1)
+#define DRT_STATWRITEERR (0x6<<1)
+
+
+/* Data error token:
+ */
+#define DET_ERROR 0x01
+#define DET_CCERR 0x02
+#define DET_ECCFAILED 0x04
+#define DET_OOR 0x08
+
+/* Start block token:
+ */
+#define START_BLOCK_TOKEN 0xfe
+#define START_BLKMBW_TOKEN 0xfc
+#define STOP_TRAN_TOKEN 0xfd
+
+
+#define R1 0x01
+#define R1B 0x81
+#define R2 0x02
+#define R3 0x03
+#define R7 0x07
+
+#define APP 0x1000
+#define CMD_APP(cmd) ((cmd & APP) ? 1 : 0)
+
+/* SD-Card command macros used by SPI mode:
+ * This definitions carry three pieces of information per macro:
+ * Response lenght, response type & command index.
+ */
+#define GO_IDLE_STATE 0
+#define SEND_OP_COND 1
+#define SWITCH_FUNC 6
+#define SEND_IF_COND 8
+#define SEND_CSD 9
+#define SEND_CID 10
+#define STOP_TRANSMISSION 12
+#define SEND_STATUS 13
+#define SET_BLOCKLEN 16
+#define READ_SINGLE_BLK 17
+#define READ_MULTIPLE_BLK 18
+#define WRITE_BLK 24
+#define WRITE_MULTIPLE_BLK 25
+#define PROGRAM_CSD 27
+#define SET_WRITE_PROT 28
+#define CLR_WRITE_PROT 29
+#define SEND_WRITE_PROT 30
+#define ERASE_WR_BLK_START_ADDR 32
+#define ERASE_WR_BLK_END_ADDR 33
+#define ERASE 38
+#define LOCK_UNLOCK 42
+#define APP_CMD 55
+#define GEN_CMD 56
+#define READ_OCR 58
+#define CRC_ON_OFF 59
+#define SD_SEND_OP_COND (41 | APP)
+
+
+/* struct sdcmd:
+ * Used to carry information about each of the commands handled
+ * by this driver for the SD-Memory Card interface.
+ */
+struct sdcmd {
+ int cmd;
+ int rlen;
+ int rtype;
+};
+
+/* struct sdinfo:
+ * Used to maintain some information about each of the interfaces.
+ * Note, in almost all cases, there will only be one SD-Card interface;
+ * however there is a table of these structures anyway.
+ */
+struct sdinfo {
+ char initialized;
+ char cardversion;
+ char highcapacity;
+};
+
+/* These two functions must be supplied by the port-specific code.
+ */
+extern char sdVerbose;
+extern void sdio_init(void);
+extern int sdCardCmd(int interface, int cmd, unsigned long arg,
+ unsigned char *resp);
+extern int sdInit(int interface, int verbosity);
+extern int sdRead(int interface, char *buf, int blknum, int blkcount);
+extern int sdWrite(int interface, char *buf, int blknum, int blkcount);
+extern int sdInstalled(int interface);
+extern int sdPowerup(int tot);
+extern int sdGenericStartup(int interface);
+extern int sdCmdrlen(int);
+extern int sdCmdrtype(int);
+extern void sdShowCID(uchar *cidbuf);
+extern void sdShowCSD(uchar *csdbuf);
+extern int sdReadCxD(int interface, unsigned char *buf, int cmd);
+extern unsigned char crc7(unsigned char seed, unsigned char *buf, int len);
+
+extern struct sdinfo sdInfoTbl[];
+
diff --git a/main/common/spif.c b/main/common/spif.c
new file mode 100644
index 0000000..3b8d91e
--- /dev/null
+++ b/main/common/spif.c
@@ -0,0 +1,456 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * spif.c:
+ *
+ * This is the generic portion of the spi-flash interface command.
+ * It assumes there is an underlying SPI-flash device interface
+ * that provides the expected API (see spif.h).
+ *
+ * The "tfs-specific" portions of this code support the model of having
+ * non-volatile TFS storage in SPI-flash that is transferred to RAM for
+ * general use, but also provides the ability to do the following:
+
+ * tfsload:
+ * Transfer a SPIF_TFS_SIZE area in SPI-flash from SPIF_TFS_BASE to
+ * FLASHRAM_BASE in RAM.
+ * tfserase:
+ * Erase the area in SPI-flash that is allocated to SPIF_TFS.
+ * tfsstore:
+ * Transfer the RAM-based TFS space back to SPI-flash.
+ * tfsls:
+ * List the files out of SPI_TFS directly.
+ * tfsrm:
+ * Mark a file in SPI_TFS as deleted.
+ * tfsadd:
+ * Append a file just after the last file currently stored in SPIF_TFS.
+ *
+ * NOTE: this does NOT support powersafe mode as of this writing.
+ *
+ * The spifmap.h file is port specific; hence would be part of the
+ * port directory.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "spif.h"
+#include "spifmap.h"
+
+
+static unsigned long spif_tfs_size;
+static unsigned long spif_tfs_base;
+static unsigned long base_of_serialtfs;
+static unsigned long end_of_serialtfs;
+
+#ifndef SPIF_TFSRAM_BASE
+#define SPIF_TFSRAM_BASE FLASHRAM_BASE
+#endif
+
+char *SpifHelp[] = {
+ "Interface with SPI-Flash",
+ "-[v] {cmd} [arg1] [arg2] [...]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -v incrementing verbosity level",
+ "",
+ "Cmds:",
+ " wen write enable",
+ " wfr wait-for-ready",
+ " stat show flash status register",
+ " gprot global protect",
+ " cerase chip erase",
+ " gunprot global unprotect",
+#if INCLUDE_TFS
+ " tfsls list files directly out of SPI flash",
+ " tfsload copy SPIF to TFSRAM",
+ " tfsstat show state of SPI flash",
+ " tfsstore copy TFSRAM to SPIF",
+ " tfserase erase SPIF space allocated to TFS",
+ " tfsrm {name} remove file directly out of SPI flash",
+ " tfsadd {name} [src sz] add file directly to SPI flash",
+#endif
+ " berase {addr bsize} block erase (bsize=4K,32K,64K)",
+ " read {addr dest len} read block",
+ " write {addr src len} write block",
+#endif
+ 0,
+};
+
+int
+SpifCmd(int argc,char *argv[])
+{
+ unsigned long addr;
+ char *cmd, *dest, *src;
+ int opt, verbose, len, bsize, rc;
+
+ spif_tfs_size = spifGetTFSSize();
+ spif_tfs_base = spifGetTFSBase();
+ base_of_serialtfs = spif_tfs_base;
+ end_of_serialtfs = spif_tfs_base + spif_tfs_size;
+
+ verbose = 0;
+ while((opt=getopt(argc,argv,"v")) != -1) {
+ switch(opt) {
+ case 'v':
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind+1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (verbose)
+ printf("CMD: %s\n",cmd);
+
+ // Establish the SPI configuration to match that of the SPI flash...
+ spifQinit();
+
+ if (strcmp(cmd,"stat") == 0) {
+ spifId(1);
+ spifReadStatus(verbose+1);
+ }
+ else if (strcmp(cmd,"gprot") == 0) {
+ spifGlobalProtect();
+ }
+ else if (strcmp(cmd,"berase") == 0) {
+
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+
+ addr = strtoul(argv[optind+1],0,0);
+
+ if (strcmp(argv[optind+2],"4K") == 0)
+ bsize = 0x1000;
+ else if (strcmp(argv[optind+2],"32K") == 0)
+ bsize = 0x8000;
+ else if (strcmp(argv[optind+2],"64K") == 0)
+ bsize = 0x10000;
+ else
+ return(CMD_PARAM_ERROR);
+
+ spifBlockErase(bsize,addr);
+ }
+ else if (strcmp(cmd,"cerase") == 0) {
+ spifChipErase();
+ }
+ else if (strcmp(cmd,"wfr") == 0) {
+ spifWaitForReady();
+ }
+ else if (strcmp(cmd,"gunprot") == 0) {
+ spifGlobalUnprotect();
+ }
+ else if (strcmp(cmd,"write") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ src = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ if ((rc = spifWriteBlock(addr,src,len)) < 0)
+ printf("spifWriteBlock returned %d\n",rc);
+
+ }
+ else if (strcmp(cmd,"read") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ dest = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ if ((rc = spifReadBlock(addr,dest,len)) < 0)
+ printf("spifReadBlock returned %d\n",rc);
+ }
+ else if (strcmp(cmd,"wen") == 0) {
+ spifWriteEnable();
+ }
+#if INCLUDE_TFS
+ else if (strcmp(cmd,"tfsload") == 0) {
+ rc = spifReadBlock(spif_tfs_base,(char *)FLASHRAM_BASE,spifGetTFSSize());
+ if (rc < 0)
+ printf("spifReadBlock returned %d\n",rc);
+ }
+ else if (strcmp(cmd,"tfsstore") == 0) {
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ rc = spifWriteBlock(spif_tfs_base,(char *)FLASHRAM_BASE,spifGetTFSSize());
+ if (rc < 0)
+ printf("spifWriteBlock returned %d\n",rc);
+ spifGlobalProtect();
+ }
+ else if (strcmp(cmd,"tfserase") == 0) {
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ addr = spif_tfs_base;
+ while (addr < (spif_tfs_base+spif_tfs_size)) {
+ spifWriteEnable();
+ rc = spifBlockErase(0x10000,addr);
+ if (rc < 0) {
+ printf("spifBlockErase(0x%lx) returned %d\n",addr,rc);
+ break;
+ }
+ if (verbose)
+ //ticktock();
+ printf("%lx ",addr);
+ addr += 0x10000;
+ }
+ spifGlobalProtect();
+ }
+ else if (strcmp(cmd, "tfsls") == 0) {
+ int ftot;
+ unsigned long addr;
+ TFILE tfshdr, *fp;
+
+ ftot = 0;
+ fp = &tfshdr;
+ addr = base_of_serialtfs;
+ while(addr < end_of_serialtfs) {
+ char fbuf[32], *flags;
+
+ if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("spifReadBlock failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+ if (TFS_FILEEXISTS(fp)) {
+ if (ftot == 0)
+ printf(" Name Size Offset Flags Info\n");
+ ftot++;
+ flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf);
+ if ((!flags) || (!fbuf[0]))
+ flags = " ";
+ printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp),
+ TFS_SIZE(fp),(unsigned long)(addr+TFSHDRSIZ),
+ flags,TFS_INFO(fp));
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while(addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsrm") == 0) {
+ unsigned long addr;
+ TFILE tfshdr, *fp;
+ char *arg2 = argv[optind+1];
+
+ fp = &tfshdr;
+ addr = base_of_serialtfs;
+ while(addr < end_of_serialtfs) {
+ if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("spifReadBlock failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff) {
+ printf("%s not found\n",arg2);
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ fp->flags &= ~TFS_ACTIVE;
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ spifGlobalProtect();
+ break;
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while(addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsadd") == 0) {
+ int size;
+ long bflags;
+ TFILE tfshdr, *fp;
+ unsigned long addr;
+ char *src, *name, *info;
+ char *arg2 = argv[optind+1];
+ char *arg3 = argv[optind+2];
+ char *arg4 = argv[optind+3];
+ char *icomma, *fcomma;
+
+ info = "";
+ bflags = 0;
+ name = arg2;
+ addr = base_of_serialtfs;
+
+ /* The incoming arguments can be either just the filename (in which
+ * case we assume the source is the file in TFS with the same name),
+ * or the filename, source address and size...
+ */
+ if (argc == optind+2) { // Just filename?
+ if ((fp = tfsstat(name)) == (TFILE *)0) {
+ printf("File '%s' not in TFS\n",name);
+ return(CMD_FAILURE);
+ }
+ name = fp->name;
+ info = fp->info;
+ bflags = fp->flags;
+ size = fp->filsize;
+ src = (char *)(fp + 1);
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ }
+ else if (argc == optind+4) { // Filename with addr and len
+ // Extract flags and info fields (if any) from the name...
+ fcomma = strchr(name,',');
+ if (fcomma) {
+ icomma = strchr(fcomma+1,',');
+ if (icomma) {
+ *icomma = 0;
+ info = icomma+1;
+ }
+ *fcomma = 0;
+ bflags = tfsctrl(TFS_FATOB,(long)(fcomma+1),0);
+ }
+
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ size = (int)strtol(arg4,0,0);
+ src = (char *)strtoul(arg3,0,0);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ while(addr < end_of_serialtfs) {
+ if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ break;
+ if (fp->hdrsize == 0xffff) {
+ unsigned long nextfileaddr;
+
+ /* We're at the address in SPIF where we can add the new
+ * file, but first we need to make sure there's enough
+ * room...
+ */
+ if ((TFSHDRSIZ + size + 16) >= (end_of_serialtfs - addr)) {
+ printf(" not enough space\n");
+ return(CMD_FAILURE);
+ }
+
+ /* Copy name and info data to header.
+ */
+ strcpy(fp->name, name);
+ strcpy(fp->info, info);
+ fp->hdrsize = TFSHDRSIZ;
+ fp->hdrvrsn = TFSHDRVERSION;
+ fp->filsize = size;
+ fp->flags = bflags;
+ fp->flags |= (TFS_ACTIVE | TFS_NSTALE);
+ fp->filcrc = crc32((unsigned char *)src,size);
+ fp->modtime = tfsGetLtime();
+#if TFS_RESERVED
+ {
+ int rsvd;
+ for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
+ fp->rsvd[rsvd] = 0xffffffff;
+ }
+#endif
+ fp->next = 0;
+ fp->hdrcrc = 0;
+ fp->hdrcrc = crc32((unsigned char *)fp,TFSHDRSIZ);
+ nextfileaddr = SPIF_TFSRAM_BASE - spif_tfs_base + addr + TFSHDRSIZ + size;
+ if (nextfileaddr & 0xf)
+ nextfileaddr = (nextfileaddr | 0xf) + 1;
+
+ fp->next = (TFILE *)nextfileaddr;
+
+ printf(" writing %s...\n",arg2);
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ spifWaitForReady();
+
+ spifWriteEnable();
+ if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ spifWaitForReady();
+
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ if ((rc = spifWriteBlock(addr+TFSHDRSIZ,src,size)) < 0)
+ printf(" write_file failed %d\n",rc);
+ spifWaitForReady();
+ spifGlobalProtect();
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ printf(" removing %s...\n",arg2);
+ fp->flags &= ~TFS_ACTIVE;
+ spifWriteEnable();
+ spifGlobalUnprotect();
+ spifWaitForReady();
+ spifWriteEnable();
+ if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ spifWaitForReady();
+ spifGlobalProtect();
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while(addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsstat") == 0) {
+ unsigned long oaddr, addr, meminuse, memdead;
+ TFILE tfshdr, *fp;
+
+ fp = &tfshdr;
+ meminuse = memdead = 0;
+ addr = base_of_serialtfs;
+ while(addr < end_of_serialtfs) {
+ if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("spifReadBlock failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+
+ oaddr = addr;
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while(addr & 0xf) addr++;
+
+ if (TFS_FILEEXISTS(fp))
+ meminuse += addr - oaddr;
+ else
+ memdead += addr - oaddr;
+ }
+ printf("Total: 0x%x, used: 0x%x, dead: 0x%x, avail: 0x%x\n",
+ (end_of_serialtfs - base_of_serialtfs),
+ meminuse, memdead,
+ (end_of_serialtfs - base_of_serialtfs) - (meminuse + memdead));
+ }
+#endif
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
diff --git a/main/common/spif.h b/main/common/spif.h
new file mode 100644
index 0000000..89310ec
--- /dev/null
+++ b/main/common/spif.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * spif.h:
+ *
+ * SPI-flash iterface. See spif.c for details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+/* Status register bits for ATMEL device: */
+#define SPRL 0x80 // Sector protection registers locked (if 1)
+#define RES 0x40 // Reserved for future use
+#define EPE 0x20 // Erase or program error (if 1)
+#define WPP 0x10 // *WP pin is deasserted (if 1)
+#define SWPS 0x0c // Software protection status bits
+#define SWPS00 0x00 // 00: all sectors unprotected
+#define SWPS01 0x04 // 01: some sectors unprotected
+#define SWPS10 0x08 // 10: reserved for future use
+#define SWPS11 0x0c // 11: all sectors protected (default)
+#define WEL 0x02 // Write enable latch (1=write enabled)
+#define BSY 0x01 // Busy (1=busy, 0=ready)
+
+/* Baudrate could be much higher, but we keep it low here for easier
+ * ability to trace out on the scope...
+ */
+#ifndef SPIFBAUD
+#define SPIFBAUD 25000000
+#endif
+
+/* The ATMEL part supports three different erase block sizes (not
+ * including the 'whole-chip' erase)...
+ */
+#define BLKSZ_4K 0x20
+#define BLKSZ_32K 0x52
+#define BLKSZ_64K 0xD8
+
+extern void spifQinit(void);
+extern int spifInit(void);
+extern int spifWaitForReady(void);
+extern int spifId(int verbose);
+extern int spifWriteEnable(void);
+extern int spifWriteDisable(void);
+extern int spifChipErase(void);
+extern int spifGlobalUnprotect(void);
+extern int spifGlobalProtect(void);
+extern int spifReadBlock(unsigned long addr,char *data,int len);
+extern int spifWriteBlock(unsigned long addr, char *data, int len);
+extern int spifBlockErase(int bsize, long addr);
+extern unsigned short spifReadStatus(int verbose);
+extern unsigned long spifGetTFSBase(void);
+extern unsigned long spifGetTFSSize(void);
diff --git a/main/common/start.c b/main/common/start.c
new file mode 100644
index 0000000..18919a2
--- /dev/null
+++ b/main/common/start.c
@@ -0,0 +1,496 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * start.c:
+ *
+ * This is typically the first 'C' code executed by the processor after a
+ * reset.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "cpuio.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "devices.h"
+#include "ether.h"
+#include "warmstart.h"
+#include "monlib.h"
+#include "monflags.h"
+#include "boardinfo.h"
+#include "cli.h"
+#include "tfsprivate.h"
+#include "fbi.h"
+
+#ifdef PRE_COMMANDLOOP_HOOK
+extern void PRE_COMMANDLOOP_HOOK();
+#endif
+
+#ifndef EXCEPTION_HEADING
+#define EXCEPTION_HEADING "EXCEPTION"
+#endif
+
+extern void vinit(void);
+extern int addcommand(struct monCommand *cmdlist, char *cmdlvl);
+
+/* StateOfMonitor:
+ * The StateOfMonitor variable is used throughout the code to determine
+ * how the monitor started up. In general, the three most common
+ * startup types are: INITIALIZE, APP_EXIT and EXCEPTION.
+ */
+int StateOfMonitor;
+
+/* MonStack:
+ * The monitor's stack is declared within the monitor's own .bss space.
+ * This keeps the memory map simple, the only thing that needs to be
+ * accounted for is that in the bss init loop, this section should not
+ * be initialized. MONSTACKSIZE must be defined in config.h.
+ */
+ulong MonStack[MONSTACKSIZE/4];
+
+/* APPLICATION_RAMSTART:
+ * Loaded with the address after which the application can be loaded.
+ */
+ulong APPLICATION_RAMSTART;
+
+/* BOOTROM_BASE:
+ * Loaded with the address considered to be the base address at which
+ * the monitor is burned into flash.
+ */
+ulong BOOTROM_BASE;
+
+/* LoopsPerMillisecond:
+ * Loaded with a count (established in config.h) that is an estimation of
+ * one second of elapsed time. It is NOT an accurate value, but serves the
+ * purpose of providing a hardware-independent mechanism for establishing
+ * a reasonable estimation of one second's worth of elapsed time.
+ */
+ulong LoopsPerMillisecond;
+
+/* init0():
+ * The code in this function was originally part of start(). It has been
+ * moved out so that this portion of the initialization can be re-used by
+ * AppWarmStart(). See notes in AppWarmStart() for more details on this.
+ */
+void
+init0(void)
+{
+ /* Store the base address of memory that is used by application.
+ * Start it off on the next 4K boundary after the end of monitor ram.
+ * Usually APPRAMBASE and BOOTROMBASE can be retrieved from bss_end and
+ * boot_base; but they can be overridden with values specified in the
+ * target-specific config.h file.
+ */
+#ifdef APPRAMBASE_OVERRIDE
+ APPLICATION_RAMSTART = APPRAMBASE_OVERRIDE;
+#else
+ APPLICATION_RAMSTART = (((ulong)&bss_end) | 0xfff) + 1;
+#endif
+
+#ifdef BOOTROMBASE_OVERRIDE
+ BOOTROM_BASE = BOOTROMBASE_OVERRIDE;
+#else
+ BOOTROM_BASE = (ulong)&boot_base;
+#endif
+
+ /* Load bottom of stack with 0xdeaddead to be used by stkchk().
+ */
+ MonStack[0] = 0xdeaddead;
+
+ /* Set up default loops-per-millisecond count.
+ */
+ LoopsPerMillisecond = LOOPS_PER_SECOND/1000;
+
+ /* Clear any user-installed command list.
+ */
+ addcommand(0,0);
+}
+
+/* init1():
+ * This is the first level of initialization (aside from the most fundamental
+ * stuff that must be done in reset.s) that is done after the system resets.
+ */
+void
+init1(void)
+{
+ initCPUio(); /* Configure all chip-selects, parallel IO
+ * direction registers, etc... This may have
+ * been done already in reset.s
+ */
+ vinit(); /* Initialize the CPU's vector table. */
+ InitRemoteIO(); /* Initialize all application-settable IO functions */
+
+ if (ConsoleBaudRate == 0)
+ ConsoleBaudRate = DEFAULT_BAUD_RATE;
+
+ devInit(ConsoleBaudRate);
+
+}
+
+/* init2():
+ */
+void
+init2(void)
+{
+#if INCLUDE_FLASH | INCLUDE_TFS
+ int rc = 0;
+#endif
+
+#if INCLUDE_FBI
+ if (StateOfMonitor == INITIALIZE)
+ fbdev_init(); /* Initialize the frame-buffer device */
+#endif
+
+#if INCLUDE_FLASH
+ if (StateOfMonitor == INITIALIZE)
+ rc = FlashInit(); /* Init flashop data structures and (possibly) */
+ /* the relocatable functions. This MUST be */
+#endif /* done prior to turning on cache!!! */
+
+ cacheInit(); /* Initialize cache. */
+
+#if INCLUDE_ETHERNET
+ enreset(); /* Clear the ethernet interface. */
+#endif
+
+#if INCLUDE_TFS
+ if (rc != -1) /* Start up TFS as long as flash */
+ tfsstartup(); /* initialization didn't fail. */
+#endif
+}
+
+/* init3():
+ * As each target boots up, it calls init1() and init2() to do multiple
+ * phases of hardware initialization. This third initialization phase
+ * is always common to all targets...
+ * It is possible that this is being called by AppWarmStart(). In this
+ * case, the user can specify which portions of the monitor code are
+ * to be initialized by specifying them in the startmode mask.
+ */
+static void
+_init3(ulong startmode)
+{
+ char *baud;
+
+#if INCLUDE_LINEEDIT
+ /* Initialize command line history table. */
+ historyinit();
+#endif
+
+#if INCLUDE_SHELLVARS
+ /* Init shell variable table. */
+ ShellVarInit();
+#endif
+
+#if INCLUDE_USRLVL
+ /* Set user level to its max, then allow monrc file to adjust it. */
+ initUsrLvl(MAXUSRLEVEL);
+#endif
+
+#if INCLUDE_BOARDINFO
+ /* Check for board-specific-information in some otherwise unused
+ * sector. Also, establish shell variables from this information
+ * based on the content of the boardinfo structure.
+ * Note that the second half of the board-specific information setup
+ * (the call to BoardInfoEnvInit()) must be done AFTER ShellVarInit()
+ * because shell variables are established here.
+ */
+ if (startmode & WARMSTART_BOARDINFO) {
+ BoardInfoInit();
+ BoardInfoEnvInit();
+ }
+#endif
+
+#ifdef MONCOMPTR
+ /* If MONCOMPTR is defined, then verify that the definition matches
+ * the location of the actual moncomptr value. The definition in
+ * config.h is provided so that outside applications can include that
+ * header file so that the value passed into monConnect() is defined
+ * formally. The REAL value of moncomptr is based on the location of
+ * the pointer in monitor memory space, determined only after the final
+ * link has been done. As a result, this check is used to simply verify
+ * that the definition matches the actual value.
+ */
+ {
+ if (MONCOMPTR != (ulong)&moncomptr)
+ printf("\nMONCOMPTR WARNING: runtime != definition\n");
+ }
+#endif
+
+#if INCLUDE_TFS
+ /* After basic initialization, if the monitor's run-control file
+ * exists, run it prior to EthernetStartup() so that the
+ * MAC/IP addresses can be configured based on shell variables
+ * that would be loaded by the rc file.
+ */
+ if (startmode & WARMSTART_RUNMONRC)
+ tfsrunrcfile();
+#endif
+
+ /* After MONRC is run, establish monitor flags...
+ */
+ InitMonitorFlags();
+
+ /* We've run the monrc file at this point, so check for the
+ * presence of the CONSOLEBAUD shell variable. If it's set,
+ * then use the value to re-establish the console baud rate.
+ * If it isn't set, then establish the CONSOLEBAUD shell variable
+ * using the default, pre-configured baud rate.
+ */
+ baud = getenv("CONSOLEBAUD");
+ if (baud)
+ ChangeConsoleBaudrate(atoi(baud));
+ ConsoleBaudEnvSet();
+
+#if INCLUDE_ETHERNET
+#if INCLUDE_STOREMAC
+ storeMac(0);
+#endif
+ if (startmode & WARMSTART_IOINIT)
+ EthernetStartup(0,1);
+#endif
+
+ /* Now that all has been initialized, display the monitor header. */
+#ifndef NO_UMON_STARTUP_HDR
+ if (startmode & WARMSTART_MONHEADER) {
+ if (!MFLAGS_NOMONHEADER())
+ monHeader(1);
+ }
+#endif
+
+#if INCLUDE_FBI
+ if (StateOfMonitor == INITIALIZE)
+ fbi_splash();
+#endif
+
+#if INCLUDE_TFS
+ if (startmode & WARMSTART_TFSAUTOBOOT)
+ tfsrunboot();
+#endif
+}
+
+void
+init3(void)
+{
+ _init3(WARMSTART_ALL);
+}
+
+/* umonBssInit():
+ * All of the monitor-owned ram is within it's bss space as defined
+ * by the locations of bss_start and bss_end in the memory map
+ * definition file. This includes the the monitor's stack and
+ * heap. To support a generic, C-based BSS initialzation loop,
+ * this loop must skip over the space allocated to the stack because
+ * the stack is likely to be in use during this loop...
+ */
+void
+umonBssInit(void)
+{
+ int *tmp;
+ volatile ulong *bssptr;
+
+ tmp = &bss_start;
+ bssptr = (ulong *)tmp;
+ while(bssptr < MonStack)
+ *bssptr++ = 0;
+ bssptr = (ulong *)MonStack+(MONSTACKSIZE/4);
+ tmp = &bss_end;
+ while(bssptr < (ulong *)tmp)
+ *bssptr++ = 0;
+}
+
+/* AppWarmStart():
+ * This function is provided to allow the application to partially
+ * restart the monitor. It supports the situation where an application
+ * run but the monitor has not already been initialized. This would be
+ * the case if some type of debugger (JTAG or BDM probably) was attached
+ * to the target and it was used to download and run the application.
+ * If this type of debug connection does not support the ability to run
+ * after the monitor runs, then the application must be able to somehow
+ * get the monitor initialized without having it go through a complete
+ * warmstart.
+ * This will only run through the stack space provided by the application.
+ */
+void
+AppWarmStart(ulong mask)
+{
+ /* First initialize monitor bss space (skipping over MonStack[]): */
+ if (mask & WARMSTART_BSSINIT)
+ umonBssInit();
+
+ StateOfMonitor = INITIALIZE;
+
+ /* Initialize some of the real fundamental stuff regardless of
+ * the incoming mask.
+ */
+ init0();
+
+ /* Subset of init1(): */
+ if (mask & WARMSTART_IOINIT) {
+ initCPUio();
+ InitRemoteIO();
+ if (ConsoleBaudRate == 0)
+ ConsoleBaudRate = DEFAULT_BAUD_RATE;
+ devInit(ConsoleBaudRate);
+ }
+ init2();
+ _init3(mask);
+}
+
+/* start():
+ * Called at the end of reset.s as the first C function after processor
+ * bootup. It is passed a state that is used to determine whether or not
+ * the CPU is restarting as a result of a warmstart or a coldstart. If
+ * the restart is a coldstart, then state will be INITIALIZE. if the
+ * restart is a warmstart, then there are a few typical values of state,
+ * the most common of which are APP_EXIT and EXCEPTION.
+ *
+ * The bss_start and bss_end variables are usually defined in the
+ * target-specific linker memory-map definition file. They symbolically
+ * identify the beginning and end of the .bss section. Many compilers
+ * support intrinsic tags for this; however, since it is apparently not
+ * consistent from one toolset to the next; I chose to make up my own
+ * tags so that this file never changes from one toolset to the next.
+ *
+ * The FORCE_BSS_INIT definition can be established in the target-specific
+ * config.h file to force .bss space initialization regardless of warm/cold
+ * start.
+ */
+void
+start(int state)
+{
+ char buf[48];
+
+#ifdef FORCE_BSS_INIT
+ state = INITIALIZE;
+#endif
+
+ /* Based on the incoming value of 'state' we may or may not initialize
+ * monitor-owned ram. Ideally, we only want to initialize
+ * monitor-owned ram when 'state' is INITIALIZE (power-up or reset);
+ * however, to support the case where the incoming state variable may
+ * be corrupted, we also initialize monitor-owned ram when 'state'
+ * is anything unexpected...
+ */
+ switch(state) {
+ case EXCEPTION:
+ case APP_EXIT:
+ break;
+ case INITIALIZE:
+ default:
+ umonBssInit();
+ break;
+ }
+
+ /* Now that the BSS clear loop has been done, we can copy the
+ * value of state (either a register or on stack) to the global
+ * variable (in BSS) StateOfMonitor...
+ */
+ StateOfMonitor = state;
+
+ /* Step through different phases of startup...
+ */
+ init0();
+ init1();
+ init2();
+
+ /* Depending on the type of startup, alert the console and do
+ * further initialization as needed...
+ */
+ switch(StateOfMonitor) {
+ case INITIALIZE:
+ reginit();
+ init3();
+ break;
+ case APP_EXIT:
+ EthernetStartup(0,0);
+ if (!MFLAGS_NOEXITSTATUS()) {
+ printf("\nApplication Exit Status: %d (0x%x)\n",
+ AppExitStatus,AppExitStatus);
+ }
+ break;
+ case EXCEPTION:
+ EthernetStartup(0,0);
+ printf("\n%s: '%s'\n",EXCEPTION_HEADING,
+ ExceptionType2String(ExceptionType));
+ printf(" Occurred near 0x%lx",ExceptionAddr);
+ if (AddrToSym(-1,ExceptionAddr,buf,0))
+ printf(" (within %s)",buf);
+ printf("\n\n");
+ exceptionAutoRestart(INITIALIZE);
+ break;
+ default:
+ printf("Unexpected monitor state: 0x%x (sp @ 0x%x)\n",
+ StateOfMonitor, buf);
+ /* To attempt to recover from the bad state, just do
+ * what INITIALIZE would do...
+ */
+ reginit();
+ init3();
+ break;
+ }
+
+#ifdef LOCK_FLASH_PROTECT_RANGE
+ /* Issue the command that will cause the range of sectors
+ * designated by FLASH_PROTECT_RANGE to be locked. This only
+ * works if the flash device is capable of being locked.
+ */
+ sprintf(buf,"flash lock %s",FLASH_PROTECT_RANGE);
+ docommand(buf,0);
+#endif
+
+#ifdef PRE_COMMANDLOOP_HOOK
+ PRE_COMMANDLOOP_HOOK();
+#endif
+
+ /* Enter the endless loop of command processing: */
+ CommandLoop();
+
+ printf("ERROR: CommandLoop() returned\n");
+ monrestart(INITIALIZE);
+}
+
+/* __eabi():
+ * Called intrinsically by main for some PowerPc builds.
+ * I'm not sure what the purpose of it is, but EABI is Embedded Application
+ * Binary Interface, and is documented on Motorola's web site at
+ * http://www.mcu.motsps.com/lit/manuals/eabispec.html#536421
+ */
+void
+__eabi(void)
+{
+}
+
+/* __main() or __gccmain(): called intrinsically by main. One or the other
+ * is typically used to run constructors and destructors for C++. If this
+ * function is not created here, then the compiler will automatically create
+ * one and with it, will come other unnecessary baggage.
+ */
+void
+__main(void)
+{
+}
+
+void
+__gccmain(void)
+{
+}
diff --git a/main/common/stddefs.h b/main/common/stddefs.h
new file mode 100644
index 0000000..cef8fb9
--- /dev/null
+++ b/main/common/stddefs.h
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * stddefs.h:
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _STDDEFS_H_
+#define _STDDEFS_H_
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed long int32_t;
+typedef signed long long int64_t;
+
+typedef volatile unsigned char vuint8_t;
+typedef volatile unsigned short vuint16_t;
+typedef volatile unsigned long vuint32_t;
+typedef volatile unsigned long long vuint64_t;
+
+typedef volatile signed char vint8_t;
+typedef volatile signed short vint16_t;
+typedef volatile signed long vint32_t;
+typedef volatile signed long long vint64_t;
+
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned int uint;
+
+typedef volatile unsigned char vuchar;
+typedef volatile unsigned short vushort;
+typedef volatile unsigned long vulong;
+typedef volatile unsigned int vuint;
+typedef volatile int vint;
+
+
+#endif
diff --git a/main/common/struct.c b/main/common/struct.c
new file mode 100644
index 0000000..5a60a3c
--- /dev/null
+++ b/main/common/struct.c
@@ -0,0 +1,783 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * struct.c:
+ *
+ * This command allows the user to build a structure into memory based
+ * on a structure set up in the definition file ("structfile").
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "ether.h"
+#include <stdarg.h>
+
+#if INCLUDE_STRUCT
+
+#define OPENBRACE '{'
+#define CLOSEBRACE '}'
+#define PTRSIZE 4
+
+int structsize(char *name);
+
+struct mbrtype {
+ char *type;
+ int size;
+};
+
+struct mbrtype types[] = {
+ { "long", 4 },
+ { "short", 2 },
+ { "char", 1 },
+ { 0, -1 }
+};
+
+static int struct_sfd;
+static ulong struct_base;
+static char *struct_fname;
+static char struct_verbose;
+static char struct_scriptisstructfile;
+
+/* err_general(), err_nostruct(), err_nomember():
+ * Error processing functions...
+ */
+static void
+err_general(int errnum,int linenum, long tfsloc)
+{
+ printf("%s: err%d at ln %d\n",struct_fname,errnum,linenum);
+ tfsseek(struct_sfd,tfsloc,TFS_BEGIN);
+}
+
+static void
+err_nostruct(char *structname, long tfsloc)
+{
+ printf("%s: can't find struct '%s'\n",struct_fname,structname);
+ tfsseek(struct_sfd,tfsloc,TFS_BEGIN);
+}
+
+static void
+err_nomember(char *structname, char *mbrname, long tfsloc)
+{
+ printf("%s: member '%s' not in struct '%s'\n",
+ struct_fname,mbrname,structname);
+ tfsseek(struct_sfd,tfsloc,TFS_BEGIN);
+}
+
+/* struct_printf():
+ * Use this function instead of "if (struct_verbose) printf(...)"
+ * all over the place.
+ */
+static int
+struct_printf(int mask, char *fmt, ...)
+{
+ int tot;
+ va_list argp;
+
+ if (!(struct_verbose & mask))
+ return(0);
+
+ va_start(argp,fmt);
+ tot = vsnprintf(0,0,fmt,argp);
+ va_end(argp);
+ return(tot);
+}
+
+/* struct_prleft():
+ * Print all characters of the incoming string up to the
+ * end of the string or the first occurrence of the equals sign.
+ * Then print the formatted string that follows.
+ */
+static int
+struct_prleft(int mask, char *str, char *fmt, ...)
+{
+ int tot = 0;
+ va_list argp;
+
+ if (!(struct_verbose & mask))
+ return(tot);
+
+ while((*str) && (*str != '=')) {
+ tot++;
+ putchar(*str++);
+ }
+
+ va_start(argp,fmt);
+ tot += vsnprintf(0,0,fmt,argp);
+ va_end(argp);
+ return(tot);
+}
+
+/* skipline():
+ * If the line is filled with only whitespace, or if the first non-whitespace
+ * character is a poundsign, return 1; else return 0.
+ */
+static int
+skipline(char *line)
+{
+ if (struct_scriptisstructfile) {
+ if (strncmp(line,"###>>",5) == 0) {
+ strcpy(line,line+5);
+ return(0);
+ }
+ else
+ return(1);
+ }
+ else {
+ while(isspace(*line)) line++;
+
+ switch(*line) {
+ case 0:
+ case '#':
+ return(1);
+ }
+ return(0);
+ }
+}
+
+/* typesize():
+ * Given the incoming type name, return the size of that symbol.
+ * Take into account the possibility of it being a pointer (leading '*')
+ * or an array (trailing [xx]).
+ */
+static int
+typesize(char *typename, char *name)
+{
+ char *np;
+ struct mbrtype *mp;
+ int nlen, ptr, arraysize;
+
+ ptr = 0;
+ arraysize = 1;
+
+ struct_printf(4,"typesize(%s,%s)\n",typename,name);
+
+ if (name[0] == '*')
+ ptr = 1;
+
+ nlen = strlen(name);
+ np = name+nlen-1;
+ if (*np == ']') {
+ while(*np && (*np != '[')) np--;
+ if (*np == 0)
+ return(-1);
+ arraysize = atoi(np+1);
+ }
+
+ mp = types;
+ while(mp->type) {
+ if (strncmp(mp->type,typename,strlen(mp->type)) == 0)
+ break;
+ mp++;
+ }
+
+ if (ptr)
+ return(PTRSIZE * arraysize);
+
+ return(mp->size * arraysize);
+}
+
+/* structline():
+ * Assume that the incoming line is text within a structure definition
+ * from the structure file. Parse it, expecting either two or three
+ * tokens (2 if the member is a basic type, 3 if the member is another
+ * structure). Return the count and pointers to each token.
+ */
+static int
+structline(char *line, char **type, char **name)
+{
+ int tot;
+ char *cp, *token1, *token2, *token3;
+
+ cp = line;
+ while(isspace(*cp)) cp++;
+ token1 = cp;
+ while(!isspace(*cp)) cp++;
+ *cp++ = 0;
+
+ if (!strcmp(token1,"struct")) {
+ while(isspace(*cp)) cp++;
+ token2 = cp;
+ while(!isspace(*cp)) cp++;
+ *cp++ = 0;
+ while(isspace(*cp)) cp++;
+ token3 = cp;
+ while((!isspace(*cp)) && (*cp != ';')) cp++;
+ if (*cp != ';')
+ return(-1);
+ *cp++ = 0;
+ *type = token2;
+ *name = token3;
+ tot = 3;
+ }
+ else {
+ while(isspace(*cp)) cp++;
+ token2 = cp;
+ while((!isspace(*cp)) && (*cp != ';')) cp++;
+ if (*cp != ';')
+ return(-1);
+ *cp++ = 0;
+ *type = token1;
+ *name = token2;
+ tot = 2;
+ }
+ struct_printf(4,"structline: type='%s', name='%s'\n",*type,*name);
+ return(tot);
+
+}
+
+/* structsize():
+ * Assuming the incoming string is a pointer to some structure definition
+ * in the structure file, parse the file and figure out how big the
+ * structure is. Return the size of successful; else return -1 to indicate
+ * some kind of parsing error.
+ */
+int
+structsize(char *structname)
+{
+ long loc;
+ int offset, slen, lno, size;
+ char line[80], *cp, *cp1, *type, *name;
+
+ struct_printf(4,"structsize(%s)\n",structname);
+
+ loc = tfstell(struct_sfd);
+
+ if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ return(-1);
+ }
+
+ offset = 0;
+ slen = strlen(structname);
+ lno = 0;
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (!strncmp(line,"struct ",7)) {
+ cp = line+7;
+ while(isspace(*cp)) cp++;
+ if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) {
+ cp1 = cp+slen;
+ while(isspace(*cp1)) cp1++;
+ if (*cp1 != OPENBRACE) {
+ err_general(1,lno,loc);
+ return(-1);
+ }
+
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (line[0] == CLOSEBRACE) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ return(offset);
+ }
+ switch(structline(line,&type,&name)) {
+ case 2:
+ if ((size = typesize(type,name)) < 0) {
+ err_general(2,lno,loc);
+ return(-1);
+ }
+ break;
+ case 3:
+ if ((size = structsize(type)) < 0) {
+ err_general(3,lno,loc);
+ return(-1);
+ }
+ break;
+ default:
+ err_general(4,lno,loc);
+ return(-1);
+ }
+ offset += size;
+ }
+ err_general(5,lno,loc);
+ return(-1);
+ }
+ }
+ }
+ err_nostruct(structname,loc);
+ return(-1);
+}
+
+int
+membertype(char *structname, char *mbrname, char *mbrtype)
+{
+ long loc;
+ int rc, slen, lno;
+ char line[80], *cp, *cp1, *type, *name;
+
+ struct_printf(4,"membertype(%s,%s)\n",structname,mbrname);
+
+ loc = tfstell(struct_sfd);
+
+ if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ return(-1);
+ }
+
+ slen = strlen(structname);
+ lno = 0;
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (!strncmp(line,"struct ",7)) {
+ cp = line+7;
+ while(isspace(*cp)) cp++;
+ if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) {
+ cp1 = cp+slen;
+ while(isspace(*cp1)) cp1++;
+ if (*cp1 != OPENBRACE) {
+ err_general(6,lno,loc);
+ return(-1);
+ }
+
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (line[0] == CLOSEBRACE) {
+ err_nomember(structname,mbrname,loc);
+ return(-1);
+ }
+ if ((rc = structline(line,&type,&name)) < 0) {
+ err_general(7,lno,loc);
+ return(-1);
+ }
+ if (!strcmp(name,mbrname)) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ if (mbrtype)
+ strcpy(mbrtype,type);
+ return(rc);
+ }
+ }
+ err_general(8,lno,loc);
+ return(-1);
+ }
+ }
+ }
+ err_nostruct(structname,loc);
+ return(-1);
+}
+
+/* memberoffset():
+ * Return the offset into the structure at which point the member resides.
+ * If mbrsize is non-zero, then assume it is a pointer to an integer
+ * into which this function will also load the size of the member.
+ */
+int
+memberoffset(char *structname, char *mbrname, int *mbrsize)
+{
+ long loc;
+ int offset, slen, size, lno;
+ char line[80], *cp, *cp1, *type, *name;
+
+ struct_printf(4,"memberoffset(%s,%s)\n",structname,mbrname);
+
+ loc = tfstell(struct_sfd);
+
+ if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ return(-1);
+ }
+
+ offset = 0;
+ slen = strlen(structname);
+ lno = 0;
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (!strncmp(line,"struct ",7)) {
+ cp = line+7;
+ while(isspace(*cp)) cp++;
+ if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) {
+ cp1 = cp+slen;
+ while(isspace(*cp1)) cp1++;
+ if (*cp1 != OPENBRACE) {
+ err_general(9,lno,loc);
+ return(-1);
+ }
+
+ while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) {
+ lno++;
+ if (skipline(line))
+ continue;
+ if (line[0] == '#')
+ continue;
+ if (line[0] == CLOSEBRACE) {
+ err_nomember(structname,mbrname,loc);
+ return(-1);
+ }
+ switch(structline(line,&type,&name)) {
+ case 2:
+ if ((size = typesize(type,name)) < 0) {
+ err_general(10,lno,loc);
+ return(-1);
+ }
+ break;
+ case 3:
+ if ((size = structsize(type)) < 0) {
+ err_general(11,lno,loc);
+ return(-1);
+ }
+ break;
+ default:
+ err_general(12,lno,loc);
+ return(-1);
+ }
+ if (!strcmp(name,mbrname)) {
+ tfsseek(struct_sfd,loc,TFS_BEGIN);
+ if (mbrsize)
+ *mbrsize = size;
+ return(offset);
+ }
+ offset += size;
+ }
+ err_general(13,lno,loc);
+ return(-1);
+ }
+ }
+ }
+ err_nostruct(structname,loc);
+ return(-1);
+}
+
+char *StructHelp[] = {
+ "Build a structure in memory",
+ "-[b:f:v] {struct.mbr[=val]} [struct.mbr1[=val1]] ...",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -b{addr} base address of structure (overrides STRUCTBASE)",
+ " -f{fname} structure definition filename (overrides STRUCTFILE)",
+ " -v additive verbosity",
+ "",
+ "Notes:",
+ " * The 'val' can be a normal value or a processed function...",
+ " strcpy(str|src), strcat(str|src), memcpy(src,size)",
+ " sizeof(structtype), tagsiz(str1,str2), e2b(enet), i2l(ip)",
+ " * If '=val' is not specified, then the size and offset of the",
+ " specified structure/member is loaded into STRUCTSIZE and",
+ " STRUCTOFFSET shellvars respectively.",
+#endif
+ 0,
+};
+
+int
+StructCmd(int argc,char *argv[])
+{
+ unsigned long lval, dest;
+ char copy[CMDLINESIZE], type[32];
+ char *eq, *dot, *str, *mbr, *env, *equation;
+ int opt, i, offset, mbrtype, rc, size, processlval;
+
+ struct_fname = 0;
+ struct_verbose = 0;
+ struct_base = 0xffffffff;
+ while((opt=getopt(argc,argv,"b:f:v")) != -1) {
+ switch(opt) {
+ case 'b':
+ struct_base = strtoul(optarg,0,0);
+ break;
+ case 'f':
+ struct_fname = optarg;
+ break;
+ case 'v':
+ struct_verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind + 1)
+ return(CMD_PARAM_ERROR);
+
+ /* If base and/or filename are not set, get them from environment
+ * variables...
+ */
+ if (struct_base == 0xffffffff) {
+ if ((env = getenv("STRUCTBASE")) == 0) {
+ printf("No struct base\n");
+ return(CMD_FAILURE);
+ }
+ struct_base = strtoul(env,0,0);
+ }
+ if (struct_fname == 0) {
+ if ((struct_fname = getenv("STRUCTFILE")) == 0) {
+ printf("No struct filename\n");
+ return(CMD_FAILURE);
+ }
+ }
+
+ struct_sfd = tfsopen(struct_fname,TFS_RDONLY,0);
+
+ if (struct_sfd < 0) {
+ printf("Can't find file '%s'\n",struct_fname);
+ return(CMD_FAILURE);
+ }
+
+ /* If the specified structure description file is the currently
+ * running script, then set a flag so that this code will look
+ * for the "###>>" prefix as a required line prefix in the
+ * structure file.
+ */
+ if (strcmp(struct_fname,tfsscriptname()) == 0)
+ struct_scriptisstructfile = 1;
+ else
+ struct_scriptisstructfile = 0;
+
+ /* Assume each command line argument is some "struct=val" statement,
+ * and process each one...
+ */
+ for(i=optind;i<argc;i++) {
+ equation = argv[i];
+
+ /* Make a copy of the argument so we can modify it.
+ * (no need to check length because sizeof(copy) is CMDLINESIZE).
+ */
+ strcpy(copy,equation);
+
+ /* Check for equal sign...
+ */
+ if ((eq = strchr(copy,'=')))
+ *eq = 0;
+
+ /* Start parsing and processing the structure request...
+ */
+ offset = mbrtype = 0;
+ dot = strchr(copy,'.');
+ if (!dot) {
+ size = structsize(copy);
+ }
+ else {
+ while(dot) {
+ *dot++ = 0;
+ mbr = dot;
+ str = dot-2;
+ while((*str != 0) && (str != copy) && (*str != '.'))
+ str--;
+ if (str != copy)
+ str++;
+ while((dot != 0) && (*dot != '.'))
+ dot++;
+ *dot = 0;
+
+ if (mbrtype == 3)
+ str = type;
+
+ if ((rc = memberoffset(str,mbr,&size)) < 0)
+ goto done;
+
+ if ((mbrtype = membertype(str,mbr,type)) < 0)
+ goto done;
+
+ offset += rc;
+ *dot = '.';
+ dot = strchr(mbr,'.');
+ }
+ }
+
+ shell_sprintf("STRUCTOFFSET","0x%lx",offset);
+ shell_sprintf("STRUCTSIZE","0x%lx",size);
+
+ /* If there is no "right half" of the equation, then just
+ * continue here...
+ */
+ if (!eq)
+ continue;
+
+ /* At this point we have the size of the member and its offset
+ * from the base, so now we parse the "val" side of the
+ * equation...
+ */
+
+ /* Check for functions (sizeof, strcpy, enet, ip, etc...).
+ * If found, then something other than just normal lval processing
+ * is done...
+ */
+ eq++;
+ lval = processlval = 0;
+ dest = struct_base + offset;
+ if (!strncmp(eq,"sizeof(",7)) {
+ char *cp;
+
+ eq += 7;
+ cp = eq;
+ if ((cp = strchr(cp,')')) == 0)
+ goto paramerr;
+ *cp=0;
+ lval = structsize(eq);
+ processlval = 1;
+ }
+ else if (!strncmp(eq,"i2l(",4)) {
+ char *cp, *cp1;
+
+ eq += 4;
+ cp = cp1 = eq;
+ if ((cp1 = strchr(cp,')')) == 0)
+ goto paramerr;
+ *cp1 = 0;
+ if (struct_verbose & 1) {
+ }
+ struct_printf(3,"i2l(0x%lx,%s)\n", dest, cp);
+
+ if (IpToBin(cp,(uchar *)dest) < 0)
+ goto paramerr;
+ }
+ else if (!strncmp(eq,"e2b(",4)) {
+ char *cp, *cp1;
+
+ cp = cp1 = eq+4;
+ if ((cp1 = strchr(cp,')')) == 0)
+ goto paramerr;
+ *cp1 = 0;
+ struct_printf(3,"e2b(0x%lx,%s)\n", dest, cp);
+
+ if (EtherToBin(cp,(uchar *)dest) < 0)
+ goto paramerr;
+ }
+ else if (!strncmp(eq,"tagsiz(",7)) {
+ char *comma, *paren;
+ int siz1, siz2;
+
+ eq += 7;
+ comma = eq;
+ if ((comma = strchr(comma,',')) == 0)
+ goto paramerr;
+ *comma++ = 0;
+ if ((paren = strrchr(comma,')')) == 0)
+ goto paramerr;
+ *paren = 0;
+ if ((siz1=structsize(eq)) < 0)
+ goto paramerr;
+ if ((siz2=structsize(comma)) < 0)
+ goto paramerr;
+ lval = (siz1+siz2)/4;
+ processlval = 1;
+ }
+ else if (!strncmp(eq,"memcpy(",7)) {
+ int len;
+ char *comma, *cp;
+
+ eq += 7;
+ comma = eq;
+ if ((comma = strchr(comma,',')) == 0)
+ goto paramerr;
+ *comma++ = 0;
+ cp = comma;
+ cp = (char *)strtoul(eq,0,0);
+ len = (int)strtoul(comma,0,0);
+ struct_printf(3,"memcpy(0x%lx,0x%lx,%d)\n",dest,(long)cp,len);
+ memcpy((void *)dest,(void *)cp,len);
+ }
+ else if (!strncmp(eq,"strcpy(",7)) {
+ char *cp, *cp1;
+
+ eq += 7;
+ cp = cp1 = eq;
+ if ((cp1 = strrchr(cp,')')) == 0)
+ goto paramerr;
+ *cp1 = 0;
+
+
+ if (!strncmp(cp,"0x",2)) {
+ cp = (char *)strtoul(eq,0,0);
+ struct_printf(3,"strcpy(0x%lx,0x%lx)\n",dest,(long)cp);
+ }
+ else {
+ struct_prleft(1,equation," = \"%s\"\n",cp);
+ struct_printf(2,"strcpy(0x%lx,%s)\n", dest,cp);
+ }
+ strcpy((char *)dest,cp);
+ }
+ else if (!strncmp(eq,"strcat(",7)) {
+ char *cp, *cp1;
+
+ eq += 7;
+ cp = cp1 = eq;
+ if ((cp1 = strrchr(cp,')')) == 0)
+ goto paramerr;
+ *cp1 = 0;
+
+ if (!strncmp(cp,"0x",2)) {
+ cp = (char *)strtoul(eq,0,0);
+ struct_printf(3,"strcat(0x%lx,0x%lx)\n",dest,(long)cp);
+ }
+ else {
+ struct_prleft(1,equation," += \"%s\"\n",cp);
+ struct_printf(2,"strcat(0x%lx,%s)\n", dest,cp);
+ }
+ strcat((char *)dest,cp);
+ }
+ else {
+ lval = strtoul(eq,0,0);
+ processlval = 1;
+ }
+
+ if (processlval) {
+ switch(size) {
+ case 1:
+ struct_prleft(1,equation," = %d (0x%x)\n",
+ (uchar)lval,(uchar)lval);
+ struct_printf(2,"*(uchar *)0x%lx = %d (0x%x)\n",
+ dest,(uchar)lval,(uchar)lval);
+ *(uchar *)(dest) = (uchar)lval;
+ break;
+ case 2:
+ struct_prleft(1,equation," = %d (0x%x)\n",
+ (ushort)lval,(ushort)lval);
+ struct_printf(2,"*(ushort *)0x%lx = %d (0x%x)\n",
+ dest,(ushort)lval,(ushort)lval);
+ *(ushort *)dest = (ushort)lval;
+ break;
+ case 4:
+ struct_prleft(1,equation," = %ld (0x%lx)\n",
+ (ulong)lval,(ulong)lval);
+ struct_printf(2,"*(ulong *)0x%lx = %d (0x%x)\n",
+ dest,lval,lval);
+ *(ulong *)dest = lval;
+ break;
+ default:
+ struct_printf(3,"memset(0x%lx,0x%x,%d)\n",
+ dest,(uchar)lval,size);
+ memset((void *)dest,lval,size);
+ break;
+ }
+ }
+ }
+done:
+ tfsclose(struct_sfd,0);
+ return(CMD_SUCCESS);
+
+paramerr:
+ tfsclose(struct_sfd,0);
+ return(CMD_PARAM_ERROR);
+}
+#endif
diff --git a/main/common/symtbl.c b/main/common/symtbl.c
new file mode 100644
index 0000000..efc08c4
--- /dev/null
+++ b/main/common/symtbl.c
@@ -0,0 +1,215 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * symtbl.c:
+ *
+ * This file contains functions related to the symbol table option in
+ * the monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#if INCLUDE_TFSSYMTBL
+#include <ctype.h>
+#include "tfs.h"
+#include "tfsprivate.h"
+
+#ifndef SYMFILE
+#define SYMFILE "symtbl"
+#endif
+
+/* SymFileFd():
+ * Attempt to open the symbol table file. First look to the SYMFILE env var;
+ * else default to SYMFILE definition. If the file exists, open it and return
+ * the file descriptor; else return TFSERR_NOFILE.
+ */
+int
+SymFileFd(int verbose)
+{
+ TFILE *tfp;
+ int tfd;
+ char *symfile;
+
+ /* Load symbol table file name. If SYMFILE is not a variable, default
+ * to the string defined by SYMFILE.
+ */
+ symfile = getenv("SYMFILE");
+ if (!symfile)
+ symfile = SYMFILE;
+
+ tfp = tfsstat(symfile);
+ if (!tfp)
+ return(TFSERR_NOFILE);
+
+ tfd = tfsopen(symfile,TFS_RDONLY,0);
+ if (tfd < 0) {
+ if (verbose)
+ printf("%s: %s\n",symfile,(char *)tfsctrl(TFS_ERRMSG,tfd,0));
+ return(TFSERR_NOFILE);
+ }
+ return(tfd);
+}
+
+/* AddrToSym():
+ * Assumes each line of symfile is formatted as...
+ * synmame SP hex_address
+ * and that the symbols are sorted from lowest to highest address.
+ * Using the file specified by the incoming TFS file descriptor,
+ * determine what symbol's address range covers the incoming address.
+ * If found, store the name of the symbol as well as the offset between
+ * the address of the symbol and the incoming address.
+ * Note, if the incoming file descriptor is -1, then we open (and later
+ * close) the file here.
+ *
+ * Return 1 if a match is found, else 0.
+ */
+int
+AddrToSym(int tfdin,ulong addr,char *name,ulong *offset)
+{
+ int lno, tfd;
+ char *space;
+ ulong thisaddr, lastaddr;
+ char thisline[84];
+ char lastline[sizeof(thisline)];
+
+ lno = 1;
+ if (offset)
+ *offset = 0;
+ lastaddr = 0;
+ if (tfdin == -1) {
+ tfd = SymFileFd(0);
+ if (tfd == TFSERR_NOFILE)
+ return(0);
+ }
+ else
+ tfd = tfdin;
+ tfsseek(tfd,0,TFS_BEGIN);
+ while(tfsgetline(tfd,thisline,sizeof(thisline)-1)) {
+ space = strpbrk(thisline,"\t ");
+ if (!space)
+ continue;
+ *space++ = 0;
+ while(isspace(*space))
+ space++;
+
+ thisaddr = strtoul(space,0,0); /* Compute address from entry in */
+ /* symfile. */
+
+ if (thisaddr == addr) { /* Exact match, use this entry */
+ strcpy(name,thisline); /* in symfile. */
+ if (tfdin == -1)
+ tfsclose(tfd,0);
+ return(1);
+ }
+ else if (thisaddr > addr) { /* Address in symfile is greater */
+ if (lno == 1) /* than incoming address... */
+ break; /* If this is first line of symfile */
+ strcpy(name,lastline); /* then return error. */
+ if (offset)
+ *offset = addr-lastaddr;/* Otherwise return the symfile */
+ if (tfdin == -1)
+ tfsclose(tfd,0);
+ return(1); /* entry previous to this one. */
+ }
+ else { /* Address in symfile is less than */
+ lastaddr = thisaddr; /* incoming address, so just keep */
+ strcpy(lastline,thisline); /* a copy of this line and go to */
+ lno++; /* the next. */
+ }
+ }
+ if (tfdin == -1)
+ tfsclose(tfd,0);
+ sprintf(name,"0x%lx",addr);
+ return(0);
+}
+
+/* getsym():
+ * Provides a similar capability to shell variables on the command line
+ * except that here, the variable replacement is based on the content of
+ * a symbol file. The file would be be loaded into TFS to provide
+ * a potentially large number of symbols.
+ * Looks for the file SYMFILE. If non-existent, just return NULL.
+ * If file exists, then search through the file for the incoming
+ * symbol name and, if found, return the replacement for the symbol.
+ * else return NULL.
+ * The text file is formatted such that no line is greater than 40 characters.
+ * Each line has 2 whitespace delimited strings. The first string is
+ * the symbol name and the second string is the replacement value for that
+ * symbol. The first string is assumed to start at the beginning of the
+ * line, and the second string is separated from the first string by
+ * spaces and/or tabs.
+ * For example, here are a few lines:
+ *
+ * main 0x10400
+ * func 0x10440
+ *
+ * With the above lines in SYMFILE, if %main were on the command line, it
+ * would be replaced with 0x10400.
+ */
+char *
+getsym(char *symname,char *line,int sizeofline)
+{
+ int tfd;
+ char *space;
+
+ if ((tfd = SymFileFd(1)) < 0) {
+ return((char *)0);
+ }
+
+ while(tfsgetline(tfd,line,sizeofline)) {
+ char *eol;
+ eol = strpbrk(line,"\r\n");
+ if (eol)
+ *eol = 0;
+ space = strpbrk(line,"\t ");
+ if (!space)
+ continue;
+ *space = 0;
+ if (!strcmp(line,symname)) {
+ tfsclose(tfd,0);
+ space++;
+ while((*space == ' ') || (*space == '\t'))
+ space++;
+ return(space);
+ }
+ }
+ tfsclose(tfd,0);
+ return((char *)0);
+}
+
+#else
+
+char *
+getsym(char *symname,char *line,int sizeofline)
+{
+ return((char *)0);
+}
+
+int
+AddrToSym(int tfd,ulong addr,char *name,ulong *offset)
+{
+ sprintf(name,"0x%lx",addr);
+ return(0);
+}
+
+#endif
diff --git a/main/common/syslog.c b/main/common/syslog.c
new file mode 100644
index 0000000..a6f0334
--- /dev/null
+++ b/main/common/syslog.c
@@ -0,0 +1,337 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * syslog.c:
+ *
+ * This code supports the monitor's SYSLOC client.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_SYSLOG
+#include "endian.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "cli.h"
+
+#define SYSLOG_PORT 514
+
+struct nameval {
+ char *name;
+ int val;
+};
+
+/* Priority codes:
+ */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+/* Facility codes:
+ */
+#define LOG_KERN (0<<3) /* kernel messages */
+#define LOG_USER (1<<3) /* random user-level messages */
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
+#define LOG_LPR (6<<3) /* line printer subsystem */
+#define LOG_NEWS (7<<3) /* network news subsystem */
+#define LOG_UUCP (8<<3) /* UUCP subsystem */
+#define LOG_CRON (9<<3) /* clock daemon */
+#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
+#define LOG_FTP (11<<3) /* ftp daemon */
+#define LOG_LOCAL0 (16<<3) /* reserved for local use */
+#define LOG_LOCAL1 (17<<3) /* reserved for local use */
+#define LOG_LOCAL2 (18<<3) /* reserved for local use */
+#define LOG_LOCAL3 (19<<3) /* reserved for local use */
+#define LOG_LOCAL4 (20<<3) /* reserved for local use */
+#define LOG_LOCAL5 (21<<3) /* reserved for local use */
+#define LOG_LOCAL6 (22<<3) /* reserved for local use */
+#define LOG_LOCAL7 (23<<3) /* reserved for local use */
+
+#define FACILITY_MASK 0x03f8
+#define PRIORITY_MASK 0x0007
+
+struct nameval prioritynames[] = {
+ { "emerg", LOG_EMERG },
+ { "alert", LOG_ALERT },
+ { "critical", LOG_CRIT },
+ { "error", LOG_ERR },
+ { "warning", LOG_WARNING },
+ { "notice", LOG_NOTICE },
+ { "info", LOG_INFO },
+ { "debug", LOG_DEBUG },
+ { 0, 0 }
+};
+
+struct nameval facilitynames[] = {
+ { "kernel", LOG_KERN },
+ { "user", LOG_USER },
+ { "mail", LOG_MAIL },
+ { "daemon", LOG_DAEMON },
+ { "authorize", LOG_AUTH },
+ { "syslog", LOG_SYSLOG },
+ { "lpr", LOG_LPR },
+ { "news", LOG_NEWS },
+ { "uucp", LOG_UUCP },
+ { "cron", LOG_CRON },
+ { "authpriv", LOG_AUTHPRIV },
+ { "ftp", LOG_FTP },
+ { "local0", LOG_LOCAL0 },
+ { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 },
+ { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 },
+ { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 },
+ { "local7", LOG_LOCAL7 },
+ { 0, 0 }
+};
+
+void
+syslogInfo(void)
+{
+ int tot;
+ struct nameval *nvp;
+
+ tot = 0;
+ nvp = prioritynames;
+ printf("\nValid 'priority' names:\n");
+ while(nvp->name) {
+ printf("%12s",nvp->name);
+ nvp++;
+ if (++tot == 4) {
+ printf("\n");
+ tot = 0;
+ }
+ }
+
+ tot = 0;
+ nvp = facilitynames;
+ printf("\nValid 'facility' names:\n");
+ while(nvp->name) {
+ printf("%12s",nvp->name);
+ nvp++;
+ if (++tot == 4) {
+ printf("\n");
+ tot = 0;
+ }
+ }
+}
+
+
+int
+getPriorityValue(char *prio)
+{
+ struct nameval *nvp;
+
+ if (prio == 0)
+ return(0);
+
+ nvp = prioritynames;
+ while(nvp->name) {
+ if (!strcmp(nvp->name,prio))
+ return(nvp->val);
+ nvp++;
+ }
+ return(-1);
+}
+
+int
+getFacilityValue(char *fac)
+{
+ struct nameval *nvp;
+
+ if (fac == 0)
+ return(0);
+
+ nvp = facilitynames;
+ while(nvp->name) {
+ if (!strcmp(nvp->name,fac))
+ return(nvp->val);
+ nvp++;
+ }
+ return(-1);
+}
+
+int
+sendSyslog(uchar *syslogsrvr,char *msg, short port, int null)
+{
+ int msglen;
+ uchar *syslogmsg;
+ ushort ip_len, sport;
+ struct ether_header *enetp;
+ struct ip *ipp;
+ struct Udphdr *udpp;
+ uchar binip[8], binenet[8], *enetaddr;
+
+ /* msglen is the length of the message, plus optionally the
+ * terminating null character (-n option of syslog command)..
+ */
+ msglen = strlen(msg) + null;
+
+ /* Convert IP address to binary:
+ */
+ if (IpToBin((char *)syslogsrvr,(unsigned char *)binip) < 0)
+ return(0);
+
+ /* Get the ethernet address for the IP:
+ */
+ enetaddr = ArpEther(binip,binenet,0);
+ if (!enetaddr) {
+ printf("ARP failed for %s\n",syslogsrvr);
+ return(0);
+ }
+
+ /* Retrieve an ethernet buffer from the driver and populate the
+ * ethernet level of packet:
+ */
+ enetp = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6);
+ memcpy((char *)&enetp->ether_dhost,(char *)binenet,6);
+ enetp->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it
+ * appropriately:
+ */
+ ipp = (struct ip *) (enetp + 1);
+ ipp->ip_vhl = IP_HDR_VER_LEN;
+ ipp->ip_tos = 0;
+ ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + msglen;
+ ipp->ip_len = ecs(ip_len);
+ ipp->ip_id = ipId();
+ ipp->ip_off = 0;
+ ipp->ip_ttl = UDP_TTL;
+ ipp->ip_p = IP_UDP;
+ memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4);
+ memcpy((char *)&ipp->ip_dst.s_addr,(char *)binip,4);
+
+ /* Now UDP...
+ */
+ sport = port+1;
+ udpp = (struct Udphdr *) (ipp + 1);
+ udpp->uh_sport = ecs(sport);
+ udpp->uh_dport = ecs(port);
+ udpp->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip)));
+
+ /* Finally, the SYSLOG data ...
+ */
+ syslogmsg = (uchar *)(udpp+1);
+ strcpy((char *)syslogmsg,(char *)msg);
+
+ ipChksum(ipp); /* Compute csum of ip hdr */
+ udpChksum(ipp); /* Compute UDP checksum */
+
+ sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + msglen);
+ return(0);
+}
+
+char *SyslogHelp[] = {
+ "Syslog client",
+ "-[f:lP:np:v] {srvr ip} {msg}",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -f {fac} specify facility",
+ " -l list facility & priority strings",
+ " -n append null-char to message",
+ " -P {##} override default port 514",
+ " -p {prio} specify priority",
+ " -v verbose",
+#endif
+ 0,
+};
+
+
+int
+SyslogCmd(int argc, char *argv[])
+{
+ char *facility, *priority, *msg;
+ int opt, verbose, fac_val, prio_val, val, port, null;
+
+ port = SYSLOG_PORT;
+ facility = priority = 0;
+ null = fac_val = prio_val = verbose = 0;
+
+ while((opt=getopt(argc,argv,"f:lnP:p:v")) != -1) {
+ switch(opt) {
+ case 'f':
+ facility = optarg;
+ break;
+ case 'l':
+ syslogInfo();
+ return(CMD_SUCCESS);
+ case 'n':
+ null = 1;
+ break;
+ case 'P':
+ port = atoi(optarg);
+ break;
+ case 'p':
+ priority = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc != optind+2)
+ return(CMD_PARAM_ERROR);
+
+ prio_val = getPriorityValue(priority);
+ fac_val = getFacilityValue(facility);
+
+ if ((prio_val == -1) || (fac_val == -1))
+ return(CMD_PARAM_ERROR);
+
+ val = (prio_val | fac_val);
+
+ if ((priority != 0) || (facility != 0)) {
+ msg = malloc(strlen(argv[optind+1])+16);
+ if (!msg)
+ return(CMD_FAILURE);
+ sprintf(msg,"<%d>%s",val,argv[optind+1]);
+ }
+ else
+ msg = argv[optind+1];
+
+ if (verbose)
+ printf("Syslog msg '%s' to %s\n",msg,argv[optind]);
+
+ sendSyslog((unsigned char *)argv[optind],msg,port,null);
+
+ if (val)
+ free(msg);
+
+ return(CMD_SUCCESS);
+}
+
+#endif
+
diff --git a/main/common/tcpstuff.c b/main/common/tcpstuff.c
new file mode 100644
index 0000000..8122637
--- /dev/null
+++ b/main/common/tcpstuff.c
@@ -0,0 +1,168 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tcpstuff.c
+ *
+ * Absolute minimum to properly refuse TCP connection requests to this
+ * device. The processTCP function is called if the incoming protocol is
+ * TCP, but this code simply responds with a TCP RESET which is essentially
+ * a refusal to establish the connection request being made from a remote
+ * machine.
+ * This is similar in functionality to the ICMP "destination unreachable
+ * message". Note that this is not an absolute necessity but it does
+ * provide a "clean" response to the remote machine that is making the
+ * connection request. Without it, the remote machine would keep trying
+ * to connect.
+ * For more details, refer to TCP/IP Comer 3rd Edition pg 216-219.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "endian.h"
+#if INCLUDE_ETHERNET
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+
+/* SendTcpConnectionReset():
+ * Called in response to any incoming TCP request.
+ * It is used to let the sender know that the TCP connection is being
+ * refused.
+ */
+int
+SendTcpConnectionReset(struct ether_header *re)
+{
+ short datalen, flags;
+ ulong ackno;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct tcphdr *ttcp, *rtcp;
+
+ ri = (struct ip *) (re + 1);
+ datalen = ecs(ri->ip_len) - ((ri->ip_vhl & 0x0f) * 4);
+
+ te = EtherCopy(re);
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ri->ip_len;
+ ti->ip_id = ri->ip_id;
+ ti->ip_off = ecs(IP_DONTFRAG);
+ ti->ip_ttl = ri->ip_ttl/2;
+ ti->ip_p = ri->ip_p;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ ttcp = (struct tcphdr *) (ti + 1);
+ rtcp = (struct tcphdr *) (ri + 1);
+ flags = ecs(rtcp->flags);
+ flags &= ~TCP_FLAGMASK;
+ flags |= (TCP_ACK | TCP_RESET);
+ ttcp->flags = ecs(flags);
+ ttcp->sport = rtcp->dport;
+ ttcp->dport = rtcp->sport;
+ memset((char *)&ttcp->seqno,0,4);
+ memcpy((char *)&ackno,(char *)&rtcp->seqno,4);
+ self_ecl(ackno);
+ ackno+=1;
+ self_ecl(ackno);
+ memcpy((char *)&ttcp->ackno,(char *)&ackno,4);
+
+ ttcp->windowsize = 0;
+ ttcp->urgentptr = 0;
+ memcpy((char *)(ttcp+1),(char *)(rtcp+1),datalen-sizeof(struct tcphdr));
+
+ ipChksum(ti); /* compute checksum of ip hdr: (3rd Edition Comer pg 100) */
+ tcpChksum(ti); /* Compute TCP checksum */
+
+ sendBuffer(sizeof(struct ether_header) + ecs(ti->ip_len));
+ return(0);
+}
+
+/* tcpChksum():
+ * Compute the checksum of the TCP packet.
+ * The incoming pointer is to an ip header, the tcp header after that ip
+ * header is directly populated with the result. Similar to the udp
+ * checksum calculation. This one is mandatory.
+ */
+void
+tcpChksum(struct ip *ihdr)
+{
+ register int i;
+ register ushort *sp;
+ register ulong t;
+ short len;
+ struct tcphdr *thdr;
+ struct UdpPseudohdr pseudohdr;
+
+ thdr = (struct tcphdr *)(ihdr+1);
+ thdr->tcpcsum = 0;
+
+ /* Start by building the pseudo header: */
+ memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4);
+ memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4);
+ pseudohdr.zero = 0;
+ pseudohdr.proto = ihdr->ip_p;
+ len = ecs(ihdr->ip_len) - sizeof(struct ip);
+ pseudohdr.ulen = ecs(len);
+
+ /* Get checksum of pseudo header: */
+ sp = (ushort *) &pseudohdr;
+ for (i=0,t=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++,sp++)
+ t += *sp;
+
+ /* If length is odd, pad and add one. */
+ if (len & 1) {
+ uchar *ucp;
+ ucp = (uchar *)thdr;
+ ucp[len] = 0;
+ len++;
+ }
+ len >>= 1;
+
+ sp = (ushort *) thdr;
+ for (i=0;i<len;i++,sp++)
+ t += *sp;
+ t = (t & 0xffff) + (t >> 16);
+ thdr->tcpcsum = ~t;
+}
+
+void
+tcperrmsg(char *msg)
+{
+ printf("TCP error: %s\n",msg);
+}
+
+void
+processTCP(struct ether_header *ehdr,ushort size)
+{
+ //struct ip *ipp;
+ //struct tcphdr *tcpp;
+
+ //ipp = (struct ip *)(ehdr + 1);
+ //tcpp = (struct tcphdr *)((char *)ipp + IP_HLEN(ipp));
+ SendTcpConnectionReset(ehdr);
+ return;
+}
+
+#endif
diff --git a/main/common/term.c b/main/common/term.c
new file mode 100644
index 0000000..67d198e
--- /dev/null
+++ b/main/common/term.c
@@ -0,0 +1,160 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * term.c:
+ *
+ * This file contains miscellaneous snippets of code that will allow
+ * umon to talk to a vt100-compatible terminal.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "genlib.h"
+#include "timer.h"
+#include "term.h"
+
+#if INCLUDE_TERM
+
+static int
+gettermtype(void)
+{
+ char *term = getenv("TERM");
+ int termtype = TERMTYPE_UNDEFINED;
+
+ if (term != 0) {
+ if (strcasecmp(term,"VT100") == 0)
+ termtype = TERMTYPE_VT100;
+ }
+
+ return(termtype);
+}
+
+int
+term_settextcolor(int fg)
+{
+ if (gettermtype() == TERMTYPE_VT100) {
+ printf("%c[%dm", 0x1B, fg + 30);
+ return(0);
+ }
+ return(-1);
+}
+
+int
+term_setbgcolor(int bg)
+{
+ if (gettermtype() == TERMTYPE_VT100) {
+ printf("%c[%dm", 0x1B, bg + 40);
+ return(0);
+ }
+ return(-1);
+}
+
+int
+term_settextattribute(int attr)
+{
+ if (gettermtype() == TERMTYPE_VT100) {
+ printf("%c[%dm", 0x1B, attr);
+ return(0);
+ }
+ return(-1);
+}
+
+
+int
+term_resettext(void)
+{
+ if (gettermtype() == TERMTYPE_VT100) {
+ printf("%c[0m",0x1b);
+ return(0);
+ }
+ return(-1);
+}
+
+/* term_getsize():
+ * Attempt to query the terminal for its row/col values...
+ */
+int
+term_getsize(int *rows, int *cols)
+{
+ int c, i, rtot, ctot;
+ char *semi, buf[16];
+ struct elapsed_tmr tmr;
+
+ if (gettermtype() == TERMTYPE_UNDEFINED)
+ return(-1);
+
+ setenv("ROWS",0);
+ setenv("COLS",0);
+
+ /* Send the "what is your terminal size?" request...
+ */
+ printf("\E[6n");
+
+ /* Wait for a response that looks like: "ESC[rrr;cccR"
+ * where 'rrr' is the number of rows, and 'ccc' is the
+ * number of columns.
+ */
+ memset(buf,0,sizeof(buf));
+ startElapsedTimer(&tmr,1000);
+ for(i=0;i<sizeof(buf);i++) {
+ while (!gotachar()) {
+ if(msecElapsed(&tmr)) {
+ return(-1);
+ }
+ }
+ c = getchar();
+ if ((i == 0) && (c != 0x1b)) {
+ return(-1);
+ }
+ if ((i == 1) && (c != '[')) {
+ return(-1);
+ }
+ if (c == 'R')
+ break;
+ buf[i] = c;
+ }
+ if (i == sizeof(buf)) {
+ return(-1);
+ }
+ semi = strchr(buf,';');
+ if (semi == (char *)0) {
+ return(-1);
+ }
+ *semi = 0;
+ buf[i] = 0;
+ rtot = atoi(buf+2);
+ ctot = atoi(semi+1);
+ shell_sprintf("ROWS","%d",rtot);
+ shell_sprintf("COLS","%d",ctot);
+ if (rows) *rows = rtot;
+ if (cols) *cols = ctot;
+ return(0);
+}
+
+void
+term_clearscreen(void)
+{
+ if (gettermtype() == TERMTYPE_VT100)
+ printf("\E[0J");
+}
+
+#endif
diff --git a/main/common/term.h b/main/common/term.h
new file mode 100644
index 0000000..274120c
--- /dev/null
+++ b/main/common/term.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * term.h:
+ *
+ * See term.c for details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ */
+#ifndef _TERM_H_
+#define _TERM_H_
+
+#define TERMTYPE_UNDEFINED 0
+#define TERMTYPE_VT100 1
+
+/* Font attributes:
+ */
+#define ATTR_RESET 0
+#define ATTR_BRIGHT 1
+#define ATTR_DIM 2
+#define ATTR_UNDERLINE 3
+#define ATTR_BLINK 4
+#define ATTR_REVERSE 7
+#define ATTR_HIDDEN 8
+
+/* Font colors:
+ */
+#define BLACK 0
+#define RED 1
+#define GREEN 2
+#define YELLOW 3
+#define BLUE 4
+#define MAGENTA 5
+#define CYAN 6
+#define WHITE 7
+
+extern int term_settextcolor(int fg);
+extern int term_setbgcolor(int bg);
+extern int term_resettext(void);
+extern int term_getsize(int *row, int *col);
+
+#endif
+
+
diff --git a/main/common/tfs.c b/main/common/tfs.c
new file mode 100644
index 0000000..5223ba2
--- /dev/null
+++ b/main/common/tfs.c
@@ -0,0 +1,3379 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfs.c:
+ *
+ * Tiny File System
+ * TFS supports the ability to store/access files in flash. The TFS
+ * functions provide a command at the monitor's user interface (the
+ * "tfs" command) as well as a library of functions that are available to
+ * the monitor/application code on this target (TFS api).
+ *
+ * The code that supports TFS in the MicroMonitor package spans across
+ * several files. This is done so that various pieces of TFS can optionally
+ * be compiled in or out (using INCLUDE_XXX macros in config.h) of the
+ * monitor package...
+ *
+ * tfs.c:
+ * Core TFS code that cannot be optionally omitted without eliminating
+ * the TFS facility from the monitor.
+ *
+ * tfsapi.c:
+ * This file contains the code that supports the application's ability
+ * to use the TFS api. Since some of the api is used by the monitor
+ * itself, not all of the api-specific code is there, some of it is
+ * in tfs.c.
+ *
+ * tfscleanX.c:
+ * TFS can be configured with one of several different flash defrag
+ * mechanisms. Currently, tfsclean[123].c are available.
+ *
+ * tfscli.c:
+ * If you don't need the "tfs" command in your command line interface,
+ * then the code in this file can be omitted.
+ *
+ * tfsloader.c:
+ * TFS can support COFF, ELF or A.OUT binary file formats. The code
+ * to load each of these formats from flash to RAM is here.
+ *
+ * tfslog.c:
+ * If there is a need to log flash interaction to a file, then this
+ * file contains code to support that.
+ *
+ *
+ * NOTES:
+ * * Dealing with multiple task access:
+ * Since the monitor is inherently a single threaded program
+ * potentially being used in a multi-tasking environment, the monitor's
+ * access functions (API) must be provided with a lock/unlock
+ * wrapper that will guarantee sequential access to all of the monitor
+ * facilities. Refer to monlib.c to see this implementation. This
+ * provides the protection needed by TFS to keep multiple "mon_"
+ * functions from being executed by different tasks.
+ * Note that originally this was supported with tfsctrl(TFS_MUTEX ) and
+ * it only protected the tfs API functions. This turned out to be
+ * insufficient because it did not prevent other tasks from calling
+ * other non-tfs functions in the monitor while tfs access (and
+ * potentially, flash update) was in progress. This meant that a flash
+ * update could be in progress and some other task could call mon_getenv()
+ * (for example). This could screw up the flash update because
+ * mon_getenv() might be fetched out of the same flash device that
+ * the TFS operation is being performed on.
+ *
+ * * Dealing with cache coherency:
+ * I believe the only concern here is that Icache must be invalidated
+ * and Dcache must be flushed whenever TFS does a memory copy that may
+ * ultimately be executable code. This is handled at the end of the
+ * tfsmemcpy function by calling flushDcache() and invalidateIcache().
+ * It is the application's responsibility to give the monitor the
+ * appropriate functions (see assigncachefuncs()) if necessary.
+ *
+ * * Configuring a device to run as TFS memory:
+ * Assuming you are using power-safe cleanup...
+ * TFS expects that on any given device used for storage of files, the
+ * device is broken up into some number of sectors with the last sector
+ * being the largest and used as the spare sector for defragmentation.
+ * All other sector sizes must be smaller than the SPARE sector and the
+ * sector just prior to the spare is used for defragmentation state
+ * overhead. This sector should be large enough to allow the overhead
+ * space to grow down from the top without filling the sector. For most
+ * flash devices, these two sectors (spare and overhead) are usually the
+ * same size and are large. For FlashRam, the device should be configured
+ * so that these two sectors are large. The spare sector will never be
+ * allowed to contain any file information (because it is 100% dedicated to
+ * the defragmentation process) and the sector next to this can have files
+ * in it, but the overhead space is also in this sector.
+ *
+ * * Testing TFS:
+ * There are three files dedicated to testing the file system. Two of them
+ * (tfstestscript & tfstestscript1) are scripts that are put into the
+ * file system and run. The third file (tfstest.c) is a piece of code
+ * that can be built into a small application that runs out of TFS to test
+ * all of the API functionality.
+ * - tfstestscript:
+ * This script is used to simply bang on normal defragmentation. It
+ * builds files with sizes and names based on the content of memory
+ * starting at $APPRAMBASE. Changing the content of memory starting at
+ * $APPRAMBASE will change the characteristics of this test so it is
+ * somewhat random. It is not 100% generic, but can be used as a
+ * base for testing TFS on various systems.
+ * - tfstestscript1:
+ * This script is used to bang on the power-safe defragmentation of
+ * TFS. It simulates power hits that might occur during defragmentation.
+ * This script assumes that the monitor has been built with the
+ * DEFRAG_TEST_ENABLED flag set.
+ * - tfstest.c:
+ * This code can be built into a small application that will thoroughly
+ * exercise the TFS API. This file can also be used as a reference for
+ * some examples of TFS api usage.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "tfsdev.h"
+#include "flash.h"
+#include "cli.h"
+
+#if INCLUDE_TFS
+
+int tfsrun_abortableautoboot(char **arglist,int verbose);
+char *(*tfsGetAtime)(long,char *,int);
+long (*tfsGetLtime)(void);
+int (*tfsDocommand)(char *,int);
+TDEV tfsDeviceTbl[TFSDEVTOT+1]; /* See notes above tfsramdevice() */
+TFILE **tfsAlist;
+struct tfsdat tfsSlots[TFS_MAXOPEN];
+long tfsTrace;
+int TfsCleanEnable;
+long tfsFmodCount;
+char tfsInitialized;
+
+static void pre_tfsautoboot_hook(void);
+
+static int tfsAlistSize, tfsOldDelFlagCheckActive;
+static int tfsMonrcActive;
+
+/* alt_tfsdevtbl[]:
+ * This pre-initialized table of "flash-empty" tfsdev structures allows
+ * the user to override the default configuration of TFS as it is defined
+ * in tfsdev.h in the port directory. This is primarily useful for cases
+ * where uMon is being deployed on an evaluation board and the users have
+ * varying needs for TFS and it's use of the on-board flash memory.
+ *
+ * If TFS_ALTDEVTBL_BASE is defined, then the flash space used as the
+ * alternate device table can be anywhere in flash memory. Obviously
+ * it has to be in space that is not used by anything else (and is erased
+ * if not in use); however, this does provide the user with the option to
+ * allocate one sector of flash for this; thus allowing the structure to
+ * be re-written by simply eraseing that sector.
+ */
+#ifdef TFS_ALTDEVTBL_BASE
+
+struct tfsdev *alt_tfsdevtbl = (struct tfsdev *)TFS_ALTDEVTBL_BASE;
+
+#else
+
+/* The following initialized array uses a GNU-extension to
+ * force an array of structures and an array of arrays be initialized
+ * to 0xff in flash. This may break for other compilers (in that case,
+ * define TFS_ALTDEVTBL_BASE). This syntax is discussed in gcc.gnu.org
+ * online documentation under the topic "Designated Initializers".
+ */
+struct tfsdev alt_tfsdevtbl[TFSDEVTOT] = {
+ [0 ... (TFSDEVTOT-1)] =
+ { (char *)0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
+};
+
+#endif
+
+#define TFS_ALTDEVTBL_SIZE (TFSDEVTOT * sizeof(struct tfsdev))
+
+/* tfsflgtbl & tfserrtbl:
+ * Tables that establish an easy lookup mechanism to convert from
+ * bitfield to string or character.
+ * Note that TFS_ULVL0 is commented out. I leave it in here as a place
+ * holder (comment), but it actually is not needed becasue ulvl_0 is the
+ * default if no other ulvl is specified.
+ */
+struct tfsflg tfsflgtbl[] = {
+ { TFS_BRUN, 'b', "run_at_boot", TFS_BRUN },
+ { TFS_QRYBRUN, 'B', "qry_run_at_boot", TFS_QRYBRUN },
+ { TFS_EXEC, 'e', "executable", TFS_EXEC },
+ { TFS_SYMLINK, 'l', "symbolic link", TFS_SYMLINK },
+ { TFS_EBIN, 'E', TFS_EBIN_NAME, TFS_EBIN },
+ { TFS_IPMOD, 'i', "inplace_modifiable", TFS_IPMOD },
+ { TFS_UNREAD, 'u', "ulvl_unreadable", TFS_UNREAD },
+/* { TFS_ULVL0, '0', "ulvl_0", TFS_ULVLMSK }, */
+ { TFS_ULVL1, '1', "ulvl_1", TFS_ULVLMSK },
+ { TFS_ULVL2, '2', "ulvl_2", TFS_ULVLMSK },
+ { TFS_ULVL3, '3', "ulvl_3", TFS_ULVLMSK },
+ { 0, 0, 0, 0 }
+};
+
+static struct tfserr tfserrtbl[] = {
+ { TFS_OKAY, "no error" },
+ { TFSERR_NOFILE, "file not found" },
+ { TFSERR_NOSLOT, "max fps opened" },
+ { TFSERR_EOF, "end of file" },
+ { TFSERR_BADARG, "bad argument" },
+ { TFSERR_NOTEXEC, "not executable" },
+ { TFSERR_BADCRC, "bad crc" },
+ { TFSERR_FILEEXISTS, "file already exists" },
+ { TFSERR_FLASHFAILURE, "flash operation failed" },
+ { TFSERR_WRITEMAX, "max write count exceeded" },
+ { TFSERR_RDONLY, "file is read-only" },
+ { TFSERR_BADFD, "invalid descriptor" },
+ { TFSERR_BADHDR, "bad binary executable header" },
+ { TFSERR_CORRUPT, "corrupt file" },
+ { TFSERR_MEMFAIL, "memory failure" },
+ { TFSERR_NOTIPMOD, "file is not in-place-modifiable" },
+ { TFSERR_FLASHFULL, "out of flash space" },
+ { TFSERR_USERDENIED, "user level access denied" },
+ { TFSERR_NAMETOOBIG, "name or info field too big" },
+ { TFSERR_FILEINUSE, "file in use" },
+ { TFSERR_NOTAVAILABLE, "tfs facility not available" },
+ { TFSERR_BADFLAG, "bad flag" },
+ { TFSERR_CLEANOFF, "defragmentation is disabled" },
+ { TFSERR_FLAKEYSOURCE, "dynamic source data" },
+ { TFSERR_BADEXTENSION, "invalid file extension" },
+ { TFSERR_LINKERROR, "file link error" },
+ { TFSERR_BADPREFIX, "invalid device prefix" },
+ { TFSERR_ALTINUSE, "alternate devcfg in use" },
+ { TFSERR_NORUNMONRC, "can't run from monrc" },
+ { TFSERR_DSIMAX, "out of DSI space" },
+ { TFSERR_TOOSMALL, "partition size too small" },
+ { 0,0 }
+};
+
+
+/* dummyAtime() & dummyLtime():
+ * These two functions are loaded into the function pointers as defaults
+ * for the time-retrieval stuff used in TFS.
+ */
+static char *
+dummyAtime(long tval,char *buf,int buflen)
+{
+/* strcpy(buf,"Fri Sep 13 00:00:00 1986"); */
+ *buf = 0;
+ return(buf);
+}
+
+static long
+dummyLtime(void)
+{
+ return(TIME_UNDEFINED);
+}
+
+/* getdfsdev():
+ * Input is a file pointer; based on that pointer return the appropriate
+ * device header pointer. If error, just return 0.
+ * A "device" in TFS is some block of some type of memory that is assumed
+ * to be contiguous space that can be configured as a block of sectors (to
+ * look like flash). For most systems, there is only one (the flash);
+ * other systems may have battery-backed RAM, etc...
+ * Note that this is not fully implemented.
+ */
+static TDEV *
+gettfsdev(TFILE *fp)
+{
+ TDEV *tdp;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if ((fp >= (TFILE *)tdp->start) &&
+ (fp < (TFILE *)tdp->end))
+ return(tdp);
+ }
+ return(0);
+}
+
+TDEV *
+gettfsdev_fromprefix(char * prefix, int verbose)
+{
+ TDEV *tdp;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!strcmp(prefix,tdp->prefix))
+ return(tdp);
+ }
+ if (verbose)
+ printf("Bad device prefix: %s\n",prefix);
+ return(0);
+}
+
+/* tfsspace():
+ * Return 1 if the incoming address is within TFS space; else
+ * return 0.
+ */
+int
+tfsspace(char *addr)
+{
+ TDEV *tdp;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if ((addr >= (char *)tdp->start) &&
+ (addr <= (char *)tdp->end))
+ return(1);
+ if ((addr >= (char *)tdp->spare) &&
+ (addr < (char *)(tdp->spare+tdp->sparesize)))
+ return(1);
+ }
+ return(0);
+}
+
+#ifndef TFS_NON_STANDARD_FLASH_INTERFACE
+/* tfsflasherase(), tfsflasheraseall() & tfsflashwrite():
+ * Wrappers for corresponding flash operations. The wrappers are used
+ * to provide one place for the incrmentation of tfsFmodCount.
+ *
+ * In almost all cases, this code is included here; however, there
+ * are some cases where the flash access functions that TFS uses must
+ * be port-specific; hence, TFS_NON_STANDARD_FLASH_INTERFACE would be defined
+ * in config.h and they would be provided by the port .
+ */
+int
+tfsflasheraseall(TDEV *tdp)
+{
+#if INCLUDE_FLASH
+ int snum, last;
+
+ if (tfsTrace > 2)
+ printf(" tfsflasheraseall(%s)\n",tdp->prefix);
+
+ tfsFmodCount++;
+
+ /* Erase the sectors within the device that are used for file store...
+ */
+ if (addrtosector((uchar *)tdp->start,&snum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+ last = snum + tdp->sectorcount;
+
+ while(snum < last) {
+ if (AppFlashErase(snum++) <= 0)
+ return(TFSERR_MEMFAIL);
+ }
+
+ /* Erase the spare (if there is one)...
+ * (if this system is configured with tfsclean2.c, then
+ * there is no need for a spare sector).
+ */
+ if (tdp->spare) {
+ if (addrtosector((uchar *)tdp->spare,&snum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+ if (AppFlashErase(snum) <= 0)
+ return(TFSERR_MEMFAIL);
+ }
+#else
+ memset((void *)tdp->start,(int)0xff,(int)(tdp->end-tdp->start));
+#endif
+ return(TFS_OKAY);
+}
+
+int
+tfsflasherase(int snum)
+{
+#if INCLUDE_FLASH
+ if (tfsTrace > 2)
+ printf(" tfsflasherase(%d)\n",snum);
+
+ tfsFmodCount++;
+ return(AppFlashErase(snum));
+#else
+ return(TFSERR_NOTAVAILABLE);
+#endif
+}
+
+int
+tfsflashwrite(uchar *dest,uchar *src,long bytecnt)
+{
+#if INCLUDE_FLASH
+ if (tfsTrace > 2)
+ printf(" tfsflashwrite(0x%lx,0x%lx,%ld)\n",
+ (ulong)dest,(ulong)src,bytecnt);
+
+ if (bytecnt < 0)
+ return(TFSERR_BADARG);
+
+ tfsFmodCount++;
+
+ if (AppFlashWrite(dest,src,bytecnt) == 0)
+ return(TFS_OKAY);
+ else
+ return(TFSERR_FLASHFAILURE);
+#else
+ return(TFSERR_NOTAVAILABLE);
+#endif
+}
+
+#endif /* TFS_NON_STANDARD_FLASH_INTERFACE */
+
+/* tfserrmsg():
+ * Return the error message string that corresponds to the incoming
+ * tfs error number.
+ */
+char *
+tfserrmsg(int errno)
+{
+ struct tfserr *tep;
+
+ tep = tfserrtbl;
+ while(tep->msg) {
+ if (errno == tep->err)
+ return(tep->msg);
+ tep++;
+ }
+ return("unknown tfs errno");
+}
+
+/* tfsmakeStale():
+ * Modify the state of a file to be stale.
+ * Do this by clearing the TFS_NOTSTALE flag in the tfs header.
+ * This function is used by tfsadd() when in the process of
+ * updating a file that already exists in the flash.
+ * See comments above tfsadd() for more details on the TFS_NOTSTALE flag.
+ */
+static int
+tfsmakeStale(TFILE *tfp)
+{
+ ulong flags;
+
+ flags = TFS_FLAGS(tfp) & ~TFS_NSTALE;
+ return(tfsflashwrite((uchar *)&tfp->flags,(uchar *)&flags,
+ (long)sizeof(long)));
+}
+
+/* tfsflagsbtoa():
+ * Convert binary flags to ascii and return the string.
+ */
+char *
+tfsflagsbtoa(long flags,char *fstr)
+{
+ int i;
+ struct tfsflg *tfp;
+
+ if ((!flags) || (!fstr))
+ return((char *)0);
+
+ i = 0;
+ tfp = tfsflgtbl;
+ *fstr = 0;
+ while(tfp->sdesc) {
+ if ((flags & tfp->mask) == tfp->flag)
+ fstr[i++] = tfp->sdesc;
+ tfp++;
+ }
+ fstr[i] = 0;
+ return(fstr);
+}
+
+/* tfsflagsatob():
+ * Convert ascii flags to binary and return the long.
+ */
+int
+tfsflagsatob(char *fstr, long *flag)
+{
+ struct tfsflg *tfp;
+
+ *flag = 0;
+
+ if (!fstr)
+ return(TFSERR_BADFLAG);
+
+ while(*fstr) {
+ tfp = tfsflgtbl;
+ while(tfp->sdesc) {
+ if (*fstr == tfp->sdesc) {
+ *flag |= tfp->flag;
+ break;
+ }
+ tfp++;
+ }
+ if (!tfp->flag)
+ return(TFSERR_BADFLAG);
+ fstr++;
+ }
+ return(TFS_OKAY);
+}
+
+/* hdrcrc():
+ * The crc of the file header was originally calculated (in tfsadd())
+ * with the header crc and next pointer nulled out; so a copy must
+ * be made and these two fields cleared. Also, note that the
+ * TFS_NSTALE and TFS_ACTIVE flags are forced to be set in the copy.
+ * This is done because it is possible that either of these bits may
+ * have been cleared due to other TFS interaction; hence, they need
+ * to be set prior to crc calculation.
+ * Note also that earlier versions of TFS deleted a file by clearing
+ * the entire flags field. This made it impossible to do a header crc
+ * check on a deleted file; deletion has been changed to simply clear
+ * the TFS_ACTIVE bit in the flags, so now a deleted file's header can
+ * can be crc tested by simply forcing the TFS_ACTIVE bit high as was
+ * mentioned above.
+ */
+ulong
+tfshdrcrc(TFILE *hdr)
+{
+ TFILE hdrcpy;
+
+ memcpy((char *)&hdrcpy,(char *)hdr,sizeof(TFILE));
+ hdrcpy.next = 0;
+ hdrcpy.hdrcrc = 0;
+ hdrcpy.flags |= (TFS_NSTALE | TFS_ACTIVE);
+ return(crc32((uchar *)&hdrcpy,TFSHDRSIZ));
+}
+
+/* validtfshdr():
+ * Return 1 if the header pointed to by the incoming header pointer is valid.
+ * Else return 0. The header crc is calculated based on the hdrcrc
+ * and next members of the structure being zero.
+ * Note that if the file is deleted, then just ignore the crc and return 1.
+ */
+int
+validtfshdr(TFILE *hdr)
+{
+ /* A few quick checks... */
+ if (!hdr || hdr->hdrsize == ERASED16)
+ return(0);
+
+ if (tfshdrcrc(hdr) == hdr->hdrcrc) {
+ return(1);
+ }
+ else {
+ /* Support transition to new deletion flag method...
+ */
+ if ((hdr->flags == 0) && tfsOldDelFlagCheckActive)
+ return(1);
+
+ printf("Bad TFS hdr crc @ 0x%lx\n",(ulong)hdr);
+ return(0);
+ }
+}
+
+/* nextfp():
+ * Used as a common means of retrieving the next file header pointer. It
+ * does some sanity checks based on the fact that all pointers must fall
+ * within the TFSSTART<->TFSEND memory range and since each file is placed
+ * just after the previous one in linear memory space, fp->next should
+ * always be greater than fp.
+ */
+TFILE *
+nextfp(TFILE *fp, TDEV *tdp)
+{
+ if (!tdp)
+ tdp = gettfsdev(fp);
+
+ /* Make some basic in-range checks...
+ */
+ if ((!tdp) || (fp < (TFILE *)tdp->start) || (fp > (TFILE *)tdp->end) ||
+ (fp->next < (TFILE *)tdp->start) || (fp->next > (TFILE *)tdp->end) ||
+ (fp->next <= fp)) {
+ printf("Bad TFS hdr ptr @ 0x%lx\n",(ulong)fp);
+ return(0);
+ }
+ return(fp->next);
+}
+
+/* tfsflasherased():
+ * Jump to the point in flash after the last file in TFS, then verify
+ * that all remaining flash that is dedicated to TFS is erased (0xff).
+ * If erased, return 1; else return 0.
+ */
+int
+tfsflasherased(TDEV *tdp, int verbose)
+{
+ ulong *lp;
+ TFILE *tfp;
+
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp))
+ tfp = nextfp(tfp,tdp);
+
+ lp = (ulong *)tfp;
+ while (lp < (ulong *)tdp->end) {
+ if (*lp != ERASED32) {
+ if (verbose)
+ printf("End of TFS on %s not erased at 0x%lx\n",
+ tdp->prefix,(ulong)lp);
+ return(0);
+ }
+#ifdef WATCHDOG_ENABLED
+ if (((ulong)lp & 0x3f) == 0)
+ WATCHDOG_MACRO;
+#endif
+ lp++;
+ }
+ return(1);
+}
+
+static int
+tfsftot(TDEV *tdpin)
+{
+ int ftot;
+ TFILE *tfp;
+ TDEV *tdp;
+
+ ftot = 0;
+ for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!tdpin || (tdpin == tdp)) {
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp))
+ ftot++;
+ tfp = nextfp(tfp,tdp);
+ }
+ }
+ }
+ return(ftot);
+}
+
+/* tfsmemuse():
+ * Step through one (or all) TFS devices and tally up various memory usage
+ * totals. See definition of tfsmem structure for more details.
+ * If incoming tdpin pointer is NULL, then tally up for all TFS devices;
+ * otherwise, tally up for only the one device pointed to by tdpin.
+ */
+int
+tfsmemuse(TDEV *tdpin, TINFO *tinfo, int verbose)
+{
+ TFILE *tfp;
+ TDEV *tdp, *dsimax;
+ int devtot, devidx, ftot, fmax;
+ char *cfgerr, varname[TFSNAMESIZE+16];
+
+ /* Start by clearing incoming structure...
+ */
+ tinfo->pso = 0;
+ tinfo->sos = 0;
+ tinfo->memtot = 0;
+ tinfo->liveftot = 0;
+ tinfo->deadftot = 0;
+ tinfo->livedata = 0;
+ tinfo->deaddata = 0;
+ tinfo->liveovrhd = 0;
+ tinfo->deadovrhd = 0;
+ tinfo->sectortot = 0;
+
+ if (verbose) {
+ printf("TFS Memory Usage...\n ");
+ printf(" name start end spare spsize scnt type\n");
+ }
+
+ devtot = fmax = 0;
+ for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++)
+ devtot++;
+
+ devidx = 0;
+ dsimax = 0;
+ for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!tdpin || (tdpin == tdp)) {
+ tfp = (TFILE *)tdp->start;
+
+ cfgerr = (char *)0;
+
+ /* Do some sanity checks on the configuration...
+ */
+ if ((tdp->spare >= tdp->start) && (tdp->spare <= tdp->end)) {
+ cfgerr = "spare within storage space";
+ }
+ if (cfgerr) {
+ printf("Bad %s TFS config: %s.\n",tdp->prefix,cfgerr);
+ }
+
+ /* Store TFS device info to shell variables.
+ */
+ sprintf(varname,"TFS_PREFIX_%d", devidx);
+ shell_sprintf(varname,"%s",tdp->prefix);
+
+ sprintf(varname,"TFS_START_%d", devidx);
+ shell_sprintf(varname,"0x%lx",tdp->start);
+
+ sprintf(varname,"TFS_END_%d", devidx);
+ shell_sprintf(varname,"0x%lx",tdp->end);
+
+ sprintf(varname,"TFS_SPARE_%d", devidx);
+ shell_sprintf(varname,"0x%lx",tdp->spare);
+
+ sprintf(varname,"TFS_SPARESZ_%d", devidx);
+ shell_sprintf(varname,"0x%lx",tdp->sparesize);
+
+ sprintf(varname,"TFS_SCNT_%d", devidx);
+ shell_sprintf(varname,"%d",tdp->sectorcount);
+
+ sprintf(varname,"TFS_DEVINFO_%d", devidx);
+ shell_sprintf(varname,"0x%lx",tdp->devinfo);
+
+ if (verbose) {
+ printf("%10s: 0x%08lx|0x%08lx|",
+ tdp->prefix,(ulong)(tdp->start),(ulong)(tdp->end));
+
+ if (TFS_DEVTYPE_ISRAM(tdp))
+ printf(" - NA - | - NA - | NA ");
+ else
+ printf("0x%08lx|0x%06lx|%4ld",(ulong)(tdp->spare),
+ tdp->sparesize,tdp->sectorcount);
+
+ printf("|0x%lx\n",(ulong)(tdp->devinfo));
+ }
+ tinfo->memtot += ((tdp->end - tdp->start) + 1) + tdp->sparesize;
+ tinfo->pso += (tdp->sectorcount * 4) + 16;
+ tinfo->sos += tdp->sparesize;
+ tinfo->sectortot += tdp->sectorcount;
+ ftot = 0;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ ftot++;
+ tinfo->liveftot++;
+ tinfo->livedata += TFS_SIZE(tfp);
+ tinfo->liveovrhd += (TFSHDRSIZ + DEFRAGHDRSIZ);
+ }
+ else {
+ tinfo->deadftot++;
+ tinfo->deaddata += TFS_SIZE(tfp);
+ tinfo->deadovrhd += TFSHDRSIZ;
+ }
+ tfp = nextfp(tfp,tdp);
+ }
+
+#if INCLUDE_FLASH
+ /* Keep track of how many files are stored, relative to the
+ * size of the sector used to store DSI info at defrag time...
+ */
+ if (!TFS_DEVTYPE_ISRAM(tdp)) {
+ int sector_ovrhd, ssize;
+
+ if (addrtosector((uchar *)(tdp->end),0,&ssize,0) < 0)
+ return(TFSERR_MEMFAIL);
+ sector_ovrhd = tdp->sectorcount * sizeof(struct sectorcrc);
+
+ if ((((ftot + 1) * DEFRAGHDRSIZ) + sector_ovrhd) > ssize)
+ dsimax = tdp;
+
+ fmax += (ssize - sector_ovrhd)/DEFRAGHDRSIZ;
+ }
+#endif
+ }
+ devidx++;
+ }
+ shell_sprintf("TFS_DEVTOT","%d",devtot);
+
+ tinfo->memused = tinfo->livedata + tinfo->liveovrhd +
+ tinfo->deaddata + tinfo->deadovrhd + tinfo->pso + tinfo->sos +
+ tinfo->sectortot * sizeof(struct sectorcrc);
+ tinfo->memfree = tinfo->memtot - tinfo->memused;
+
+ /* Remaining space may not even be big enough to contain the
+ * file overhead, if this is the case, show a remaining space
+ * of zero rather than a negative number...
+ */
+ tinfo->memfordata =
+ tinfo->memfree - (devtot * (TFSHDRSIZ + DEFRAGHDRSIZ));
+ if (tinfo->memfordata < 0)
+ tinfo->memfordata = 0;
+
+
+ if (verbose) {
+ printf("\n Total memory: %d bytes (used=%d, avail=%d (%d for data)).\n",
+ tinfo->memtot,tinfo->memused,tinfo->memfree, tinfo->memfordata);
+ printf(" Per-device overhead: %d bytes ",tinfo->pso+tinfo->sos);
+ printf("(defrag-state=%d spare-sector=%d).\n",tinfo->pso,tinfo->sos);
+ printf(" File data space: %d bytes (live=%d, dead=%d).\n",
+ tinfo->livedata+tinfo->deaddata,
+ tinfo->livedata,tinfo->deaddata);
+ printf(" File overhead space: %d bytes (live=%d, dead=%d).\n",
+ tinfo->liveovrhd+tinfo->deadovrhd,
+ tinfo->liveovrhd,tinfo->deadovrhd);
+ printf(" Sector overhead space: %d bytes.\n",
+ tinfo->sectortot*sizeof(struct sectorcrc));
+ printf(" File count: %d (live=%d, dead=%d).\n",
+ tinfo->liveftot+tinfo->deadftot,tinfo->liveftot,tinfo->deadftot);
+ printf(" Defrag will release %d bytes\n",
+ tinfo->deadovrhd+tinfo->deaddata);
+ printf(" Max # files storable in flash: %d\n",fmax);
+ if (dsimax)
+ printf(" Device '%s' has max Defrag-State-Info\n",dsimax->prefix);
+ printf("\n");
+ }
+ return(tinfo->liveftot + tinfo->deadftot);
+}
+
+/* tfscheck():
+ * Step through each file in a particular device making a few checks...
+ * - First look at the header. If hdrsize is erased, it "should" indicate
+ * the end of the linear list of files. To be anal about it, verify that
+ * the entire header is erased. If it is, we truly are at the end of the
+ * list; otherwise, header error.
+ * - Second, do a crc32 on the header.
+ * - Third, if the file is not deleted, then do a crc32 on the data portion
+ * of the file (if the file is deleted, then it really doesn't matter if
+ * there is a crc32 error on that data).
+ * - Finally, if the header is not corrupted, index to the next pointer and
+ * continue. If the header is corrupt, see if enough information
+ * in the header is valid to allow us to step to the next file. Do this
+ * by calculating where the next pointer should be (using current pointer,
+ * file+header size and mod16 adjustment) and then see if that matches the
+ * value stored in the actual "next" pointer. If yes, go to next file;
+ * else break out of the loop.
+ *
+ * The purpose is to do more sophisticated file system checks than are
+ * done in normal TFS operations.
+ */
+#define TFS_CORRUPT 1
+#define HDR_CORRUPT 2
+#define DATA_CORRUPT 4
+
+int
+tfscheck(TDEV *tdp, int verbose)
+{
+ TFILE *fp, *fp1;
+ int tfscorrupt, filtot, err;
+
+ /* If the incoming device pointer is null, then loop through all
+ * devices in TFS, recursively calling tfscheck() with each pointer...
+ */
+ if (!tdp) {
+ for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ err = tfscheck(tdp,verbose);
+ if (err != TFS_OKAY)
+ return(err);
+ }
+ return(TFS_OKAY);
+ }
+
+ if (verbose)
+ printf("TFS device %s check:\n",tdp->prefix);
+
+ filtot = tfscorrupt = 0;
+
+ fp = (TFILE *)tdp->start;
+ while(1) {
+ tfscorrupt &= ~(HDR_CORRUPT | DATA_CORRUPT);
+
+ /* If hdrsize is ERASED16, then verify that the whole header is
+ * also ERASED16, if yes, we're at the end of the linear list of
+ * files; otherwise, we have a corrupt header.
+ */
+ if (fp->hdrsize == ERASED16) {
+ int i;
+ ushort *sp;
+
+ /* If this is right at the edge of the end of the TFS device,
+ * then break with no further checks to this header.
+ */
+ if ((fp+1) > (TFILE *)tdp->end)
+ break;
+
+ /* Make sure the entire header is erased...
+ */
+ sp = (ushort *)fp;
+ for(i=0;i<TFSHDRSIZ;i+=2,sp++) {
+ if (*sp != ERASED16) {
+ if (verbose)
+ printf(" Corrupt hdr @ 0x%lx",(ulong)fp);
+ tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
+ break;
+ }
+ }
+ if (!(tfscorrupt & HDR_CORRUPT))
+ break;
+ else
+ goto nextfile;
+ }
+
+ /* Run a crc check on the header even if file is deleted...
+ */
+ if (tfshdrcrc(fp) != fp->hdrcrc) {
+ if (verbose)
+ printf(" CRC error in hdr @ 0x%lx\n",(ulong)fp);
+ tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
+ goto nextfile;
+ }
+
+ /* If file exists, and it's not IPMOD, run a crc check on data...
+ */
+ if (TFS_FILEEXISTS(fp) && !(fp->flags & TFS_IPMOD)) {
+ filtot++;
+ if (verbose)
+ printf(" %s...",fp->name);
+
+ if ((!(fp->flags & TFS_IPMOD)) &&
+ (crc32((uchar *)(TFS_BASE(fp)),fp->filsize) != fp->filcrc)) {
+ if (verbose)
+ printf(" CRC error in data");
+ tfscorrupt = DATA_CORRUPT | TFS_CORRUPT;
+ }
+ else {
+ if (verbose)
+ printf(" ok");
+ }
+ }
+
+ /* Prior to incrementing to the next file pointer, if the header
+ * is corrupted, attempt to salvage the next pointer...
+ * If the value of the next pointer matches what is calculated
+ * from the file size and header size, then assume it is ok
+ * and allow the tfscheck() loop to continue; otherwise break.
+ */
+nextfile:
+ if (tfscorrupt & HDR_CORRUPT) {
+ if (fp->next) {
+ ulong modnext;
+
+ modnext = (ulong)((int)(fp+1) + fp->filsize);
+ if (modnext & 0xf) {
+ modnext += 16;
+ modnext &= ~0xf;
+ }
+ if (verbose)
+ printf(" (next ptr ");
+ if (fp->next != (TFILE *)modnext) {
+ if (verbose)
+ printf("damaged)\n");
+ break;
+ }
+ else {
+ if (verbose)
+ printf("salvaged)");
+ }
+ }
+ }
+ fp1 = nextfp(fp,tdp);
+ if (!fp1) {
+ tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
+ break;
+ }
+ if ((verbose) && (TFS_FILEEXISTS(fp) || tfscorrupt))
+ putchar('\n');
+ fp = fp1;
+ }
+ tfsflasherased(tdp,verbose);
+ if (tfscorrupt)
+ return(TFSERR_CORRUPT);
+ if (verbose)
+ printf(" PASSED\n");
+ return (TFS_OKAY);
+}
+
+void
+tfsclear(TDEV *tdp)
+{
+ int i;
+
+ /* Clear the fileslot[] table indicating that no files are opened.
+ * Only clear the slots applicable to the incoming TDEV pointer.
+ */
+ for (i = 0; i < TFS_MAXOPEN; i++) {
+ ulong offset;
+
+ offset = tfsSlots[i].offset;
+ if (offset != (ulong)-1) {
+ if ((tdp == (TDEV *)0) ||
+ ((offset >= tdp->start) && (offset <= tdp->end)))
+ tfsSlots[i].offset = -1;
+ }
+ }
+
+ /* If the incoming TDEV pointer is NULL, then we can assume a global
+ * clear and go ahead and cleanup everything; otherwise, we just return
+ * here.
+ */
+ if (tdp != (TDEV *)0)
+ return;
+
+ /* Turn off tracing.
+ */
+ tfsTrace = 0;
+
+ /* Init the time retrieval function pointers to their dummy values.
+ */
+ tfsGetAtime = dummyAtime;
+ tfsGetLtime = dummyLtime;
+
+ /* Default to using standard docommand() within scripts.
+ */
+ tfsDocommand = docommand;
+
+ /* Start off with a buffer for 16 files. This is probably more than
+ * will be used, so it avoids reallocations in tfsreorder().
+ *
+ * Note that this function may be called as a result of the monitor
+ * doing an application exit. In that case, the heap is not
+ * re-initialized; hence, tfsAlist may already be allocated.
+ * If it is, then just leave it alone...
+ */
+ if (tfsAlist == 0) {
+ tfsAlistSize = 16;
+ tfsAlist = (TFILE **)malloc((tfsAlistSize+1) * sizeof(TFILE **));
+ if (!tfsAlist) {
+ printf("tfsclear(): tfsAlist allocation failed\n");
+ tfsAlistSize = 0;
+ }
+ }
+}
+
+/* tfsqstalecheck():
+ * This originally was just part of the tfsstalecheck() function.
+ * As of Nov2009 a bug was reported where TFS *could* end up with
+ * two files with the same name. The only case that I was able to
+ * find that allowed this to occur is if tfsadd() was aborted just
+ * after a new file is put in flash, and prior to the old one
+ * (already marked stale) is deleted. If that occurs and uMon
+ * isn't restarted (which is what would call tfsstalecheck()), then
+ * this "duplicate file" case would be created if yet another version
+ * of the file was put into TFS.
+ * Anyway, calling tfsqstalecheck() at the top of tfsadd() prevents
+ * this confusion by making sure that the stale file is removed
+ * even if uMon doesn't reset.
+ */
+static TFILE *
+tfsqstalecheck(void)
+{
+ TDEV *tdp;
+ TFILE *tfp, *tfpa;
+
+ tfpa = (TFILE *)0;
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ tfp = (TFILE *)tdp->start;
+ tfpa = (TFILE *)0;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ if (tfpa) {
+ if (!strcmp(TFS_NAME(tfp),TFS_NAME(tfpa))) {
+ _tfsunlink(TFS_NAME(tfpa));
+ return((TFILE *)0);
+ }
+ }
+ else if (TFS_STALE(tfp)) {
+ tfpa = tfp;
+ }
+ }
+ tfp = nextfp(tfp,tdp);
+ }
+ if (tfpa)
+ break;
+ }
+ return(tfpa);
+}
+
+/* tfsstalecheck():
+ * Called at startup to clean up any file that may be in STALE mode.
+ * A file is stale if it was in the process of being modified
+ * and a power hit occurred. Refer to notes in tfsadd() for details.
+ * There are a few cases to be covered here...
+ * 1. there is no stale file; so there is nothing to do.
+ * 2. there is a stale file, but no other file with the same name...
+ * In this case, the stale file must be copied to another file (with the
+ * TFS_NSTALE flag set) and the stale file is deleted.
+ * 3. there is stale file and another file with the same name...
+ * In this case, the stale file is simply deleted because the other file
+ * with the same name is newer.
+ */
+static void
+tfsstalecheck(void)
+{
+ int err;
+ ulong flags;
+ TFILE *tfpa;
+ char buf[16];
+
+ tfpa = tfsqstalecheck();
+ if (tfpa) {
+ char name[TFSNAMESIZE+1];
+
+ strcpy(name,TFS_NAME(tfpa));
+ printf("TFS stale fixup (%s)...\n",name);
+ if (pollConsole("ok?")) {
+ printf("aborted\n");
+ return;
+ }
+ flags = TFS_FLAGS(tfpa) | TFS_NSTALE;
+ err = tfsadd(TFS_NAME(tfpa),TFS_INFO(tfpa),tfsflagsbtoa(flags,buf),
+ (uchar *)(TFS_BASE(tfpa)),TFS_SIZE(tfpa));
+
+ /* If rewrite was successful, then remove the stale one;
+ * else, leave it there and report the error.
+ */
+ if (err == TFS_OKAY) {
+ _tfsunlink(TFS_NAME(tfpa));
+ }
+ else {
+ printf("TFS stalecheck(%s) error: %s\n",name,tfserrmsg(err));
+ }
+ }
+}
+
+/* tfsdevtblinit():
+ * Transfer the information in tfsdevtbl (in tfsdev.h) to tfsDeviceTbl[].
+ * In most cases, this will be a simple copy. If the device flag is set
+ * to indicate that the initalization is dynamic, then use the flash
+ * ops to retrieve the information from the specified bank.
+ *
+ * For dynamic configuration, the "start" member of the tfsdev structure
+ * must be set in tfsdev.h and the "devinfo & TFS_DEVINFO_BANKMASK" area
+ * must contain the number of the last flash bank that is to be part of
+ * the TFS device. Typically this value is the same bank number as the
+ * starting bank, but it could span across multiple contiguous banks
+ * if the hardware is set up that way.
+ *
+ * To support the use of top-boot devices, plus the TFS requirement that
+ * the SPARE sector be at-least as large as any other sector in the device,
+ * this code will automatically step down the sector list until it finds
+ * the first large sector below all the small ones usually at the top of
+ * a top-boot device. The call to lastlargesector() takes care of this.
+ *
+ * NOTE:
+ * This dynamic configuration assumes that the end of the TFS space is
+ * just below the beginning of the spare space.
+ *
+ */
+void
+tfsdevtblinit(void)
+{
+ int i;
+#if INCLUDE_FLASH
+ int startsector, endsector, bank;
+#endif
+ TDEV *tDp, *tdp;
+
+ for(i=0;i<TFSDEVTOT;i++) {
+ if ((alt_tfsdevtbl != (struct tfsdev *)0xffffffff) &&
+ (alt_tfsdevtbl[i].prefix != (char *)0xffffffff)) {
+ tdp = &alt_tfsdevtbl[i];
+
+ /* do some sanity checking on the alternate table:
+ */
+ if ((tdp->start >= tdp->end) ||
+ (tdp->sparesize > (1024*1024)) ||
+ (tdp->sectorcount > (1024*16))) {
+ printf("TFS altdevtbl[%d] appears corrupt\n",i);
+ tdp = &tfsdevtbl[i];
+ }
+ }
+ else
+ tdp = &tfsdevtbl[i];
+
+ tDp = &tfsDeviceTbl[i];
+ memcpy((char *)tDp,(char *)tdp,sizeof(struct tfsdev));
+ if (i == TFSDEVTOT-1)
+ break;
+
+#if INCLUDE_FLASH
+ if (tdp->devinfo & TFS_DEVINFO_DYNAMIC) {
+ bank = tDp->devinfo & TFS_DEVINFO_BANKMASK;
+
+ /* The spare sector may not be the last sector in the device...
+ * device. Especially if the device is TopBoot type.
+ */
+ if (lastlargesector(bank, (uchar *)tDp->start,
+ tDp->sectorcount+1, &endsector,
+ (int *)&tDp->sparesize,(uchar **)&tDp->spare) == -1)
+ break;
+
+ tDp->end = tDp->spare - 1;
+ if (addrtosector((uchar *)tDp->start,&startsector,0,0) == -1)
+ break;
+ tDp->sectorcount = endsector - startsector;
+
+ /*
+ printf( "tfsdevtblinit - dynamic TFS allocation\n"
+ " prefix........ %s\n"
+ " start......... 0x%08X\n"
+ " end........... 0x%08X\n"
+ " spare......... 0x%08X\n"
+ " sparesize..... 0x%08X\n"
+ " sectorcount... %d\n",
+ tDp->prefix, tDp->start, tDp->end, tDp->spare,
+ tDp->sparesize, tDp->sectorcount);
+ */
+ }
+#endif
+ }
+}
+
+/* tfsstartup():
+ * Called at system startup to get things properly initialized.
+ */
+void
+tfsstartup()
+{
+ TDEV *tdp;
+
+ if (!tfsInitialized)
+ tfsdevtblinit();
+
+ tfsclear((TDEV *)0);
+
+ /* No need to walk through the entire TFS init if it has already
+ * been done...
+ */
+ if (tfsInitialized)
+ return;
+
+ /* Step through the table looking for TFS devices that may need to
+ * be automatically initialized at startup. There are two cases:
+ * - if the devtype is TFS_DEVTYPE_RAM.
+ * - if the devtype is TFS_DEVTYPE_NVRAM with AUTOINIT set.
+ */
+ for(tdp = tfsDeviceTbl;tdp->prefix != 0;tdp++) {
+ if (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM) ||
+ (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_NVRAM) &&
+ (tdp->devinfo & TFS_DEVINFO_AUTOINIT))) {
+ _tfsinit(tdp);
+ }
+ }
+
+ tfsfixup(3,0);
+ tfsstalecheck();
+ tfsInitialized = 1;
+}
+
+/* tfsexec: Treat the file as machine code that is COFF or ELF. */
+
+static int
+tfsexec(TFILE *fp,int verbose)
+{
+ int err, (*entry)(void);
+ long address;
+
+ err = tfsloadebin(fp,verbose,&address,0,0);
+ if (err != TFS_OKAY)
+ return(err);
+
+ entry = (int(*)(void))address;
+ entry(); /* Call entrypoint (may not return). */
+ return(TFS_OKAY);
+}
+
+/* struct tfsran:
+ Used by tfsrunboot only. No need to put this in tfs.h.
+ */
+struct tfsran {
+ char name[TFSNAMESIZE+1];
+};
+
+/* tfsrunboot():
+ * This function is called at monitor startup. It scans the list of
+ * files built by tfsreorder() and executes each file in the list that has
+ * the BRUN flag set. As each file is run its name is added to the
+ * ranlist[] table.
+ *
+ * After each file is run, there is a check made to see if the flash has
+ * been modified. If yes, then tfsreorder() is run again and we start
+ * over at the top of the list of files organized by tfsreorder(). As
+ * we step through the tfsAlist[] array, if the file has a BRUN flag set
+ * but it is already in the ranlist[] table, it is not run again.
+ *
+ * This scheme allows a file in the initial list of BRUN files to modify
+ * the file list without confusing the list of files that are to be run.
+ * Files (even new BRUN files) can be added to the list by some other BRUN
+ * file, and these new files will be run.
+ */
+int
+tfsrunboot(void)
+{
+ static struct tfsran *ranlist;
+ char *argv[2];
+ int rancnt, aidx, ridx, err, fmodcnt;
+
+#if TFS_RUN_DISABLE
+ return(TFSERR_NOTAVAILABLE);
+#endif
+
+ if (!tfsInitialized) {
+ printf("TFS not initialized, tfsrunboot aborting.\n");
+ return(0);
+ }
+
+ /* The argv[] array is used by tfsrun(); argv[0] is name of file to be
+ * executed, argv[1] must be nulled to indicate no command line args
+ * passed to the BRUN file/script.
+ */
+ argv[1] = (char *)0;
+
+ /* Keep a local copy of tfsFmodCount so that we can determine if flash
+ * was modified by one of the BRUN files executed.
+ */
+ fmodcnt = tfsFmodCount;
+
+ /* Create list of file pointers (tfsAlist[]) in alphabetical order
+ * based on name...
+ */
+ if ((err = tfsreorder()) < 0) {
+ printf("tfsrunboot() reorder1: %s\n",tfserrmsg(err));
+ return(-1);
+ }
+
+ /* Clear the ranlist pointer. This pointer is the base address of a
+ * list of file names that have been run.
+ */
+ rancnt = 0;
+ ranlist = (struct tfsran *)0;
+
+restartloop:
+ for (aidx=0;tfsAlist[aidx];aidx++) {
+ char fname[TFSNAMESIZE+1];
+ int alreadyran;
+ TFILE *fp;
+ struct tfsran *rp;
+
+ fp = tfsAlist[aidx];
+ strcpy(fname,TFS_NAME(fp));
+
+ /* If the file has no BRUN flag set, just continue. If a BRUN flag
+ * is set, then see if the file has already been run. If yes, then
+ * just continue; else run the file.
+ */
+ alreadyran = 0;
+ if (fp->flags & (TFS_BRUN | TFS_QRYBRUN)) {
+ for(ridx=0;ridx<rancnt;ridx++) {
+ if (!strcmp(ranlist[ridx].name,fname)) {
+ alreadyran = 1;
+ break;
+ }
+ }
+ }
+ else
+ continue; /* No BRUN flag set. */
+
+ if (alreadyran) { /* BRUN flag set, but file has already */
+ continue; /* been run. */
+ }
+
+ err = TFS_OKAY;
+ argv[0] = fname;
+
+ /* At this point we know the file is a BRUN type, so just see if
+ * the query should precede the run...
+ */
+ if (fp->flags & TFS_QRYBRUN) {
+ int pollval;
+ char query[TFSNAMESIZE+8];
+
+ sprintf(query,"%s?",fname);
+ pollval = pollConsole(query);
+#ifdef TFS_AUTOBOOT_CANCEL_CHAR
+ if (pollval == (int)TFS_AUTOBOOT_CANCEL_CHAR)
+ continue;
+#else
+ if (pollval)
+ continue;
+#endif
+ }
+ /* Increase the size of the ranlist[] table and add the file that
+ * is about to be run to that list...
+ */
+ rancnt++;
+ rp = (struct tfsran*)realloc((char *)ranlist,
+ rancnt*sizeof(struct tfsran));
+
+ if (!rp) {
+ if (ranlist)
+ free((char *)ranlist);
+ printf("tfsrunboot() runlist realloc failure\n");
+ return(-1);
+ }
+
+ ranlist = rp;
+ strcpy(ranlist[rancnt-1].name,fname);
+
+ /* Run the executable...
+ */
+ if (fp->flags & TFS_BRUN) {
+ err = tfsrun_abortableautoboot(argv,0);
+ }
+ else {
+ pre_tfsautoboot_hook();
+ err = tfsrun(argv,0);
+ }
+
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",fname,tfserrmsg(err));
+
+ /* If flash has been modified, then we must re-run tfsreorder() and
+ * start over...
+ */
+ if (fmodcnt != tfsFmodCount) {
+ if ((err = tfsreorder()) < 0) {
+ printf("tfsrunboot() reorder2: %s\n",tfserrmsg(err));
+ return(err);
+ }
+ fmodcnt = tfsFmodCount;
+ goto restartloop;
+ }
+ }
+ if (ranlist)
+ free((char *)ranlist);
+ return(rancnt);
+}
+
+/* tfsreorder():
+ * Populate the tfsAlist[] array with the list of currently active file
+ * pointers, but put in alphabetical (lexicographical using strcmp()) order
+ * based on the filename.
+ * Note that after each file addition/deletion, this must be re-run.
+ */
+int
+tfsreorder(void)
+{
+ TFILE *fp;
+ TDEV *tdp;
+ int i, j, tot;
+
+ /* Determine how many valid files exist, and create tfsAlist array:
+ */
+ tot = 0;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ fp = (TFILE *)tdp->start;
+ while(validtfshdr(fp)) {
+ if (TFS_FILEEXISTS(fp))
+ tot++;
+ fp = nextfp(fp,tdp);
+ }
+ }
+
+ /* If tfsAlist already exists, and is already big enough, then
+ * don't do any allocation; otherwise, create the array with one extra
+ * slot for a NULL pointer used elsewhere as an end-of-list indicator.
+ */
+ if (tot > tfsAlistSize) {
+ tfsAlist = (TFILE **)realloc((char *)tfsAlist,
+ (tot+1) * sizeof(TFILE **));
+ if (!tfsAlist) {
+ tfsAlistSize = 0;
+ return(TFSERR_MEMFAIL);
+ }
+ tfsAlistSize = tot;
+ }
+
+ /* Clear the entire table (plus the extra one at the end):
+ */
+ for(i=0;i<=tot;i++)
+ tfsAlist[i] = (TFILE *)0;
+
+ /* Populate tfsAlist[] with a pointer to each active file
+ * in flash as they exist in memory...
+ */
+ i = 0;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ fp = (TFILE *)tdp->start;
+ while(validtfshdr(fp)) {
+ if (TFS_FILEEXISTS(fp)) {
+ tfsAlist[i++] = fp;
+ }
+ fp = nextfp(fp,tdp);
+ }
+ }
+
+ /* Now run a bubble sort on that list based on the lexicographical
+ * ordering returned by strcmp...
+ */
+ for(i=1;i<tot;++i) {
+ for(j=tot-1;j>=i;--j) {
+ if (strcmp(TFS_NAME(tfsAlist[j-1]),TFS_NAME(tfsAlist[j])) > 0) {
+ fp = tfsAlist[j-1];
+ tfsAlist[j-1] = tfsAlist[j];
+ tfsAlist[j] = fp;
+ }
+ }
+ }
+ return(tot);
+}
+
+/* tfsheadroom():
+ * Based on the current offset into the file specified by the incoming
+ * descriptor, return the gap between the current offset and the end
+ * of the file.
+ */
+static long
+tfsheadroom(int fd)
+{
+ struct tfsdat *tdat;
+
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+ if (tdat->flagmode & TFS_RDONLY)
+ return(tdat->hdr.filsize - tdat->offset);
+ else
+ return(tdat->hwp - tdat->offset);
+}
+
+/* tfstell():
+ * Return the offset into the file that is specified by the incoming
+ * descriptor.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+long
+tfstell(int fd)
+{
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+ return(tfsSlots[fd].offset);
+}
+
+/* tfscompare():
+ * Compare the content of the file specified by tfp with the content pointed
+ * to by the remaining arguments. If identical, return 0; else return -1.
+ */
+static int
+tfscompare(TFILE *tfp,char *name, char *info, char *flags, uchar *src, int size)
+{
+ long bflags;
+
+ /* Compare size, name, info field, flags and data:
+ */
+
+ /* Size...
+ */
+ if (TFS_SIZE(tfp) != size)
+ return(-1);
+
+ /* Name...
+ */
+ if (strcmp(name,TFS_NAME(tfp)))
+ return(-1);
+
+ /* Info field...
+ */
+ if (info) {
+ if (strcmp(info,TFS_INFO(tfp)))
+ return(-1);
+ }
+ else {
+ if (TFS_INFO(tfp)[0] != 0)
+ return(-1);
+ }
+
+ /* Flags...
+ */
+ if (tfsflagsatob(flags, &bflags) == -1)
+ return(-1);
+ if (bflags != (TFS_FLAGS(tfp) & 0x7ff))
+ return(-1);
+
+ /* Data...
+ */
+ if (memcmp(TFS_BASE(tfp),(char *)src,size))
+ return(-1);
+
+ return(0);
+}
+
+/* tfsinit():
+ * Clear out all the flash that is dedicated to the file system.
+ * This removes all currently stored files and erases the flash.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+_tfsinit(TDEV *tdpin)
+{
+ int ret;
+ TDEV *tdp;
+
+ /* Step through the table of TFS devices and erase each sector...
+ */
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!tdpin || (tdp == tdpin)) {
+ ret = tfsflasheraseall(tdp);
+ if (ret != TFS_OKAY)
+ return(ret);
+ }
+ }
+ return(TFS_OKAY);
+}
+
+int
+tfsinit(void)
+{
+ if (tfsTrace > 0)
+ printf("tfsinit()\n");
+ return(_tfsinit(0));
+}
+
+
+/* tfsFtot():
+ * Return the number of files in a device, or all devices if tdpin is null.
+ */
+int
+tfsFtot(TDEV *tdpin)
+{
+ int ftot;
+ TFILE *fp;
+ TDEV *tdp;
+
+ ftot = 0;
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!tdpin || (tdpin == tdp)) {
+ fp = (TFILE *)tdp->start;
+ while (fp->hdrsize != ERASED16) {
+ ftot++;
+ fp = nextfp(fp,tdp);
+ }
+ }
+ }
+ return(ftot);
+}
+
+/* tfsFileIsOpened():
+ * Return 1 if file is currently opened; else 0.
+ */
+int
+tfsFileIsOpened(char *name)
+{
+ int i;
+ struct tfsdat *slot;
+
+ slot = tfsSlots;
+ for (i=0;i<TFS_MAXOPEN;i++,slot++) {
+ if ((slot->offset >= 0) && !strcmp(slot->hdr.name,name))
+ return(1);
+ }
+ return(0);
+}
+
+/* tfsunopen():
+ * If the incoming file descriptor is valid, mark that file as no-longer
+ * opened and return TFS_OKAY; else return TFSERR_BADARG.
+ * descriptor.
+ */
+static long
+tfsunopen(int fd)
+{
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+ if (tfsSlots[fd].offset == -1)
+ return(TFSERR_BADARG);
+ tfsSlots[fd].offset = -1;
+ return(TFS_OKAY);
+}
+
+/* tfsctrl():
+ * Provides an ioctl-like interface to tfs.
+ * Requests supported:
+ * TFS_ERRMSG: Return error message (char *) corresponding to
+ * the incoming error number (arg1).
+ * TFS_MEMUSE: Return the total amount of memory currently in use by
+ * TFS.
+ * TFS_MEMAVAIL: Return the amount of memory currently avaialable for
+ * use in TFS.
+ * TFS_MEMDEAD: Return the amount of memory currently in use by
+ * dead files in TFS.
+ * TFS_DEFRAG: Mechanism for the application to issue
+ * a defragmentation request.
+ * Arg1: if 1, then reset after defrag is complete.
+ * Arg2: verbosity level.
+ * TFS_TELL: Return the offset into the file specified by the
+ * incoming file descriptor (arg1).
+ * TFS_FATOB: Return the binary equivalent of the TFS flags string
+ * pointed to by arg1.
+ * TFS_FBTOA: Return the string equivalent of the TFS flags (long)
+ * in arg1, destination buffer in arg2.
+ * TFS_UNOPEN: In TFS, a the data is not actually written to FLASH
+ * until the tfsclose() function is called. This argument
+ * to tfsctrl() allows a file to be opened and possibly
+ * written to, then unopened without actually modifying
+ * the FLASH. The value of arg1 file descriptor to
+ * apply the "unopen" to.
+ * TFS_TIMEFUNCS: This ctrl call is used to tell TFS what function
+ * to call for time information...
+ * Arg1 is a pointer to:
+ * (long)getLtime(void)
+ * - Get Long Time...
+ * Returns a long representation of time.
+ * Arg2 is a pointer to:
+ * (char *)getAtime(long tval,char *buf).
+ * - Get Ascii Time...
+ * If tval is zero, the buf is loaded with a string
+ * representing the current time;
+ * If tval is non-zero, then buf is loaded with a
+ * string conversion of the value of tval.
+ * Note that since it is up to these functions to
+ * make the conversion between binary version of time
+ * and ascii version, we don't define the exact meaning
+ * of the value returne by getBtime().
+ * TFS_DOCOMMAND: Allows the application to redefine the function
+ * that is called to process each line of a script.
+ * This is useful if the application has its own
+ * command interpreter, but wants to use the scripting
+ * facilities of the monitor.
+ * Arg1 is a pointer to the docommand function to be
+ * used instead of the standard;
+ * Arg2 is a pointer to a location into which the current
+ * docommand function pointer can be stored.
+ * If arg1 is 0, load standard docommand;
+ * if arg2 is 0, don't load old value.
+ * TFS_INITDEV: Allows the application to initialize one of TFS's
+ * devices. Arg1 is a pointer to the device name prefix.
+ * TFS_DEFRAGDEV: Allows the application to defrag one of TFS's
+ * devices. Arg1 is a pointer to the device name prefix.
+ * TFS_CHECKDEV: Allows the application to check one of TFS's
+ * devices. Arg1 is a pointer to the device name prefix.
+ * TFS_RAMDEV: Allows the application to create (or remove) a
+ * special temporary TFS device in RAM.
+ *
+ *
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+
+long
+tfsctrl(int rqst,long arg1,long arg2)
+{
+ long retval, flag;
+ TDEV *tdp;
+ TINFO tinfo;
+ TRAMDEV *trdp;
+
+ if (tfsTrace > 0)
+ printf("tfsctrl(%d,0x%lx,0x%lx)\n",rqst,arg1,arg2);
+
+ switch(rqst) {
+ case TFS_ERRMSG:
+ retval = (long)tfserrmsg(arg1);
+ break;
+ case TFS_MEMUSE:
+ tfsmemuse(0,&tinfo,0);
+ retval = tinfo.memused;
+ break;
+ case TFS_MEMAVAIL:
+ tfsmemuse(0,&tinfo,0);
+ retval = tinfo.memfordata;
+ break;
+ case TFS_MEMDEAD:
+ tfsmemuse(0,&tinfo,0);
+ retval = tinfo.deadovrhd+tinfo.deaddata;
+ break;
+ case TFS_INITDEV:
+ tdp = gettfsdev_fromprefix((char *)arg1,0);
+ if (!tdp)
+ retval = TFSERR_BADARG;
+ else
+ retval = _tfsinit(tdp);
+ break;
+ case TFS_CHECKDEV:
+ tdp = 0;
+ if (arg1 != 0)
+ tdp = gettfsdev_fromprefix((char *)arg1,0);
+ retval = tfscheck(tdp,0);
+ break;
+ case TFS_DEFRAGDEV:
+ tdp = gettfsdev_fromprefix((char *)arg1,0);
+ if (!tdp)
+ retval = TFSERR_BADARG;
+ else
+ retval = tfsclean(tdp,0);
+ break;
+ case TFS_DEFRAG:
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++)
+ tfsclean(tdp,(int)arg1);
+ retval = 0;
+ break;
+ case TFS_FCOUNT:
+ if (arg1) {
+ tdp = gettfsdev_fromprefix((char *)arg1,0);
+ if (!tdp)
+ retval = TFSERR_BADARG;
+ else
+ retval = tfsftot(tdp);
+ }
+ else {
+ retval = tfsftot(0);
+ }
+ break;
+ case TFS_DEFRAGON:
+ retval = tfsclean_on();
+ break;
+ case TFS_DEFRAGOFF:
+ retval = tfsclean_off();
+ break;
+ case TFS_UNOPEN:
+ retval = tfsunopen((int)arg1);
+ break;
+ case TFS_FATOB:
+ retval = tfsflagsatob((char *)arg1,&flag);
+ if (retval == TFS_OKAY)
+ retval = flag;
+ break;
+ case TFS_FBTOA:
+ retval = (long)tfsflagsbtoa(arg1,(char *)arg2);
+ if (retval == 0)
+ retval = TFSERR_BADARG;
+ break;
+ case TFS_HEADROOM:
+ retval = tfsheadroom(arg1);
+ break;
+ case TFS_RAMDEV:
+ trdp = (TRAMDEV *)arg1;
+ retval = tfsramdevice(trdp->name,trdp->base,trdp->size);
+ break;
+ case TFS_TELL:
+ retval = tfstell(arg1);
+ break;
+ case TFS_TIMEFUNCS:
+ tfsGetLtime = (long(*)(void))arg1;
+ tfsGetAtime = (char *(*)(long,char *,int))arg2;
+ retval = TFS_OKAY;
+ break;
+ case TFS_DOCOMMAND:
+ if (arg2)
+ *(long *)arg2 = (long)tfsDocommand;
+ if (arg1)
+ tfsDocommand = (int(*)(char *,int))arg1;
+ else
+ tfsDocommand = docommand;
+ retval = TFS_OKAY;
+ break;
+ default:
+ retval = TFSERR_BADARG;
+ break;
+ }
+ return(retval);
+}
+
+/* tfsNameToDevice():
+ * Given the filename, return the device pointer associated with
+ * that filename. The device used depends on the prefix of
+ * the incoming file name. If the incoming prefix doesn't match
+ * any of the devices in the table, then return a pointer to the
+ * first device in the table (assumed to be the default).
+ */
+TDEV *
+tfsNameToDevice(char *name)
+{
+ TDEV *tdp;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ if (!strncmp(name,tdp->prefix,strlen(tdp->prefix)))
+ break;
+ }
+ if (tdp->start == TFSEOT)
+ tdp = tfsDeviceTbl;
+
+ return(tdp);
+}
+
+/* tfsramdevice():
+ * Create (or remove) a temporary (RAM-based) TFS device..
+ * This function is callable from both the API and the CLI.
+ * The TFS device table is established with one extra slot.
+ * The purpose of that slot is to allow the user to establish
+ * a temporary, ram-based TFS device. This function supports
+ * that capability.
+ */
+int
+tfsramdevice(char *name,long base,long size)
+{
+ TFILE *fp;
+ TDEV *tdp, *ramdev;
+ char tmpname[TFSNAMESIZE+1];
+ static char devname[TFSNAMESIZE+1];
+
+ ramdev = (TDEV *)0;
+ snprintf(tmpname,TFSNAMESIZE,"//%s/",name);
+
+ if (tfsTrace > 0)
+ printf("tfsramdevice(%s,0x%lx,%ld)\n",name,base,size);
+
+ /* Scan through the current list of files and make sure that
+ * the name being requested is not the name of a file already
+ * in TFS... Note that the incoming name can't form even the
+ * same prefix as any file currently in TFS.
+ */
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ fp = (TFILE *)tdp->start;
+ while(validtfshdr(fp)) {
+ if ((TFS_FILEEXISTS(fp)) &&
+ (strncmp(tmpname,fp->name,strlen(tmpname)) == 0))
+ return(TFSERR_FILEEXISTS);
+ fp = nextfp(fp,tdp);
+ }
+ }
+
+ /* Scan through the device table to find the slot that can
+ * be used by the "ramdev" device...
+ */
+ tdp = tfsDeviceTbl;
+ while(tdp->start != TFSEOT) {
+ if ((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM)
+ ramdev = tdp;
+ if (strcmp(tdp->prefix,tmpname) == 0) {
+ if (size != 0) {
+ return(TFSERR_FILEEXISTS);
+ }
+ else {
+ if (ramdev != tdp)
+ return(TFSERR_FILEEXISTS);
+ }
+ }
+ tdp++;
+ }
+
+ if (ramdev) {
+ if (size == 0) {
+ if (strcmp(tmpname,ramdev->prefix) != 0)
+ return(TFSERR_NOFILE);
+
+ memset((char *)ramdev->start,0,ramdev->end - ramdev->start);
+ ramdev->prefix = 0;
+ ramdev->start = 0;
+ ramdev->devinfo = 0;
+ ramdev->end = 0;
+ ramdev->start = TFSEOT;
+ }
+ else
+ return(TFSERR_FILEEXISTS);
+ }
+ else {
+ /* If size is zero, just do nothing and return OK...
+ */
+ if (size == 0)
+ return(TFS_OKAY);
+
+ /* Minimum size of a TFS partition is 1024 bytes...
+ */
+ if (size < 1024)
+ return(TFSERR_TOOSMALL);
+
+ strcpy(devname,tmpname);
+ tdp->prefix = devname;
+ tdp->start = base;
+ tdp->sparesize = 0;
+ tdp->sectorcount = 0;
+ tdp->devinfo = TFS_DEVTYPE_RAM;
+ tdp->end = tdp->start + size - 1;
+ tdp->spare = 0;
+ memset((char *)tdp->start,0xff,size);
+ tdp++;
+ tdp->start = TFSEOT;
+ }
+ return(TFS_OKAY);
+}
+
+/* tfsadd():
+ * Add a file to the current list.
+ * If the file already exists AND everything is identical between the
+ * old and the new (flags, info and data), then return and do nothing;
+ * else remove the old file prior to adding the new one.
+ *
+ * Note:
+ * At the point when tfsadd is called for a file that currently exists,
+ * the old file must be removed and a new one is put in its place. This
+ * opens up the possibility of losing the file if a power-hit or reset was
+ * to occur between the point at which the old file was removed and the new
+ * one was put in its place. To overcome this problem, TFS files have a
+ * flag called TFS_NSTALE. It is a bit that is normally 1, but cleared
+ * if it becomes stale (hence the name TFS_NSTALE). A file is
+ * in this mode only for a short time... the time it takes to write the
+ * new file that replaces the file that was made stale.
+ * Now, if a reset occurs after the file is stale, depending on
+ * whether or not the new file was written, it will either be removed or
+ * used to recreate the original file because the write of the new file
+ * was chopped off by the power hit. Refer to the function tfsstalecheck()
+ * for details on the recovery after a reset or powerhit.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsadd(char *name, char *info, char *flags, uchar *src, int size)
+{
+ TDEV *tdp;
+ TFILE *fp, tf, *sfp;
+ long bflags;
+ ulong endoftfsflash, nextfileaddr, thisfileaddr;
+ ulong crc_pass1, crc_pass2;
+ int ftot, cleanupcount, err, stale, rc;
+
+ if (!info) info = "";
+ if (!flags) flags = "";
+
+ if (tfsTrace > 0)
+ printf("tfsadd(%s,%s,%s,0x%lx,%d)\n", name,info,flags,(ulong)src,size);
+
+ /* Check for valid size and name:
+ */
+ if ((size < 0) || (!name) || (*name == 0))
+ return(TFSERR_BADARG);
+
+ /* If name or info field length is too long, abort now...
+ */
+ if ((strlen(name) > TFSNAMESIZE) ||
+ ((info) && (strlen(info) > TFSINFOSIZE)))
+ return(TFSERR_NAMETOOBIG);
+
+ /* The incoming filename cannot match any of the existing
+ * TFS device names...
+ */
+ tdp = tfsDeviceTbl;
+ while(tdp->start != TFSEOT) {
+ if (strcmp(tdp->prefix,name) == 0)
+ return(TFSERR_FILEEXISTS);
+ tdp++;
+ }
+
+ /* If the file is currently opened, then don't allow the add...
+ */
+ if (tfsFileIsOpened(name))
+ return(TFSERR_FILEINUSE);
+
+ /* If incoming flags are illegal, abort now...
+ */
+ if (*flags == 0) {
+ bflags = 0;
+ }
+ else {
+ err = tfsflagsatob(flags,&bflags);
+ if (err != TFS_OKAY)
+ return(err);
+
+ /* If we're adding a link, then the size better be zero...
+ */
+ if ((bflags & TFS_SYMLINK) && (size != 0))
+ return(TFSERR_LINKERROR);
+ }
+
+ /* Make sure that there isn't a stale file and a normal file
+ * of the same name already in TFS...
+ */
+ tfsqstalecheck();
+
+ /* If size is zero, but the request is not a link, then
+ * error...
+ */
+ if ((size == 0) && ((bflags & TFS_SYMLINK) != TFS_SYMLINK))
+ return(TFSERR_BADARG);
+
+ stale = 0;
+ cleanupcount = 0;
+
+ /* Take snapshot of source crc. Note that we only run the CRC
+ * if the IPMOD flag is not set. If this flag is set, then the
+ * CRC is invalid...
+ */
+ if (!(bflags & TFS_IPMOD))
+ crc_pass1 = crc32(src, size);
+ else
+ crc_pass1 = 0;
+
+ /* Establish the device that is to be used for the incoming file
+ * addition request...
+ */
+ tdp = tfsNameToDevice(name);
+
+#ifndef TFS_DISABLE_AUTODEFRAG
+tryagain:
+#endif
+ fp = (TFILE *)tdp->start;
+
+ /* Find end of current storage: */
+ ftot = 0;
+ while (fp) {
+ if (fp->hdrsize == ERASED16)
+ break;
+ if (TFS_FILEEXISTS(fp)) {
+ ftot++;
+ if (!strcmp(TFS_NAME(fp),name)) {
+ if (!(TFS_STALE(fp))) {
+ /* If destination file exists, but we do not meet the
+ * user level requirements, return error now.
+ */
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ return(TFSERR_USERDENIED);
+
+ /* If file of the same name exists AND it is identical to
+ * the new file to be added, then return TFS_OKAY and be
+ * done; otherwise, remove the old one and continue.
+ * Two exceptions to this:
+ * 1. If the current file is stale, then we are here
+ * because of a stale-file fixup at system startup.
+ * 2. If the src file is in-place-modify then source
+ * data is undefined.
+ */
+ if (!(bflags & TFS_IPMOD) &&
+ (!tfscompare(fp,name,info,flags,src,size))) {
+ return(TFS_OKAY);
+ }
+
+#ifdef TFS_DISABLE_MAKE_BEFORE_BREAK
+ err = _tfsunlink(name);
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",name,tfserrmsg(err));
+#else
+ /* If a file of the same name exists but is different
+ * than the new file, set a flag to indicate that the
+ * file should be marked stale just prior to
+ * adding the new file.
+ */
+ stale = 1;
+#endif
+ }
+ }
+ }
+ fp = nextfp(fp,tdp);
+ }
+ if (!fp) /* If fp is 0, then nextfp() (above) detected corruption. */
+ return(TFSERR_CORRUPT);
+
+ /* Calculate location of next file (on mod16 address). This will be
+ * initially used to see if we have enough space left in flash to store
+ * the current request; then, if yes, it will become part of the new
+ * file's header.
+ */
+ thisfileaddr = (ulong)(fp+1);
+ nextfileaddr = thisfileaddr + size;
+ if (nextfileaddr & 0xf)
+ nextfileaddr = (nextfileaddr | 0xf) + 1;
+
+ /* Make sure that the space is available for writing to flash...
+ * Remember that the end of useable flash space must take into
+ * account the fact that some space must be left over for the
+ * defragmentation state tables. Also, the total space needed for
+ * state tables cannot exceed the size of the sector that will contain
+ * those tables.
+ */
+ if (TFS_DEVTYPE_ISRAM(tdp)) {
+ endoftfsflash = tdp->end;
+ }
+ else {
+#if INCLUDE_FLASH
+ int ssize;
+ ulong state_table_overhead;
+
+ /* The state table overhead cannot exceed one additional
+ * sector's space, so we need to check for that...
+ */
+ state_table_overhead = ((ftot+1) * DEFRAGHDRSIZ) +
+ (tdp->sectorcount * sizeof(struct sectorcrc));
+
+ if (addrtosector((uchar *)(tdp->end),0,&ssize,0) < 0)
+ return(TFSERR_MEMFAIL);
+
+ if (state_table_overhead >= (ulong)ssize)
+ return(TFSERR_DSIMAX);
+
+ endoftfsflash = (tdp->end + 1) - state_table_overhead;
+#else
+ return(TFSERR_NOTAVAILABLE);
+#endif
+ }
+
+ if ((nextfileaddr >= endoftfsflash) ||
+ (nextfileaddr < thisfileaddr) ||
+ (!flasherased((uchar *)fp,(uchar *)fp + (size+TFSHDRSIZ)))) {
+#ifndef TFS_DISABLE_AUTODEFRAG
+ if (!cleanupcount) {
+ err = tfsclean(tdp,0);
+ if (err != TFS_OKAY) {
+ printf("tfsadd autoclean failed: %s\n",
+ (char *)tfsctrl(TFS_ERRMSG,err,0));
+ return(err);
+ }
+ cleanupcount++;
+ goto tryagain;
+ }
+ else
+#endif
+ return(TFSERR_FLASHFULL);
+ }
+
+ memset((char *)&tf,0,TFSHDRSIZ);
+
+ /* Do another crc on the source data. If crc_pass1 != crc_pass2 then
+ * somehow the source is changing. This is typically caused by the fact
+ * that the source address is within TFS space that was automatically
+ * defragmented above. There is no need to check source data if the
+ * source is in-place-modifiable.
+ */
+ if (!(bflags & TFS_IPMOD)) {
+ crc_pass2 = crc32(src,size);
+ if (crc_pass1 != crc_pass2)
+ return(TFSERR_FLAKEYSOURCE);
+ }
+ else
+ crc_pass2 = ERASED32;
+
+ /* Now that we have determined that we have enough space to do the
+ * copy, if the "stale" flag was set (indicating that there is already
+ * a file in TFS with the same name as the incoming file), we must now
+ * mark the file stale...
+ */
+ if (stale) {
+ sfp = (TFILE *)tdp->start;
+ while (sfp) {
+ if (sfp->hdrsize == ERASED16)
+ break;
+ if (TFS_FILEEXISTS(sfp)) {
+ if (!strcmp(TFS_NAME(sfp),name)) {
+ if (TFS_DEVTYPE_ISRAM(tdp)) {
+ TFS_FLAGS(sfp) &= ~TFS_NSTALE;
+ }
+ else {
+ if ((err = tfsmakeStale(sfp)) != TFS_OKAY)
+ return(err);
+ }
+ break;
+ }
+ }
+ sfp = nextfp(sfp,tdp);
+ }
+ if (!sfp)
+ return(TFSERR_CORRUPT);
+ }
+
+ /* Copy name and info data to header.
+ */
+ strcpy(tf.name, name);
+ strcpy(tf.info, info);
+ tf.hdrsize = TFSHDRSIZ;
+ tf.hdrvrsn = TFSHDRVERSION;
+ tf.filsize = size;
+ tf.flags = bflags;
+ tf.flags |= (TFS_ACTIVE | TFS_NSTALE);
+ tf.filcrc = crc_pass2;
+ tf.modtime = tfsGetLtime();
+#if TFS_RESERVED
+ {
+ int rsvd;
+ for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
+ tf.rsvd[rsvd] = 0xffffffff;
+ }
+#endif
+ tf.next = 0;
+ tf.hdrcrc = 0;
+ tf.hdrcrc = crc32((uchar *)&tf,TFSHDRSIZ);
+ tf.next = (TFILE *)nextfileaddr;
+
+ /* Now copy the file and header to flash.
+ * Note1: the header is copied AFTER the file has been
+ * successfully copied. If the header was written successfully,
+ * then the data write failed, the header would be incorrectly
+ * pointing to an invalid file. To avoid this, simply write the
+ * data first.
+ * Note2: if the file is in-place-modifiable, then there is no
+ * file data to be written to the flash. It will be left as all FFs
+ * so that the flash can be modified by tfsipmod() later.
+ */
+
+ /* Write the file to flash if not TFS_IPMOD:
+ */
+ if (!(tf.flags & TFS_IPMOD)) {
+ if (TFS_DEVTYPE_ISRAM(tdp))
+ memcpy((char *)(fp+1),(char *)src,size);
+ else {
+ rc = tfsflashwrite((uchar *)(fp+1),(uchar *)src,size);
+ if (rc != TFS_OKAY)
+ return(rc);
+ }
+ }
+
+ /* Write the file header to flash:
+ */
+ if (TFS_DEVTYPE_ISRAM(tdp))
+ memcpy((char *)fp,(char *)&tf,TFSHDRSIZ);
+ else {
+ rc = tfsflashwrite((uchar *)fp,(uchar *)(&tf),TFSHDRSIZ);
+ if (rc != TFS_OKAY)
+ return(rc);
+ }
+
+ /* Double check the CRC now that it is in flash.
+ */
+ if (!(tf.flags & TFS_IPMOD)) {
+ if (crc32((uchar *)(fp+1), size) != tf.filcrc)
+ return(TFSERR_BADCRC);
+ }
+
+ /* If the add was a file that previously existed, then the stale flag
+ * will be set and the old file needs to be deleted...
+ */
+ if (stale) {
+ err = _tfsunlink(name);
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",name,tfserrmsg(err));
+ }
+
+ tfslog(TFSLOG_ADD,name);
+ return(TFS_OKAY);
+}
+
+/* tfsunlink():
+ * Delete a file from the current list of files. Note that there
+ * is no attempt to de-fragment the flash; it simply nulls out the flags
+ * field of the file. If successful return 0; else return error number.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsunlink(char *name)
+{
+ if (tfsTrace > 0)
+ printf("tfsunlink(%s)\n",name);
+
+ /* If the file is currently opened, then don't allow the deletion...
+ */
+ if (tfsFileIsOpened(name))
+ return(TFSERR_FILEINUSE);
+
+ return(_tfsunlink(name));
+}
+
+int
+_tfsunlink(char *name)
+{
+ int rc;
+ TFILE *fp;
+ TDEV *tdp;
+ ulong flags_marked_deleted;
+
+ if (tfsTrace > 0)
+ printf("_tfsunlink(%s)\n",name);
+
+ fp = _tfsstat(name,0);
+ if (!fp)
+ return(TFSERR_NOFILE);
+
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ return(TFSERR_USERDENIED);
+
+ flags_marked_deleted = fp->flags & ~TFS_ACTIVE;
+
+ tdp = tfsNameToDevice(name);
+ if (TFS_DEVTYPE_ISRAM(tdp))
+ memcpy((char *)&fp->flags,(char *)&flags_marked_deleted,sizeof(long));
+ else {
+ rc = tfsflashwrite((uchar *)&fp->flags,
+ (uchar *)&flags_marked_deleted, sizeof(long));
+ if (rc != TFS_OKAY)
+ return(rc);
+ }
+
+ tfslog(TFSLOG_DEL,name);
+ return (TFS_OKAY);
+}
+
+int
+tfslink(char *src, char *target)
+{
+ TFILE *tfp;
+ char linfo[TFSINFOSIZE+1];
+ char flags[16];
+
+ tfp = tfsstat(src);
+ if (tfp) {
+ if (TFS_ISLINK(tfp))
+ return(TFSERR_LINKERROR);
+
+ strncpy(linfo,src,TFSINFOSIZE-1);
+ linfo[TFSINFOSIZE] = 0;
+ flags[0] = 'l';
+ tfsflagsbtoa(tfp->flags,flags+1);
+ return(tfsadd(target,linfo,flags,0,0));
+ }
+ return(TFSERR_NOFILE);
+}
+
+
+static void
+pre_tfsautoboot_hook(void)
+{
+#ifdef PRE_TFSAUTOBOOT_HOOK
+ extern void PRE_TFSAUTOBOOT_HOOK();
+
+ if (tfsMonrcActive == 0)
+ {
+ PRE_TFSAUTOBOOT_HOOK();
+ }
+#endif
+}
+
+/*
+ * tfsrun_abortableautoboot():
+ *
+ * Aborting execution of the monrc & non-query-autoboot files:
+ * The code wrapped within the #ifdef TFS_AUTOBOOT_ABORTABLE definition
+ * is an implementation of an idea from Jason DiDonato (Jan 2004).
+ * These files can be aborted by an escape character under two
+ * circumstances:
+ *
+ * 1. There is no password file installed
+ * 2. The user correctly enters the level-three password when
+ * prompted by the abort interaction below.
+ *
+ * This mechanism maintains security, but only when security is desired.
+ * A system that needs security will have a password file installed;
+ * hence, if no password file is found, the escape character
+ * (AUTOBOOT_ABORT_CHAR) is all that is needed at startup to abort an
+ * otherwise non-abortable file.
+ * If a password file is found, then the user must know the level-3 password
+ * to abort the execution; otherwise, after a few seconds, the interaction
+ * will terminate and the file will be executed.
+ *
+ * Prior to this implementation, autobootables were not abortable in any
+ * way. This is still the default, which is overridden by the definition
+ * of TFS_AUTOBOOT_ABORTABLE in config.h
+ */
+
+
+#define AUTOBOOT_ABORT_NULL 0
+#define AUTOBOOT_ABORT_NO 1
+#define AUTOBOOT_ABORT_YES 2
+#define AUTOBOOT_ABORT_FAILED 3
+
+#ifndef AUTOBOOT_ABORT_CHAR
+#ifdef TFS_AUTOBOOT_CANCEL_CHAR
+#define AUTOBOOT_ABORT_CHAR TFS_AUTOBOOT_CANCEL_CHAR
+#else
+#define AUTOBOOT_ABORT_CHAR 0x03 /* CTRL-C */
+#endif
+#endif
+
+int
+tfsrun_abortableautoboot(char **arglist,int verbose)
+{
+#ifdef TFS_AUTOBOOT_ABORTABLE
+ int err;
+ static int autoboot_abort;
+
+ /* If a character has been detected at the console, and the
+ * character is AUTOBOOT_ABORT_CHAR, then, if a password file
+ * exists, require that the user enter the level-3 password
+ * to abort the autoboot file...
+ * Note that this is only done on the first pass through this
+ * function. All subsequent passes use the result of the initial
+ * pass.
+ */
+ if (autoboot_abort == AUTOBOOT_ABORT_NULL) {
+ autoboot_abort = AUTOBOOT_ABORT_NO;
+
+ if (gotachar() && (getchar() == AUTOBOOT_ABORT_CHAR)) {
+#if INCLUDE_USRLVL
+ if (passwordFileExists()) {
+ char passwd[16];
+
+ /* To allow the user to simply hold down on the abort
+ * character during a target, reset, this loop will
+ * absorb a burst of incoming characters. Then, when
+ * the burst halts, the user will be queried for the
+ * password.
+ */
+ monDelay(500);
+ while(gotachar()) {
+ getchar();
+ monDelay(500);
+ }
+
+ getpass("autoboot-abort password: ",passwd,sizeof(passwd)-1,50);
+ if (validPassword(passwd,3))
+ autoboot_abort = AUTOBOOT_ABORT_YES;
+ else
+ autoboot_abort = AUTOBOOT_ABORT_FAILED;
+ }
+ else
+#endif
+ autoboot_abort = AUTOBOOT_ABORT_YES;
+ }
+ }
+
+ err = TFS_OKAY;
+
+ switch(autoboot_abort) {
+ case AUTOBOOT_ABORT_NO:
+ pre_tfsautoboot_hook();
+ err = tfsrun(arglist,verbose);
+ break;
+ case AUTOBOOT_ABORT_YES:
+ printf("%s aborted\n",arglist[0]);
+ break;
+ case AUTOBOOT_ABORT_FAILED:
+ printf("%s abort attempt failed\n",arglist[0]);
+ pre_tfsautoboot_hook();
+ err = tfsrun(arglist,verbose);
+ break;
+ }
+ return(err);
+#else
+ pre_tfsautoboot_hook();
+ return(tfsrun(arglist,verbose));
+#endif /* TFS_AUTOBOOT_ABORTABLE */
+}
+
+
+/* tfsrun():
+ * Run the named file. Based on the file flags, the file is either
+ * executed as a COFF/ELF file with all relocation data in the file
+ * or run as a simple script of monitor commands.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+
+int
+tfsrun(char **arglist,int verbose)
+{
+ int i, err;
+ TFILE fstat, *fp;
+ char *name;
+
+ name = arglist[0];
+ fp = tfsstat(name);
+
+ if (!fp)
+ return (TFSERR_NOFILE);
+
+ tfsfstat(name,&fstat);
+
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ return(TFSERR_USERDENIED);
+
+#if INCLUDE_TFSSCRIPT
+ /* Store away the argument list so that it is accessible by the script
+ * or executable application about to be run:
+ */
+ for(i=0;arglist[i];i++)
+ putargv(i,arglist[i]);
+ putargv(i,(char *)0);
+#endif
+
+ /* Executable file can be script or binary...
+ */
+ if (!(fp->flags & (TFS_EXEC|TFS_EBIN)))
+ return(TFSERR_NOTEXEC);
+
+ if (!(fp->flags & TFS_IPMOD)) {
+ if (crc32((uchar *)(TFS_BASE(fp)), fp->filsize) != fp->filcrc)
+ return(TFSERR_BADCRC);
+ }
+ /* Machine code or script...
+ * If machine code, then block it if monrc is active.
+ */
+ if (fp->flags & TFS_EBIN) {
+ if (tfsRunningMonrc())
+ err = TFSERR_NORUNMONRC;
+ else
+ err = tfsexec(fp,verbose);
+ }
+ else {
+ err = tfsscript(&fstat,verbose);
+ }
+
+ return(err);
+}
+
+/* tfsrunrcfile():
+ * Called at system startup to run the monitor's run-control file (monrc).
+ * Three attempts are made to find the monrc file...
+ * 1. Call tfsstat("monrc")
+ * 2. Call tfsstat("monrc.bak")
+ * 3. For each device, prepend the device prefix to the monrc name
+ * and run tfsstat() on that string (i.e.. tfsstat(//A/monrc)).
+ * This supports a multi-device system in which the monrc file is not
+ * in the first TFS device.
+ *
+ * If one of the above is found, it will be automatically executed.
+ * Note that only the first one found will be executed.
+ * If the file is flagged as autobootable, post a warning message.
+ * This lets the user know that the monrc file is going to be run twice
+ * (probably not what they want, so when the warning is seen, the flag
+ * should be changed by the user).
+ *
+ */
+
+void
+tfsrunrcfile(void)
+{
+ int err;
+ TDEV *tdp;
+ TFILE *tfp;
+ char *arglist[2], bigname[TFSNAMESIZE+1], *name;
+
+#if TFS_RUN_DISABLE
+ return;
+#endif
+
+ if (!tfsInitialized) {
+ printf("TFS not initialized, tfsrunrcfile aborting.\n");
+ return;
+ }
+
+ name = TFS_RCFILE;
+ tfp = tfsstat(name);
+ if (!tfp) {
+ name = TFS_RCFILE ".bak";
+ tfp = tfsstat(name);
+ }
+ if (!tfp) {
+ for(tdp=tfsDeviceTbl; (tdp->start != TFSEOT) ; tdp++) {
+ sprintf(bigname,"%smonrc",tdp->prefix);
+ if ((tfp = tfsstat(bigname))) {
+ name = bigname;
+ break;
+ }
+ }
+ }
+ if (!tfp)
+ return;
+
+ if (TFS_FLAGS(tfp) & (TFS_BRUN | TFS_QRYBRUN))
+ printf("Warning: %s is autobootable\n",name);
+
+ arglist[0] = name;
+ arglist[1] = (char *)0;
+
+ tfsMonrcActive = 1;
+ err = tfsrun_abortableautoboot(arglist,0);
+ tfsMonrcActive = 0;
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",name,tfserrmsg(err));
+ return;
+}
+
+int
+tfsRunningMonrc(void)
+{
+ return(tfsMonrcActive);
+}
+
+/* tfsnext():
+ * Called to retrieve the "next" file in the tfs list. If
+ * incoming argument is NULL then return the first file in the list. If no
+ * more files, return NULL; else return the tfshdr structure pointer to the
+ * next (or first) file in the tfs.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+TFILE *
+tfsnext(TFILE *fp)
+{
+ TDEV *tdp;
+ TFILE *fpnext;
+
+ if (!fp) {
+ tdp = tfsDeviceTbl;
+ fpnext = (TFILE *) tfsDeviceTbl[0].start;
+ }
+ else {
+ tdp = gettfsdev(fp);
+ fpnext = nextfp(fp,0);
+ }
+
+ while(tdp->start != TFSEOT) {
+ while(validtfshdr(fpnext)) {
+ if (TFS_FILEEXISTS(fpnext))
+ return (fpnext);
+ fpnext = nextfp(fpnext,0);
+ }
+ tdp++;
+ fpnext = (TFILE *)tdp->start;
+ }
+ return ((TFILE *) 0);
+}
+
+/* tfsBase() and the notion of a "fake" file header...
+ * Generally speaking TFS code assumes that the data portion of a file
+ * follows the header contiguously in flash memory space. As a result, the
+ * code that looks for the data portion of the file just adds the size of
+ * the header to the file header pointer...
+ *
+ * #define TFS_BASE(fp) (char *)(fp)+(fp->hdrsize)
+ *
+ * As of Mar 2007, TFS supports the ability to load an executable image
+ * (usually elf) from outside TFS space by simply using the command...
+ *
+ * tfs ld 0x12345678,E,info
+ *
+ * This is useful for cases where users don't want the large elf image to
+ * be in TFS because each time it is updated, a defrag will occur. If put
+ * in raw flash space, that flash space can simply be erased and written
+ * over as needed; thus, eliminating the overhead of tfs defrag.
+ *
+ * When this is needed, TFS must be able to load the elf image using a
+ * 'fake' TFS header that points to an elf-formatted block of data in raw
+ * flash space. As a result, we now allocate the first reserved entry of
+ * TFS's header structure to this funcationality. If this first entry is
+ * not 0xffffffff, then it is assumed to be a pointer to the data area of
+ * the file.
+ */
+char *
+tfsBase(TFILE *fp)
+{
+ if (fp->rsvd[0] != 0xffffffff)
+ return((char *)fp->rsvd[0]);
+ else
+ return(TFS_BASE(fp));
+}
+
+
+/* tfsstat():
+ * Steps through the list of files until it finds the specified
+ * filename or reaches the end of the list. If found, a pointer to that
+ * file's structure is returned; else return 0.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+TFILE *
+tfsstat(char *name)
+{
+ if (!tfsInitialized) {
+ printf("TFS not initialized, tfsstat aborting.\n");
+ return(0);
+ }
+
+ return(_tfsstat(name,1));
+}
+
+TFILE *
+_tfsstat(char *name,int uselink)
+{
+ int len;
+ TFILE *fp;
+ TDEV *tdp;
+ char *prefix, *dotslash = "./";
+
+ if (tfsTrace > 0)
+ printf("_tfsstat(%s,%d)\n",name,uselink);
+
+ /* Support the ability to have a hex address for a filename...
+ * This uses a "fake" file header.
+ */
+ if ((name[0] == '0') && (name[1] == 'x')) {
+ int rsvd;
+ static TFILE fakehdr; /* WARNING: not reentrant!!! */
+ char *comma1, *comma2, tmpname[TFSNAMESIZE+1];
+
+ strncpy(tmpname,name,sizeof(tmpname));
+
+ comma1 = comma2 = (char *)0;
+ if ((comma1 = strchr(tmpname,',')) != 0)
+ comma2 = strchr(comma1+1,',');
+
+ if (comma1) *comma1 = 0;
+ if (comma2) *comma2 = 0;
+
+ strcpy(fakehdr.name,tmpname);
+ if (comma2)
+ strcpy(fakehdr.info,comma2+1);
+ else
+ fakehdr.info[0] = 0;
+ fakehdr.hdrsize = TFSHDRSIZ;
+ fakehdr.hdrvrsn = TFSHDRVERSION;
+ fakehdr.filsize = 0;
+ if (comma1)
+ tfsflagsatob(comma1+1, &fakehdr.flags);
+ else
+ fakehdr.flags = 0;
+ fakehdr.flags |= TFS_ACTIVE | TFS_NSTALE;
+ fakehdr.filcrc = 0;
+ fakehdr.modtime = tfsGetLtime();
+
+ for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
+ fakehdr.rsvd[rsvd] = 0xffffffff;
+ fakehdr.rsvd[0] = strtol(name,0,0);
+
+ fakehdr.next = 0;
+ fakehdr.hdrcrc = 0;
+ fakehdr.hdrcrc = crc32((uchar *)&fakehdr,TFSHDRSIZ);
+ fakehdr.next = (TFILE *)0;
+ return(&fakehdr);
+ }
+
+ /* Account for the possibility that the filename might have the
+ * device name prefixed for the first device in the table (or "./").
+ */
+ tdp = &tfsDeviceTbl[0];
+ if (strncmp(name,tdp->prefix,strlen(tdp->prefix)) == 0) {
+ len = strlen(tdp->prefix);
+ prefix = tdp->prefix;
+ }
+ else if (strncmp(name,dotslash,2) == 0) {
+ len = 2;
+ prefix = dotslash;
+ }
+ else {
+ len = 0;
+ prefix = 0;
+ }
+
+ if (prefix) {
+ fp = (TFILE *) tdp->start;
+ while(validtfshdr(fp)) {
+ if (TFS_FILEEXISTS(fp) && (strcmp(name+len, fp->name) == 0)) {
+ if (uselink && TFS_ISLINK(fp))
+ return(_tfsstat(TFS_INFO(fp),0));
+ else
+ return(fp);
+ }
+ fp = nextfp(fp,tdp);
+ }
+ }
+
+ /* Then, if not found, walk through all TFS devices normally...
+ */
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ fp = (TFILE *) tdp->start;
+ while(validtfshdr(fp)) {
+ if (TFS_FILEEXISTS(fp) && (strcmp(name, fp->name) == 0)) {
+ if (uselink && TFS_ISLINK(fp))
+ return(_tfsstat(TFS_INFO(fp),0));
+ else
+ return(fp);
+ }
+ fp = nextfp(fp,tdp);
+ }
+ }
+ return ((TFILE *) 0);
+}
+
+/* tfsfstat():
+ * Very similar in purpose to tfsstat(). This version is provided to the
+ * API as a "defrag-safe" version of tfsstat()...
+ * If tfsstat() is called (returning a pointer into TFS memory space), then
+ * a defragmentation occurs, that pointer is stale; hence, the need for
+ * an alternative that will load the content of the TFILE structure into
+ * an application-supplied block of memory (usually a pointer to a local
+ * TFILE structure). Using tfsfstat avoids this because if a defrag occurs,
+ * it does not affect the content of the locally stored TFILE structure.
+ * NOTE:
+ * addition of this function to the TFS API was due to the fact that
+ * I did not consider the above described condition when first adding
+ * tfsstat() to the TFS API. In general, tfsfstat() should be considered
+ * a replacement for all tfsstat() situations that will dereference the
+ * pointer.
+ * NOTE1:
+ * The return value is similar to standard "stat"... Return 0 if
+ * successful, else -1.
+ */
+int
+tfsfstat(char *name, TFILE *apptfp)
+{
+ TFILE *tfp;
+ int otrace;
+
+ otrace = tfsTrace;
+
+ if (tfsTrace > 0) {
+ tfsTrace = 0;
+ printf("tfsfstat(%s)\n",name);
+ }
+
+ tfp = tfsstat(name);
+ tfsTrace = otrace;
+
+ if (!tfp)
+ return(-1);
+
+ memcpy((char *)apptfp,(char *)tfp,sizeof(TFILE));
+ return(0);
+}
+
+int
+showTfsError(int errno, char *msg)
+{
+ if (errno == TFS_OKAY)
+ return(TFS_OKAY);
+
+ if (msg)
+ printf("%s: %s\n",msg,tfserrmsg(errno));
+ else
+ printf("%s\n",tfserrmsg(errno));
+ return(errno);
+}
+
+/* tfscfg():
+ * If the alt_tfsdev structure for the specified device prefix is
+ * not already established, then this function allows the caller to
+ * re-configure TFS for that device.
+ */
+int
+tfscfg(char *prefix, ulong tfsstart, ulong tfsend, ulong spare)
+{
+#if INCLUDE_FLASH
+ uchar *base;
+ TDEV *tdp, td;
+ int idx, sec_start, sec_end, size, flash_not_erased, rc;
+
+ if (tfsTrace) {
+ printf("tfscfg(%s,0x%lx,0x%lx,0x%lx)\n",
+ prefix, tfsstart, tfsend, spare);
+ }
+
+ /* If the alt_tfsdevtbl pointer is initialized to 0xffffffff, then
+ * we assume that this feature has been disable for this port.
+ */
+ if (alt_tfsdevtbl == (struct tfsdev *)0xffffffff) {
+ return(TFSERR_NOTAVAILABLE);
+ }
+
+#ifndef TFS_ALTDEVTBL_BASE
+ /* We assume that if TFS_ALTDEVTBL_BASE is defined, then it is pointing
+ * to fixed area in flash; hence, we don't care if uMon is running out
+ * of RAM or not (because the default alt_tfsdevtbl[] which would be
+ * relocated to ram at startup isn't being used).
+ */
+ if (uMonInRam()) {
+ printf("tfs cfg applies to rom-based images only\n");
+ return(TFSERR_MEMFAIL);
+ }
+#endif
+
+ /* Match incoming prefix with an entry in the TFS device table.
+ * If prefix pointer is NULL, then use first device in table...
+ */
+ if (prefix == (char *)0) {
+ tdp=&tfsDeviceTbl[0];
+ idx = 0;
+ }
+ else {
+ for(idx=0,tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++,idx++) {
+ if (!strcmp(prefix,tdp->prefix))
+ break;
+ }
+ }
+ if (tdp->start == TFSEOT)
+ return(TFSERR_BADPREFIX);
+
+ /* If no change, just return success...
+ */
+ if ((tfsstart == tdp->start) && (tfsend == tdp->end))
+ return(TFS_OKAY);
+
+ /* If the alternate table entry is already written, then error...
+ * User must run "tfs cfg restore" first.
+ */
+ if (alt_tfsdevtbl[idx].prefix != (char *)0xffffffff) {
+ printf("Hint: try 'tfs cfg restore' first.\n");
+ return(TFSERR_ALTINUSE);
+ }
+
+ if (spare == 0xffffffff)
+ spare = tfsend+1;
+
+ /* Do some checking prior to applying the new configuration...
+ */
+ if (tfsend <= tfsstart)
+ return(TFSERR_BADARG);
+
+ if (addrtosector((uchar *)tfsstart,&sec_start,0,&base) == -1)
+ return(TFSERR_BADARG);
+
+ if (tfsstart != (ulong)base) {
+ printf("Start (0x%lx) is not base address of sector\n",tfsstart);
+ return(TFSERR_BADARG);
+ }
+
+ if (addrtosector((uchar *)tfsend,&sec_end,&size,&base) == -1)
+ return(TFSERR_BADARG);
+
+ if (addrtosector((uchar *)spare,0,&size,&base) == -1)
+ return(TFSERR_BADARG);
+
+ if (spare != (ulong)base) {
+ printf("Spare (0x%lx) is not base address of sector\n",spare);
+ return(TFSERR_BADARG);
+ }
+
+ flash_not_erased = 0;
+
+#ifdef TFS_ALTDEVTBL_BASE
+ /* If TFS_ALTDEVTBL_BASE is defined, then the alt_tfsdevtbl value is
+ * pointing to space that may not be automatically allocated by the
+ * compiler (as it would have been if TFS_ALTDEVTBL_BASE wasn't
+ * defined). As a result, we need to check to make sure that the
+ * space we need is erased and available...
+ * If this check fails, it probably indicates that the space allocated
+ * for this structure at build time (possibly in rom_reset.s) is just
+ * not big enough and needs to be increased at build time.
+ */
+ {
+ uchar *end = (uchar *)&alt_tfsdevtbl[idx];
+ end += sizeof(struct tfsdev) - 1;
+ if (!flasherased((uchar *)&alt_tfsdevtbl[idx],end)) {
+ printf("Alternate tfsdev structure area (0x%lx-0x%lx) not erased\n",
+ (long)alt_tfsdevtbl,(long)end);
+ flash_not_erased = 1;
+ }
+ }
+#endif
+
+ if (tfsend < tdp->end) {
+ if (!flasherased((uchar *)tfsend,(uchar *)tdp->end)) {
+ printf("flash within 0x%lx -> 0x%lx not erased\n",
+ tfsend,tdp->end);
+ flash_not_erased = 1;
+ }
+ }
+ else if (tdp->end < tfsend) {
+ if (!flasherased((uchar *)tdp->end,(uchar *)tfsend)) {
+ printf("flash within 0x%lx -> 0x%lx not erased\n",
+ tdp->end,tfsend);
+ flash_not_erased = 1;
+ }
+ }
+ if (tfsstart < tdp->start) {
+ if (!flasherased((uchar *)tfsstart,(uchar *)tdp->start)) {
+ printf("flash within 0x%lx -> 0x%lx not erased\n",
+ tfsstart,tdp->start);
+ flash_not_erased = 1;
+ }
+ }
+ else if (tdp->start < tfsstart) {
+ if (!flasherased((uchar *)tdp->start,(uchar *)tfsstart)) {
+ printf("flash within 0x%lx -> 0x%lx not erased\n",
+ tdp->start,tfsstart);
+ flash_not_erased = 1;
+ }
+ }
+
+ if (flash_not_erased)
+ return(TFSERR_MEMFAIL);
+
+ td.prefix = tdp->prefix;
+ td.start = tfsstart;
+ td.end = tfsend;
+ td.spare = spare;
+ td.sparesize = size;
+ td.sectorcount = sec_end - sec_start + 1;
+
+ /* When a TFS device is re-configured using "tfs cfg", it
+ * shouldn't do any self-adjustment based on flash because
+ * the user is forcing the configuration. So, the reconfigured
+ * device must always have TFS_DEVINFO_DYNAMIC cleared...
+ */
+ tdp->devinfo &= ~TFS_DEVINFO_DYNAMIC;
+ td.devinfo = tdp->devinfo;
+
+ rc = tfsflashwrite((uchar *)&alt_tfsdevtbl[idx],
+ (uchar *)&td,sizeof(TDEV));
+
+ if (rc == TFS_OKAY) {
+ tdp->start = tfsstart;
+ tdp->end = tfsend;
+ tdp->spare = spare;
+ tdp->sparesize = size;
+ tdp->sectorcount = sec_end - sec_start + 1;
+ }
+ return(rc);
+#else
+ return(TFSERR_NOTAVAILABLE);
+#endif
+}
+
+/* tfscfgrestore():
+ * This function is used to erase any alternate TFS configuration
+ * structure that may have been previously written. This function
+ * is DANGEROUS because it does a self-modification of uMon binary
+ * space; hence, should be done with caution (i.e. don't interrupt
+ * it).
+ */
+int
+tfscfgrestore(void)
+{
+#if INCLUDE_FLASH
+ char *ram;
+ ulong offset;
+ uchar *base;
+ int sec_start, size;
+
+ printf("WARNING: uMon control structure restoration in progress.\n");
+ printf("Allow this to complete (2-5 seconds) without interruption\n");
+
+ if (addrtosector((uchar *)alt_tfsdevtbl,&sec_start,&size,&base) == -1)
+ return(TFSERR_FLASHFAILURE);
+
+ offset = (ulong)alt_tfsdevtbl - (ulong)base;
+ ram = (char *)getAppRamStart();
+
+ if (s_memcpy(ram,(char *)base,size,0,0) == -1)
+ return(TFSERR_MEMFAIL);
+ if (s_memset((uchar *)(ram+offset),0xff,TFS_ALTDEVTBL_SIZE,0,0) == -1)
+ return(TFSERR_MEMFAIL);
+
+ /* In most ports, flashewrite() doesn't return. */
+ if (flashewrite((uchar *)base,(uchar *)ram,size) < 0)
+ return(TFSERR_FLASHFAILURE);
+ else
+ return(TFS_OKAY);
+#else
+ return(TFSERR_NOTAVAILABLE);
+#endif
+}
+
+int
+tfsclean_on(void)
+{
+ TfsCleanEnable++;
+ return(TfsCleanEnable);
+}
+
+int
+tfsclean_off(void)
+{
+ TfsCleanEnable--;
+ return(TfsCleanEnable);
+}
+
+/* tfsclean_nps():
+ * This is an alternative to the complicated powersafe defragmentation
+ * scheme used in tfsclean1.c. It simply scans through the file list
+ * and copies all valid files
+ * to RAM; then flash is erased and the RAM is copied back to flash.
+ * <<< WARNING >>>
+ * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY
+ * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE.
+ */
+int
+tfsclean_nps(TDEV *tdp, char *ramstart, ulong ramsize)
+{
+ TFILE *tfp;
+ ulong appramstart;
+ uchar *tbuf, *ramend, *cp1, *cp2;
+ int dtot, nfadd, len, chkstat;
+#if INCLUDE_FLASH
+ TFILE *lasttfp;
+#endif
+
+ if (TfsCleanEnable < 0)
+ return(TFSERR_CLEANOFF);
+
+ if (ramstart)
+ appramstart = (ulong)ramstart;
+ else
+ appramstart = getAppRamStart();
+
+ if (ramsize)
+ ramend = (uchar *)appramstart + appramstart;
+ else
+ ramend = 0;
+
+ /* Determine how many "dead" files exist. */
+ dtot = 0;
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ if (!TFS_FILEEXISTS(tfp))
+ dtot++;
+ tfp = nextfp(tfp,tdp);
+ }
+
+ if (dtot == 0)
+ return(TFS_OKAY);
+
+ printf("TFS device '%s' non-powersafe defragmentation\n",tdp->prefix);
+
+ tbuf = (uchar *)appramstart;
+ tfp = (TFILE *)(tdp->start);
+#if INCLUDE_FLASH
+ lasttfp = tfp;
+#endif
+ nfadd = tdp->start;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ len = TFS_SIZE(tfp) + sizeof(struct tfshdr);
+ if (len % TFS_FSIZEMOD)
+ len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD);
+ nfadd += len;
+
+ if (ramend && ((tbuf+len) > ramend)) {
+ printf("Insufficient ram, aborting defrag.\n");
+ return(TFSERR_MEMFAIL);
+ }
+
+ if (s_memcpy((char *)tbuf,(char *)tfp,len,0,0) != 0)
+ return(TFSERR_MEMFAIL);
+
+ ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd;
+ tbuf += len;
+ }
+#if INCLUDE_FLASH
+ lasttfp = tfp;
+#endif
+ tfp = nextfp(tfp,tdp);
+ }
+
+ /* We've now copied all of the active files from flash to ram.
+ * Now we want to see how much of the flash space needs to be
+ * erased. We only need to erase the sectors that have changed...
+ */
+ cp1 = (uchar *)tdp->start;
+ cp2 = (uchar *)appramstart;
+ while(cp2 < tbuf) {
+ if (*cp1 != *cp2)
+ break;
+ cp1++; cp2++;
+ }
+#if INCLUDE_FLASH
+ if ((cp2 != tbuf) || (!TFS_FILEEXISTS(lasttfp))) {
+ int first, last;
+
+ if (addrtosector(cp1,&first,0,0) == -1)
+ return(TFSERR_FLASHFAILURE);
+
+ if (addrtosector((uchar *)tdp->end,&last,0,0) == -1)
+ return(TFSERR_FLASHFAILURE);
+ printf("Erasing sectors %d-%d...\n",first,last);
+ while(first<last) {
+ if (flasherase(first++) == 0)
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+#endif
+
+ /* Copy data placed in RAM back to flash: */
+ printf("Restoring flash...\n");
+ if (TFS_DEVTYPE_ISRAM(tdp)) {
+ memcpy((char *)(tdp->start),(char *)appramstart,
+ (tbuf-(uchar*)appramstart));
+ }
+ else {
+#if INCLUDE_FLASH
+ int err;
+
+ err = AppFlashWrite((uchar *)(tdp->start),(uchar *)appramstart,
+ (tbuf-(uchar*)appramstart));
+ if (err < 0)
+#endif
+ return(TFSERR_FLASHFAILURE);
+ }
+
+ /* All defragmentation is done, so verify sanity of files... */
+ chkstat = tfscheck(tdp,1);
+
+ return(chkstat);
+}
+
+/* tfsclean():
+ * Wrapper to the underlying _tfsclean() function.
+ * The original intent of this was to enable a call to appexit() if there
+ * is an error returned by tfsclean(). This is used for testing TFS...
+ * If a script is running to try to cause tfsclean to break, then we want
+ * it to halt if tfsclean does return an error.
+
+
+ * As of uMon1.0, if this function detects that the device is volatile
+ * RAM, then the clean is not powersafe; hence, doesn't have to go
+ * through the rigorous sector-based defragmentation.
+ */
+int
+tfsclean(TDEV *tdp,int verbose)
+{
+ TFILE *tfp, *tfp1, *tfpnxt;
+ int cleanresult, size;
+ char *cp;
+
+ if (TFS_DEVTYPE_ISRAM(tdp)) {
+ cp = 0;
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ tfpnxt = nextfp(tfp,tdp);
+ if (TFS_DELETED(tfp)) {
+ if (cp == 0)
+ cp = (char *)tfp;
+ }
+ else {
+ if (cp != 0) {
+ size = TFS_SIZE(tfp) + TFSHDRSIZ;
+ if (size & 0xf)
+ size = (size | 0xf) + 1;
+ memcpy(cp,(char *)tfp,size);
+ tfp1 = (TFILE *)cp;
+ tfp1->next = (TFILE *)(cp+size);
+ tfp1->hdrcrc = tfshdrcrc(tfp1);
+ cp += size;
+ }
+ }
+ tfp = tfpnxt;
+ }
+ if (cp)
+ memset(cp,0xff,(char *)(tdp->end)-cp);
+ cleanresult = TFS_OKAY;
+ }
+ else {
+ cleanresult = _tfsclean(tdp,0,verbose);
+ if (cleanresult != TFS_OKAY) {
+ if (getenv("APP_EXITONCLEANERROR"))
+ appexit(0);
+#if INCLUDE_TFSSCRIPT
+ if (getenv("SCR_EXITONCLEANERROR"))
+ ScriptExitFlag = EXIT_SCRIPT;
+#endif
+ }
+ }
+
+ return(cleanresult);
+}
+
+#else /* INCLUDE_TFS */
+
+char *
+tfserrmsg(int errno)
+{
+ return(0);
+}
+int
+tfsinit(void)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsfstat(char *name, TFILE *apptfp)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+TFILE *
+tfsstat(char *name)
+{
+ return ((TFILE *) 0);
+}
+
+int
+tfslink(char *src, char *target)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+TFILE *
+tfsnext(TFILE *fp)
+{
+ return ((TFILE *) 0);
+}
+
+int
+tfsrun(char **arglist,int verbose)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsunlink(char *name)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsadd(char *name, char *info, char *flags, uchar *src, int size)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+long
+tfsctrl(int rqst,long arg1,long arg2)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+long
+tfstell(int fd)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsRunningMonrc(void)
+{
+ return(0);
+}
+
+int
+tfsspace(char *addr)
+{
+ return(0);
+}
+
+#endif /* INCLUDE_TFS else */
diff --git a/main/common/tfs.h b/main/common/tfs.h
new file mode 100644
index 0000000..d4e21e5
--- /dev/null
+++ b/main/common/tfs.h
@@ -0,0 +1,213 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfs.h:
+ *
+ * Header file for TFS transactions, used by both application and monitor.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _TFS_H_
+#define _TFS_H_
+
+#define TFSINFOSIZE 23 /* Max size of info string (mod4-1). */
+
+#ifndef TFSNAMESIZE /* This specifies the maximum size of a file */
+#define TFSNAMESIZE 23 /* name that can be used in TFS. */
+#endif /* This MUST be some value mod4 - 1. */
+
+#ifndef TFS_CHANGELOG_FILE /* Information used for change-log */
+#define TFS_CHANGELOG_SIZE 0 /* facility within tfs. */
+#define TFS_CHANGELOG_FILE ".tfschlog"
+#endif
+
+#ifndef SYMFILE /* This specifies the default filename */
+#define SYMFILE "symtbl" /* used by the monitor for the symbol */
+#endif /* table. */
+
+#define MINUSRLEVEL 0 /* Minimum user level supported. */
+#define MAXUSRLEVEL 3 /* Maximum user level supported. */
+
+#ifndef TFS_RESERVED
+#define TFS_RESERVED 4 /* Number of "reserved" entries (ulong) */
+#endif /* in the TFS header. */
+
+
+/* Flags: */
+#define TFS_EXEC 0x00000001 /* 'e': Executable script. */
+#define TFS_BRUN 0x00000002 /* 'b': To be executed at boot. */
+#define TFS_QRYBRUN 0x00000004 /* 'B': To be executed at boot if */
+ /* query passes. */
+#define TFS_SYMLINK 0x00000008 /* 'l': Symbolic link file. */
+#define TFS_EBIN 0x00000010 /* 'E': Executable binary (coff/elf/a.out). */
+#define TFS_IPMOD 0x00000080 /* 'i': File is in-place modifiable. */
+#define TFS_UNREAD 0x00000100 /* 'u': File is not even readable if the */
+ /* user-level requirement is not met; */
+ /* else, it is read-only. */
+#define TFS_ULVLMSK 0x00000600 /* User level mask defines 4 access levels: */
+#define TFS_ULVL0 0x00000000 /* '0' level 0 */
+#define TFS_ULVL1 0x00000200 /* '1' level 1 */
+#define TFS_ULVL2 0x00000400 /* '2' level 2 */
+#define TFS_ULVL3 0x00000600 /* '3' level 3 */
+#define TFS_NSTALE 0x00000800 /* File is NOT stale, invisible to user.
+ * When this bit is clear, the file is
+ * considered stale (see notes in tfsadd()).
+ * See notes in tfsclose() for this.
+ */
+#define TFS_ACTIVE 0x00008000 /* Used to indicate that file is not deleted. */
+
+#define TFS_ULVLMAX TFS_ULVL3
+#define TFS_USRLVL(f) ((f->flags & TFS_ULVLMSK) >> 9)
+
+/* Open modes */
+#define TFS_RDONLY 0x00010000 /* File is opened for reading. */
+#define TFS_CREATE 0x00020000 /* File is to be created. Error if file */
+ /* with the same name already exists. */
+#define TFS_APPEND 0x00040000 /* Append to existing file. If OR'ed */
+ /* with TFS_CREATE, then create if */
+ /* necessary. */
+#define TFS_ALLFFS 0x00080000 /* File is created with all FFs. */
+#define TFS_CREATERM 0x00100000 /* File is to be created. If file with */
+ /* same name already exists, then allow */
+ /* tfsadd() to remove it if necessary. */
+
+/* The function tfsrunrc() will search through the current file set and */
+/* if the file defined by TFS_RCFILE exists, it will be executed. */
+/* If this file exists, it will NOT be run by tfsrunboot(). */
+#define TFS_RCFILE "monrc"
+
+/* Requests that can be made to tfsctrl(): */
+#define TFS_ERRMSG 1
+#define TFS_MEMUSE 2
+#define TFS_MEMDEAD 3
+#define TFS_DEFRAG 4
+#define TFS_TELL 5
+#define TFS_UNOPEN 7
+#define TFS_FATOB 8
+#define TFS_FBTOA 9
+#define TFS_MEMAVAIL 10
+#define TFS_TIMEFUNCS 11
+#define TFS_DOCOMMAND 12
+#define TFS_INITDEV 13
+#define TFS_CHECKDEV 14
+#define TFS_DEFRAGDEV 15
+#define TFS_DEFRAGOFF 16
+#define TFS_DEFRAGON 17
+#define TFS_HEADROOM 18
+#define TFS_FCOUNT 19
+#define TFS_RAMDEV 20
+
+/* struct tfshdr:
+ * It is in FLASH as part of the file system to record the attributes of
+ * the file at the time of creation.
+ *
+ * New as of March 2007...
+ * See tfsBase() for info on the use of the first entry of the rsvd[] array.
+ */
+struct tfshdr {
+ unsigned short hdrsize; /* Size of this header. */
+ unsigned short hdrvrsn; /* Header version #. */
+ long filsize; /* Size of the file. */
+ long flags; /* Flags describing the file. */
+ unsigned long filcrc; /* 32 bit CRC of file. */
+ unsigned long hdrcrc; /* 32 bit CRC of the header. */
+ unsigned long modtime; /* Time when file was last modified. */
+ struct tfshdr *next; /* Pointer to next file in list. */
+ char name[TFSNAMESIZE+1]; /* Name of file. */
+ char info[TFSINFOSIZE+1]; /* Miscellaneous info field. */
+#if TFS_RESERVED
+ unsigned long rsvd[TFS_RESERVED];
+#endif
+};
+
+/* struct tfsramdev:
+ * Used with the tfsctrl function TFS_RAMDEV to allow the user to
+ * specify the name, base address and size of a new, temporary
+ * ram-based TFS device.
+ */
+struct tfsramdev {
+ char *name;
+ long base;
+ long size;
+};
+
+#define TFSHDRSIZ sizeof(struct tfshdr)
+
+/* TFS error returns. */
+#define TFS_OKAY 0
+#define TFSERR_NOFILE -1
+#define TFSERR_NOSLOT -2
+#define TFSERR_EOF -3
+#define TFSERR_BADARG -4
+#define TFSERR_NOTEXEC -5
+#define TFSERR_BADCRC -6
+#define TFSERR_FILEEXISTS -7
+#define TFSERR_FLASHFAILURE -8
+#define TFSERR_WRITEMAX -9
+#define TFSERR_RDONLY -10
+#define TFSERR_BADFD -11
+#define TFSERR_BADHDR -12
+#define TFSERR_CORRUPT -13
+#define TFSERR_MEMFAIL -14
+#define TFSERR_NOTIPMOD -16
+#define TFSERR_MUTEXFAILURE -17
+#define TFSERR_FLASHFULL -18
+#define TFSERR_USERDENIED -19
+#define TFSERR_NAMETOOBIG -20
+#define TFSERR_FILEINUSE -21
+#define TFSERR_NOTAVAILABLE -23
+#define TFSERR_BADFLAG -24
+#define TFSERR_CLEANOFF -25
+#define TFSERR_FLAKEYSOURCE -26
+#define TFSERR_BADEXTENSION -27
+#define TFSERR_LINKERROR -28
+#define TFSERR_BADPREFIX -29
+#define TFSERR_ALTINUSE -30
+#define TFSERR_NORUNMONRC -31
+#define TFSERR_DSIMAX -32
+#define TFSERR_TOOSMALL -33
+#define TFSERR_MIN -100
+
+/* TFS seek options. */
+#define TFS_BEGIN 1
+#define TFS_CURRENT 2
+#define TFS_END 3
+
+/* Macros: */
+#define TFS_DELETED(fp) (!((fp)->flags & TFS_ACTIVE))
+#define TFS_FILEEXISTS(fp) ((fp)->flags & TFS_ACTIVE)
+#define TFS_ISEXEC(fp) ((fp)->flags & TFS_EXEC)
+#define TFS_ISBOOT(fp) ((fp)->flags & TFS_BRUN)
+#define TFS_ISLINK(fp) ((fp)->flags & TFS_SYMLINK)
+#define TFS_STALE(fp) (!((fp)->flags & TFS_NSTALE))
+#define TFS_FLAGS(fp) ((fp)->flags)
+#define TFS_NAME(fp) ((fp)->name)
+#define TFS_SIZE(fp) ((fp)->filsize)
+#define TFS_TIME(fp) ((fp)->modtime)
+#define TFS_INFO(fp) ((fp)->info)
+#define TFS_NEXT(fp) ((fp)->next)
+#define TFS_CRC(fp) ((fp)->filcrc)
+#define TFS_ENTRY(fp) ((fp)->entry)
+#define TFS_BASE(fp) ((char *)(fp)+(fp)->hdrsize)
+
+typedef struct tfshdr TFILE;
+typedef struct tfsramdev TRAMDEV;
+#endif
diff --git a/main/common/tfsapi.c b/main/common/tfsapi.c
new file mode 100644
index 0000000..212d264
--- /dev/null
+++ b/main/common/tfsapi.c
@@ -0,0 +1,622 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsapi.c:
+ *
+ * This file contains the portion of TFS that provides the function-level
+ * API to the application. If this is not being used by the application
+ * then it can be omitted from the monitor build.
+ * Note that not all of the api-specific code is here; some of it is in
+ * tfs.c. This is because the the MicroMonitor uses some of the api itself,
+ * so it cannot be omitted from the TFS package without screwing up some
+ * other monitor functionality that needs it.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#if INCLUDE_TFSAPI
+
+/* tfstruncate():
+ * To support the ability to truncate a file (make it smaller); this
+ * function allows the user to adjust the high-water point of the currently
+ * opened (and assumed to be opened for modification) file and replaces
+ * that with the incoming argument. This replacement is only done if the
+ * current high-water point is higher than the incoming length.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfstruncate(int fd, long len)
+{
+ struct tfsdat *tdat;
+
+ if (tfsTrace > 1)
+ printf("tfstruncate(%d,%ld)\n",fd,len);
+
+ /* Verify valid range of incoming file descriptor. */
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADFD);
+
+ tdat = &tfsSlots[fd];
+
+ /* Make sure the file pointed to by the incoming descriptor is active
+ * and that the incoming length is greater than the current high-water
+ * point...
+ */
+ if (tdat->offset == -1)
+ return(TFSERR_BADFD);
+ if (len > tdat->hwp)
+ return(TFSERR_BADARG);
+
+ /* Make the adjustment... */
+ tdat->hwp = len;
+ return(TFS_OKAY);
+}
+
+/* tfseof():
+ * Return 1 if at the end of the file, else 0 if not at end; else negative
+ * if error.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfseof(int fd)
+{
+ struct tfsdat *tdat;
+
+ /* Verify valid range of incoming file descriptor. */
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+
+ /* Make sure the file pointed to by the incoming descriptor is active. */
+ if (tdat->offset == -1)
+ return(TFSERR_BADFD);
+
+ if (tdat->offset >= tdat->hdr.filsize)
+ return(1);
+ else
+ return(0);
+}
+
+/* tfsread():
+ * Similar to a standard read call to a file.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsread(int fd, char *buf, int cnt)
+{
+ struct tfsdat *tdat;
+ uchar *from;
+
+ if (tfsTrace > 1)
+ printf("tfsread(%d,0x%lx,%d)\n",fd,(ulong)buf,cnt);
+
+ /* Verify valid range of incoming file descriptor. */
+ if ((cnt < 1) || (fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+
+ /* Make sure the file pointed to by the incoming descriptor is active. */
+ if (tdat->offset == -1)
+ return(TFSERR_BADFD);
+
+ if (tdat->offset >= tdat->hdr.filsize)
+ return(TFSERR_EOF);
+
+ from = (uchar *) tdat->base + tdat->offset;
+
+ /* If request size is within the range of the file and current
+ * then copy the data to the requestors buffer, increment offset
+ * and return the count.
+ */
+ if ((tdat->offset + cnt) <= tdat->hdr.filsize) {
+ if (s_memcpy((char *)buf, (char *)from, cnt,0,0) != 0)
+ return(TFSERR_MEMFAIL);
+ }
+ /* If request size goes beyond the size of the file, then copy
+ * to the end of the file and return that smaller count.
+ */
+ else {
+ cnt = tdat->hdr.filsize - tdat->offset;
+ if (s_memcpy((char *)buf, (char *)from, cnt, 0, 0) != 0)
+ return(TFSERR_MEMFAIL);
+ }
+ tdat->offset += cnt;
+ return(cnt);
+}
+
+/* tfswrite():
+ * Similar to a standard write call to a file.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfswrite(int fd, char *buf, int cnt)
+{
+ struct tfsdat *tdat;
+
+ if (tfsTrace > 1)
+ printf("tfswrite(%d,0x%lx,%d)\n", fd,(ulong)buf,cnt);
+
+ /* Verify valid range of incoming file descriptor. */
+ if ((cnt < 1) || (fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ /* Make sure the file pointed to by the incoming descriptor is active. */
+ if (tfsSlots[fd].offset == -1)
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+
+ /* Make sure file is not opened as read-only */
+ if (tdat->flagmode & TFS_RDONLY)
+ return(TFSERR_RDONLY);
+
+ if (s_memcpy((char *)tdat->base+tdat->offset,(char *)buf,cnt,0,0) != 0)
+ return(TFSERR_MEMFAIL);
+
+ tdat->offset += cnt;
+
+ /* If new offset is greater than current high-water point, then
+ * adjust the high water point so that it is always reflecting the
+ * highest offset into which the file has had some data written.
+ */
+ if (tdat->offset > tdat->hwp)
+ tdat->hwp = tdat->offset;
+
+ return(TFS_OKAY);
+}
+
+/* tfsseek():
+ * Adjust the current pointer into the specified file.
+ * If file is read-only, then the offset cannot exceed the file size;
+ * otherwise, the only check made to the offset is that it is positive.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsseek(int fd, int offset, int whence)
+{
+ int o_offset;
+ struct tfsdat *tdat;
+
+ if (tfsTrace > 1)
+ printf("tfsseek(%d,%d,%d)\n",fd,offset,whence);
+
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+ o_offset = tdat->offset;
+
+ switch (whence) {
+ case TFS_BEGIN:
+ tdat->offset = offset;
+ break;
+ case TFS_CURRENT:
+ tdat->offset += offset;
+ break;
+ default:
+ return(TFSERR_BADARG);
+ }
+
+ /* If new offset is less than zero or if the file is read-only and the
+ * new offset is greater than the file size, return EOF...
+ */
+ if ((tdat->offset < 0) ||
+ ((tdat->flagmode & TFS_RDONLY) && (tdat->offset > tdat->hdr.filsize))){
+ tdat->offset = o_offset;
+ return(TFSERR_EOF);
+ }
+ return(tdat->offset);
+}
+
+/* tfsipmod():
+ * Modify "in-place" a portion of a file in TFS.
+ * This is a cheap and dirty way to modify a file...
+ * The idea is that a file is created with a lot of writeable flash space
+ * (data = 0xff). This function can then be called to immediately modify
+ * blocks of space in that flash. It will not do any tfsunlink/tfsadd, and
+ * it doesn't even require a tfsopen() tfsclose() wrapper. Its a fast and
+ * efficient way to modify flash in the file system.
+ * Arguments:
+ * name = name of the file to be in-place-modified;
+ * buf = new data to be written to flash;
+ * offset = offset into file into which new data is to be written;
+ * size = size of new data (in bytes).
+ *
+ * With offset of -1, set offset to location containing first 0xff value.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsipmod(char *name,char *buf,int offset,int size)
+{
+ int rc;
+ TFILE *fp;
+ uchar *cp;
+
+ fp = tfsstat(name);
+ if (!fp)
+ return (TFSERR_NOFILE);
+ if (!(fp->flags & TFS_IPMOD))
+ return(TFSERR_NOTIPMOD);
+
+ if (offset == -1) {
+ cp = (uchar *)(TFS_BASE(fp));
+ for (offset=0;offset<fp->filsize;offset++,cp++) {
+ if (*cp == 0xff)
+ break;
+ }
+ }
+ else if (offset < -1)
+ return(TFSERR_BADARG);
+
+ if ((offset + size) > fp->filsize)
+ return(TFSERR_WRITEMAX);
+
+ /* BUG fixed: 2/21/2001:
+ * The (ulong *) cast was done prior to adding offset to the base.
+ * This caused the offset to be quadrupled.
+ */
+ rc = tfsflashwrite((uchar *)(TFS_BASE(fp)+offset),(uchar *)buf,size);
+ if (rc != TFS_OKAY)
+ return(rc);
+
+ tfslog(TFSLOG_IPM,name);
+ return(TFS_OKAY);
+}
+
+/* tfsopen():
+ * Open a file for reading or creation. If file is opened for writing,
+ * then the caller must provide a RAM buffer pointer to be used for
+ * the file storage until it is transferred to flash by tfsclose().
+ * Note that the "buf" pointer is only needed for opening a file for
+ * creation or append (writing).
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsopen(char *file,long flagmode,char *buf)
+{
+ register int i;
+ int errno, retval;
+ long fmode;
+ TFILE *fp;
+ struct tfsdat *slot;
+
+ errno = TFS_OKAY;
+
+ fmode = flagmode & (TFS_RDONLY | TFS_APPEND | TFS_CREATE | TFS_CREATERM);
+
+ /* See if file exists... */
+ fp = tfsstat(file);
+
+ /* If file exists, do a crc32 on the data.
+ * If the file is in-place-modifiable, then the only legal flagmode
+ * is TFS_RDONLY. Plus, in this case, the crc32 test is skipped.
+ */
+ if (fp) {
+ if (!((fmode == TFS_RDONLY) && (fp->flags & TFS_IPMOD))) {
+ if (crc32((unsigned char *)TFS_BASE(fp),fp->filsize) != fp->filcrc) {
+ retval = TFSERR_BADCRC;
+ goto done;
+ }
+ }
+ }
+
+ /* This switch verifies...
+ * - that the file exists if TFS_RDONLY or TFS_APPEND
+ * - that the file does not exist if TFS_CREATE
+ */
+ switch(fmode) {
+ case TFS_RDONLY: /* Read existing file only, no change to file at all. */
+ if (!fp) {
+ if (_tfsstat(file,0))
+ errno = TFSERR_LINKERROR;
+ else
+ errno = TFSERR_NOFILE;
+ }
+ else {
+ if ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl()))
+ errno = TFSERR_USERDENIED;
+ }
+ break;
+ case TFS_APPEND: /* Append to the end of the current file. */
+ if (!fp)
+ errno = TFSERR_NOFILE;
+ else {
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ errno = TFSERR_USERDENIED;
+ }
+ break;
+ case TFS_CREATERM: /* Create a new file, allow tfsadd() to remove */
+ fmode = TFS_CREATE; /* it if it exists. */
+ break;
+ case TFS_CREATE: /* Create a new file, error if it exists. */
+ if (fp)
+ errno = TFSERR_FILEEXISTS;
+ break;
+ case (TFS_APPEND|TFS_CREATE): /* If both mode bits are set, clear one */
+ if (fp) { /* based on the presence of the file. */
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ errno = TFSERR_USERDENIED;
+ fmode = TFS_APPEND;
+ }
+ else {
+ fmode = TFS_CREATE;
+ }
+ break;
+ default:
+ errno = TFSERR_BADARG;
+ break;
+ }
+
+ if (errno != TFS_OKAY) {
+ retval = errno;
+ goto done;
+ }
+
+ /* Find an empty slot...
+ */
+ slot = tfsSlots;
+ for (i=0;i<TFS_MAXOPEN;i++,slot++) {
+ if (slot->offset == -1)
+ break;
+ }
+
+ /* Populate the slot structure if a slot is found to be
+ * available...
+ */
+ if (i < TFS_MAXOPEN) {
+ retval = i;
+ slot->hwp = 0;
+ slot->offset = 0;
+ slot->flagmode = fmode;
+ if (fmode & TFS_CREATE) {
+ strncpy(slot->hdr.name,file,TFSNAMESIZE);
+ slot->flagmode |= (flagmode & TFS_FLAGMASK);
+ slot->base = (uchar *)buf;
+ }
+ else if (fmode & TFS_APPEND) {
+ memcpy((char *)&slot->hdr,(char *)fp,sizeof(struct tfshdr));
+ if (s_memcpy((char *)buf,(char *)(TFS_BASE(fp)),
+ fp->filsize,0,0) != 0) {
+ retval = TFSERR_MEMFAIL;
+ goto done;
+ }
+ slot->flagmode = fp->flags;
+ slot->flagmode |= TFS_APPEND;
+ slot->base = (uchar *)buf;
+ slot->hwp = fp->filsize;
+ slot->offset = fp->filsize;
+ }
+ else {
+ slot->base = (uchar *) (TFS_BASE(fp));
+ memcpy((char *)&slot->hdr,(char *)fp,sizeof(struct tfshdr));
+ }
+ }
+ else {
+ retval = TFSERR_NOSLOT;
+ }
+
+done:
+ if (tfsTrace > 0)
+ printf("tfsopen(%s,0x%lx,0x%lx)=%d\n",file,flagmode,(ulong)buf,retval);
+
+ return(retval);
+}
+
+/* tfsclose():
+ * If the file was opened for reading only, then just close out the
+ * entry in the tfsSlots table. If the file was opened for creation,
+ * then add it to the tfs list. Note the additional argument is
+ * only needed for tfsclose() of a newly created file.
+ * info = additional text describing the file.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsclose(int fd,char *info)
+{
+ int err;
+ struct tfsdat *tdat;
+
+ if (!info) info = "";
+
+ if (tfsTrace > 0)
+ printf("tfsclose(%d,%s)\n",fd,info);
+
+ if ((fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+
+ if (tdat->offset == -1)
+ return(TFSERR_BADFD);
+
+ /* Mark the file as closed by setting the offset to -1.
+ * Note that this is done prior to potentially calling tfsadd() so
+ * that tfsadd() will not think the file is opened and reject the add...
+ */
+ tdat->offset = -1;
+
+ /* If the file was opened for creation or append, and the hwp
+ * (high-water-point) is greater than zero, then add it now.
+ *
+ * Note regarding hwp==0...
+ * In cases where a non-existent file is opened for creation,
+ * but then nothing is written to the file, the hwp value will
+ * be zero; hence, no need to call tfsadd().
+ */
+ if ((tdat->flagmode & (TFS_CREATE | TFS_APPEND)) && (tdat->hwp > 0)) {
+ char buf[16];
+
+ err = tfsadd(tdat->hdr.name, info, tfsflagsbtoa(tdat->flagmode,buf),
+ tdat->base, tdat->hwp);
+ if (err != TFS_OKAY) {
+ printf("%s: %s\n",tdat->hdr.name,tfserrmsg(err));
+ return(err);
+ }
+ }
+ return(TFS_OKAY);
+}
+
+#else /* INCLUDE_TFSAPI */
+
+int
+tfstruncate(int fd, long len)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfseof(int fd)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsread(int fd, char *buf, int cnt)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfswrite(int fd, char *buf, int cnt)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsseek(int fd, int offset, int whence)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsopen(char *file,long flagmode,char *buf)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsclose(int fd,char *info)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+tfsipmod(char *name,char *buf,int offset,int size)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+#endif /* INCLUDE_TFSAPI else */
+
+#if INCLUDE_TFSAPI || INCLUDE_TFSSCRIPT
+
+/* tfsgetline():
+ * Read into the buffer a block of characters upto the next EOL delimiter
+ * the file. After the EOL, or after max-1 chars are loaded, terminate
+ * with a NULL. Return the number of characters loaded.
+ * At end of file return 0.
+ * MONLIB NOTICE: this function is accessible through monlib.c.
+ */
+int
+tfsgetline(int fd,char *buf,int max)
+{
+ uchar *from;
+ int tot, rtot;
+ struct tfsdat *tdat;
+ volatile char *to;
+
+ max--;
+
+ if (tfsTrace > 1)
+ printf("tfsgetline(%d,0x%lx,%d)\n",fd,(ulong)buf,max);
+
+ /* Verify valid range of incoming file descriptor. */
+ if ((max < 1) || (fd < 0) || (fd >= TFS_MAXOPEN))
+ return(TFSERR_BADARG);
+
+ /* Make sure the file pointed to by the incoming descriptor is active. */
+ if (tfsSlots[fd].offset == -1)
+ return(TFSERR_BADARG);
+
+ tdat = &tfsSlots[fd];
+
+ if (tdat->offset == -1)
+ return(TFSERR_BADFD);
+
+ if (tdat->offset >= tdat->hdr.filsize)
+ return(0);
+
+ from = (uchar *) tdat->base + tdat->offset;
+ to = buf;
+
+ /* If the incoming buffer size is larger than needed, adjust the
+ * 'max' value so that we don't pass the end of the file...
+ */
+ if ((tdat->offset + max) > tdat->hdr.filsize)
+ max = tdat->hdr.filsize - tdat->offset + 1;
+
+ /* Read from the file data area until newline (0x0a) is found
+ * (or until the 'max buffer space' value is reached).
+ * Strip 0x0d (if present) and terminate with NULL in all cases.
+ */
+ for(rtot=0,tot=0;tot < max; from++) {
+ /* Terminate on Ctrl-Z, non-ASCII, Newline or NULL.
+ * Ignore carriage return completely...
+ */
+ if ((*from == 0x1a) || (*from > 0x7f) || (*from == 0))
+ break;
+
+ tot++;
+
+ if (*from == 0x0d)
+ continue;
+
+ *to = *from;
+ if (*to != *from)
+ return(TFSERR_MEMFAIL);
+
+ to++; rtot++;
+
+ if (*from == 0x0a)
+ break;
+ }
+ *to = 0;
+
+ tdat->offset += tot;
+ return(rtot);
+}
+
+#else
+
+int
+tfsgetline(int fd,char *buf,int max)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+#endif
diff --git a/main/common/tfsclean1.c b/main/common/tfsclean1.c
new file mode 100755
index 0000000..801db29
--- /dev/null
+++ b/main/common/tfsclean1.c
@@ -0,0 +1,2195 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsclean1.c:
+ *
+ * This is one of several different versions of tfsclean(). This version
+ * is by far the most complex, but offers power-hit safety and minimal
+ * flash overhead. It uses a "spare" sector to backup the
+ * "one-sector-at-a-time" defragmentation process.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "flash.h"
+#include "monflags.h"
+#include "warmstart.h"
+
+#if INCLUDE_TFS
+
+#if !INCLUDE_FLASH
+#error: If flash is not included, then use tfsclean2.c
+#endif
+
+#if DEFRAG_TEST_ENABLED
+void
+defragExitTestPoint(int val)
+{
+ if ((DefragTestType == DEFRAG_TEST_EXIT) && (DefragTestPoint == val)) {
+ printf("\n+++++++++ EXIT @ TEST POINT(%d)\n",val);
+ CommandLoop();
+ }
+}
+#else
+#define defragExitTestPoint(val)
+#endif
+
+/* Variables for testing tfsclean():
+ * They are set up through arguments to "tfs clean" in tfscli.c.
+ */
+int DefragTestType;
+int DefragTestPoint;
+int DefragTestSector;
+
+/* defragTick():
+ * Used to show progress, just to let the user know that we aren't
+ * dead in the water.
+ */
+static void
+defragTick(int verbose)
+{
+ static int tick;
+ static char clockhand[] = { '|', '/', '-', '\\' };
+
+ if (!verbose && (!MFLAGS_NODEFRAGPRN())) {
+ if (tick > 3)
+ tick = 0;
+ printf("%c\b",clockhand[tick++]);
+ }
+}
+
+/* defragCrcTable():
+ * Return a pointer to the crc table for the specified TFS device.
+ */
+struct sectorcrc *
+defragCrcTable(TDEV *tdp)
+{
+ return((struct sectorcrc *)(tdp->end+1) - tdp->sectorcount);
+}
+
+/* defragSerase():
+ * Common function to call from within tfsclean() to erase a sector
+ * and generate an error message if necessary.
+ *
+ * If DEFRAG_TEST_ENABLED is defined and the type/sector/point criteria
+ * is met, then instead of erasing the sector; just change the first non-zero
+ * byte to zero to corrupt it. This essentially makes it a corrupted erase.
+ */
+static int
+defragSerase(int tag, int snum)
+{
+ int ret = 0;
+
+#if DEFRAG_TEST_ENABLED
+ int ssize;
+ uchar *sbase, *send, zero;
+
+ printf(" serase_%02d(%02d)\n",tag,snum);
+
+ if ((DefragTestType == DEFRAG_TEST_SERASE) &&
+ (DefragTestSector == snum) && (DefragTestPoint == tag)) {
+ sectortoaddr(snum,&ssize,&sbase);
+ send = sbase+ssize;
+ zero = 0;
+ while(sbase < send) {
+ if (*sbase != 0) {
+ tfsflashwrite((ulong *)sbase,(ulong *)&zero,1);
+ break;
+ }
+ sbase++;
+ }
+ printf("DEFRAG_TEST_SERASE activated @ %d sector %d\n",tag,snum);
+ CommandLoop();
+ }
+ else
+#endif
+ ret = tfsflasherase(snum);
+ if (ret <= 0) {
+ printf("tfsclean() serase erase failed: %d,%d,%d\n",snum,tag,ret);
+ }
+ return(ret);
+}
+
+/* defragFwrite():
+ * Common function to call from within tfsclean() to write to flash
+ * and generate an error message if necessary.
+ * If DEFRAG_TEST_ENABLED is defined and the test type is set to
+ * DEFRAG_TEST_FWRITE, then use APPRAMBASE as the source of the data
+ * so that the end result is an errored flash write.
+ */
+static int
+defragFwrite(int tag, uchar *dest,uchar *src,int size)
+{
+ int ret = 0;
+
+#if DEFRAG_TEST_ENABLED
+ int snum;
+
+ addrtosector((char *)dest,&snum,0,0);
+ printf(" fwrite_%02d(%d,0x%lx,0x%lx,%d)\n",
+ tag,snum,(ulong)dest,(ulong)src,size);
+
+ if ((DefragTestType == DEFRAG_TEST_FWRITE) &&
+ (DefragTestSector == snum) && (DefragTestPoint == tag)) {
+ tfsflashwrite((ulong *)dest,(ulong *)getAppRamStart(),size/2);
+ printf("DEFRAG_TEST_FWRITE activated @ %d sector %d\n",tag,snum);
+ CommandLoop();
+ }
+ else
+#endif
+ ret = tfsflashwrite(dest,src,size);
+ if (ret != TFS_OKAY) {
+ printf("tfsclean() fwrite failed: 0x%lx,0x%lx,%d,%d\n",
+ (ulong)dest,(ulong)src,size,tag);
+ }
+ return(ret);
+}
+
+/* defragGetSpantype():
+ * With the incoming sector base and end (s_base, s_end),
+ * determine the type of span that the incoming file (f_base, f_end)
+ * has across it. There are six different ways the spanning can
+ * occur:
+ * 1. begin and end in previous active sector (bpep);
+ * 2. begin in previously active sector, end in this one (bpec);
+ * 3. begin in previously active sector, end in later one (bpel);
+ * 4. begin and end in this active sector (bcec);
+ * 5. begin in this active sector, end in later one (bcel);
+ * 6. begin and end in later active sector (blel);
+ */
+static int
+defragGetSpantype(char *s_base,char *s_end,char *f_base,char *f_end)
+{
+ int spantype;
+
+ if (f_base < s_base) {
+ if ((f_end > s_base) && (f_end <= s_end))
+ spantype = SPANTYPE_BPEC;
+ else if (f_end > s_end)
+ spantype = SPANTYPE_BPEL;
+ else
+ spantype = SPANTYPE_BPEP;
+ }
+ else {
+ if (f_base > s_end)
+ spantype = SPANTYPE_BLEL;
+ else if (f_end <= s_end)
+ spantype = SPANTYPE_BCEC;
+ else
+ spantype = SPANTYPE_BCEL;
+ }
+ return(spantype);
+}
+
+/* defragGetSpantypeStr():
+ * Return a string that corresponds to the incoming state value.
+ */
+static char *
+defragGetSpantypeStr(int spantype)
+{
+ char *str;
+
+ switch(spantype) {
+ case SPANTYPE_BPEC:
+ str = "BPEC";
+ break;
+ case SPANTYPE_BLEL:
+ str = "BLEL";
+ break;
+ case SPANTYPE_BPEL:
+ str = "BPEL";
+ break;
+ case SPANTYPE_BPEP:
+ str = "BPEP";
+ break;
+ case SPANTYPE_BCEC:
+ str = "BCEC";
+ break;
+ case SPANTYPE_BCEL:
+ str = "BCEL";
+ break;
+ default:
+ str = "???";
+ break;
+ }
+ return(str);
+}
+
+/* defragEraseSpare():
+ * Erase the spare sector associated with the incoming TFS device.
+ * The underlying flash driver SHOULD have a check so that it only
+ * erases the sector if the sector is not already erased, so this
+ * extra check (call to flasherased()) may not be necessary in
+ * most cases.
+ */
+static int
+defragEraseSpare(TDEV *tdp)
+{
+ int snum, ssize;
+ uchar *sbase;
+
+ if (addrtosector((unsigned char *)tdp->spare,&snum,&ssize,&sbase) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ if (!flasherased(sbase,sbase+(ssize-1))) {
+ if (defragSerase(1,snum) < 0) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+ return(TFS_OKAY);
+}
+
+/* defragValidDSI():
+ * Test to see if we have a valid defrag state information (DSI)
+ * area. The DSI area, working back from tdp->end, consists of a
+ * table of 32-bit crcs (one per sector), a table of defraghdr
+ * structures (one per active file) and a 32-bit crc of the DSI
+ * itself. Knowing this format, we can easily step backwards into
+ * the DSI space to see if it all makes sense.
+ * If the table is 100% valid, then we will be able to step
+ * backwards through the DSI to find the 32-bit crc of the DSI area.
+ * If it matches, then we can be sure that the DSI is valid.
+ * Return total number of files in header if the defrag header
+ * table appears to be sane, else 0.
+ */
+static int
+defragValidDSI(TDEV *tdp, struct sectorcrc **scp)
+{
+ int ftot, valid, lastssize;
+ uchar *lastsbase;
+ struct sectorcrc *crctbl;
+ ulong hdrcrc, *crc;
+ struct defraghdr *dhp, dfhcpy;
+
+ ftot = valid = 0;
+ crctbl = defragCrcTable(tdp);
+ dhp = (struct defraghdr *)crctbl - 1;
+ /* next line was <dfhcpy = *dhp> ... */
+ memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr));
+ hdrcrc = dfhcpy.crc;
+ dfhcpy.crc = 0;
+ if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
+ ftot = dhp->idx + 1;
+ dhp = (struct defraghdr *)crctbl - ftot;
+ crc = (ulong *)dhp - 1;
+ if (crc32((uchar *)dhp,(uchar *)tdp->end-(uchar *)dhp) == *crc) {
+ if (scp)
+ *scp = crctbl;
+ return(ftot);
+ }
+ }
+
+ /* It's possible that the DSI space has been relocated to the spare
+ * sector, so check for that here...
+ */
+ addrtosector((unsigned char *)tdp->end,0,&lastssize,&lastsbase);
+
+ crctbl = ((struct sectorcrc *)(tdp->spare+lastssize) - tdp->sectorcount);
+ dhp = (struct defraghdr *)crctbl - 1;
+ /* next line was <dfhcpy = *dhp> ... */
+ memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr));
+ hdrcrc = dfhcpy.crc;
+ dfhcpy.crc = 0;
+ if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
+ ftot = dhp->idx + 1;
+ dhp = (struct defraghdr *)crctbl - ftot;
+ crc = (ulong *)dhp - 1;
+ if (crc32((uchar *)dhp,
+ (uchar *)(tdp->spare+lastssize-1) - (uchar *)dhp) == *crc) {
+#if DEFRAG_TEST_ENABLED
+ printf("TFS: DSI in spare\n");
+#endif
+ if (scp)
+ *scp = crctbl;
+ return(ftot);
+ }
+ }
+ return(0);
+}
+
+/* defragSectorInSpare():
+ * For each sector, run a CRC32 on the content of the spare
+ * using the size of the sector in question. If the calculated
+ * crc matches that of the table, then we have located the sector
+ * that has been copied to the spare.
+ * This is a pain in the butt because we can't just run a CRC32 on
+ * the spare sector itself because the size of the spare may not match
+ * the size of the sector that was copied to it. The source sector
+ * might have been smaller; hence when we calculate the CRC32, we need
+ * to use the size of the potential source sector.
+ */
+static int
+defragSectorInSpare(TDEV *tdp, struct sectorcrc *crctbl)
+{
+ uchar *sbase;
+ struct defraghdr *dhp;
+ int i, ssize, snum, ftot;
+
+ sbase = (uchar *)tdp->start;
+ dhp = (struct defraghdr *)crctbl - 1;
+ ftot = dhp->idx + 1;
+
+ for(i=0;i<tdp->sectorcount;i++) {
+ addrtosector(sbase,&snum,&ssize,0);
+ if (i == tdp->sectorcount - 1) {
+ ssize -= /* CRC table */
+ (tdp->sectorcount * sizeof(struct sectorcrc));
+ ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */
+ ssize -= 4; /* Crc of the tables */
+ }
+ if (crc32((uchar *)tdp->spare,ssize) == crctbl[i].precrc)
+ return(snum);
+ sbase += ssize;
+ }
+ return(-1);
+}
+
+/* defragTouchedSectors():
+ * Step through the crc table and TFS flash space to find the first
+ * and last sectors that have been touched by defragmentation.
+ * This is used by defragGetState() to recover from an interrupted
+ * defragmentation, so a few verbose messages are useful to indicate
+ * status to the user.
+ */
+void
+defragTouchedSectors(TDEV *tdp,int *first, int *last)
+{
+ uchar *sbase;
+ struct defraghdr *dhp;
+ struct sectorcrc *crctbl;
+ int i, ssize, snum, ftot;
+
+ *first = -1;
+ *last = -1;
+ sbase = (uchar *)tdp->start;
+ crctbl = defragCrcTable(tdp);
+ dhp = (struct defraghdr *)crctbl - 1;
+ ftot = dhp->idx + 1;
+
+ printf("TFS: calculating per-sector crcs... ");
+ for(i=0;i<tdp->sectorcount;i++) {
+ addrtosector(sbase,&snum,&ssize,0);
+ if (i == tdp->sectorcount - 1) {
+ ssize -= /* CRC table */
+ (tdp->sectorcount * sizeof(struct sectorcrc));
+ ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */
+ ssize -= 4; /* Crc of the tables */
+ }
+ if (crc32(sbase,ssize) != crctbl[i].precrc) {
+ if (*first == -1)
+ *first = snum;
+ *last = snum;
+ }
+ sbase += ssize;
+ defragTick(0);
+ }
+ printf("done\n");
+ return;
+}
+
+/* defragPostCrcCheck():
+ * Return 1 if the post-crc check of the incoming sector number passes;
+ * else 0.
+ */
+int
+defragPostCrcCheck(TDEV *tdp, int isnum)
+{
+ uchar *sbase;
+ struct defraghdr *dhp;
+ struct sectorcrc *crctbl;
+ int ftot, i, snum, ssize, lastsnum, lastssize;
+
+ sbase = (uchar *)tdp->start;
+ crctbl = defragCrcTable(tdp);
+ dhp = (struct defraghdr *)crctbl - 1;
+ ftot = dhp->idx + 1;
+
+ addrtosector((uchar *)tdp->end,&lastsnum,&lastssize,0);
+
+ for(i=0;i<tdp->sectorcount;i++) {
+ addrtosector(sbase,&snum,&ssize,0);
+ if (snum == isnum)
+ break;
+ sbase += ssize;
+ }
+ if (isnum == lastsnum) {
+ ssize -= (tdp->sectorcount * sizeof(struct sectorcrc));
+ ssize -= (ftot * DEFRAGHDRSIZ);
+ ssize -= 4;
+ }
+ if (crctbl[i].postcrc == crc32(sbase,ssize))
+ return(1);
+ else
+ return(0);
+}
+
+/* defragGetStateStr():
+ * Return a string that corresponds to the incoming state value.
+ */
+static char *
+defragGetStateStr(int state)
+{
+ char *str;
+
+ switch(state) {
+ case SECTOR_DEFRAG_INACTIVE:
+ str = "SectorDefragInactive";
+ break;
+ case SECTOR_DEFRAG_ABORT_RESTART:
+ str = "DefragRestartAborted";
+ break;
+ case SCANNING_ACTIVE_SECTOR_1:
+ str = "ScanningActiveSector1";
+ break;
+ case SCANNING_ACTIVE_SECTOR_2:
+ str = "ScanningActiveSector2";
+ break;
+ case SCANNING_ACTIVE_SECTOR_3:
+ str = "ScanningActiveSector3";
+ break;
+ case SCANNING_ACTIVE_SECTOR_4:
+ str = "ScanningActiveSector4";
+ break;
+ case SCANNING_ACTIVE_SECTOR_5:
+ str = "ScanningActiveSector5";
+ break;
+ case SECTOR_DEFRAG_ALMOST_DONE:
+ str = "DefragAlmostDone";
+ break;
+ default:
+ str = "???";
+ break;
+ }
+ return(str);
+}
+
+/* defragRestart():
+ * Poll the console allowing the user to abort the auto-restart of
+ * the defragmentation. If a character is received on the console,
+ * then return 0 indicating that the defrag should not be restarted;
+ * else return 1.
+ */
+int
+defragRestart(int state,int snum)
+{
+ printf("TFS defrag restart state: %s sector %d\n",
+ defragGetStateStr(state),snum);
+ if (pollConsole("Hit any key to abort..."))
+ return(0);
+ return(1);
+}
+
+/* defragGetState():
+ * Step through the files in the specified device and check for
+ * sanity. Return SECTOR_DEFRAG_INACTIVE if it is determined that
+ * a defragmentation was not in progress; otherwise, return one of
+ * several different defrag state values depending on what is found
+ * in the TFS flash area.
+ *
+ * NOTE:
+ * As of Jan 2008, the code wrapped within the ifdef/endif
+ * ENABLE_FLASHERASED_CHECK_AT_STARTUP is not used by default
+ * (the macro must be defined in config.h to pull it in).
+ * This change has been determined to be safe and allows startup
+ * to be much faster for systems that have a lot of empty TFS
+ * space. The code was used to verify that all flash space after
+ * the last stored file in TFS was actually erased. If not, then
+ * it erases it.
+ * This turns out to not really be necessary because if tfsadd()
+ * runs and finds that the area it needs isn't erased, it will
+ * automatically fall into a tfsclean anyway. As a result, to
+ * make startup quicker, this code is not enabled by default. If
+ * it is needed, then just define the macro in config.h.
+ *
+ * As of Mar 2011, thanks to input from Jamie Randall, I'm essentially
+ * undoing the previous change by defining the
+ * ENABLE_FLASHERASED_CHECK_AT_STARTUP right here. Turns out that
+ * while removal of this snippet of code does make bootup faster for
+ * those cases where the flash has a large number of sectors, it does
+ * cause powersafe defrag to fail in certain cases if a hit occurs.
+ *
+ */
+#define ENABLE_FLASHERASED_CHECK_AT_STARTUP /* see note above */
+
+static int
+defragGetState(TDEV *tdp, int *activesnum)
+{
+ TFILE *tfp;
+ struct defraghdr *dhp;
+ struct sectorcrc *crctbl;
+ int snum_in_spare, firstsnum;
+ int first_touched_snum, last_touched_snum;
+ int break_cause, break1_cause, spare_is_erased, ftot, ftot1, errstate;
+
+ /* Establish state of spare sector:
+ */
+ spare_is_erased = flasherased((uchar *)tdp->spare,
+ (uchar *)tdp->spare+tdp->sparesize-1);
+
+ ftot = 0;
+ break_cause = break1_cause = 0;
+ for(tfp=(TFILE *)tdp->start; tfp < (TFILE *)tdp->end; tfp=tfp->next) {
+ /* If we are legally at the end of file storage space, then we
+ * will hit a header size that is ERASED16. If we reach this
+ * point and the remaining space dedicated to file storage is
+ * erased and the spare is erased, it is safe to assume that we
+ * were not in the middle of a defrag.
+ */
+ if (tfp->hdrsize == ERASED16) {
+#ifdef ENABLE_FLASHERASED_CHECK_AT_STARTUP /* (see note above) */
+ /* Is space from last file to end of TFS space erased? */
+ if (!flasherased((uchar *)tfp,(uchar *)tdp->end)) {
+ break_cause = 1;
+ break;
+ }
+ if (!spare_is_erased) {
+ break_cause = 2;
+ break;
+ }
+#if DEFRAG_TEST_ENABLED
+ printf("\ndefragGetState: inactive_1\n");
+#endif
+#endif
+ return(SECTOR_DEFRAG_INACTIVE);
+ }
+
+ /* If the crc32 of the header is corrupt, or if the next pointer
+ * doesn't make any sense, then we must assume that a defrag
+ * was in progress...
+ */
+ if (tfshdrcrc(tfp) != tfp->hdrcrc) {
+ break;
+ }
+
+ if (!(tfp->next) || (tfp->next <= (TFILE *)tdp->start) ||
+ (tfp->next >= (TFILE *)tdp->end)) {
+ break;
+ }
+ if (TFS_FILEEXISTS(tfp))
+ ftot++;
+ }
+ /* If we are here, then something is not "perfect" with the flash
+ * space used by TFS. If break_cause is non-zero, there is a chance
+ * that the only problem is that a file-write was interrupted and
+ * we did not actually interrupt an in-progress-defrag. An interrupted
+ * file write would place some incomplete data after the last file.
+ */
+ ftot1 = defragValidDSI(tdp,&crctbl);
+
+ /* If we don't have valid defrag state info (DSI), then we can assume
+ * that the files in TFS have not yet been touched (since if we had
+ * touched them, we would have already successfully created the DSI).
+ * This being the case, then we will not continue with any defrag,
+ * let TFS clean things up when the space is needed.
+ */
+ if (!ftot1) {
+ if (break_cause) {
+ /* Hmmm... Should something be done here? */
+ }
+#if DEFRAG_TEST_ENABLED
+ printf("\ndefragGetState: inactive_2\n");
+#endif
+ return(SECTOR_DEFRAG_INACTIVE);
+ }
+
+ /* If we get here, then we have a valid defrag header table, so we
+ * can use it and the state of each of the sectors to figure out
+ * where we are in the defragmentation process. We need to determine
+ * which sector was being worked on at the point in time when the
+ * defragmentation was interrupted. A sector is in the "touched"
+ * state if a crc32 on its content does not match the crc32 stored
+ * in the crc table above the defrag header table.
+ *
+ * Here we step through the defrag header table and see if each file
+ * in the header table exists in TFS. If all files exist, then we
+ * must have been very close to completion of the defrag process.
+ */
+ printf("TFS: scanning DSI space... ");
+ dhp = (struct defraghdr *)crctbl - ftot1;
+ while(dhp < (struct defraghdr *)crctbl) {
+ tfp = (TFILE *)dhp->nda;
+ if (tfp->hdrcrc != dhp->ohdrcrc)
+ break;
+
+ if (tfshdrcrc(tfp) != tfp->hdrcrc) {
+ break1_cause = 1;
+ break;
+ }
+ if (crc32((uchar *)(tfp+1),tfp->filsize) != tfp->filcrc) {
+ break1_cause = 2;
+ break;
+ }
+ dhp++;
+ defragTick(0);
+ }
+ printf("done\n");
+
+ /* If we stepped through the entire table, then we've completed the
+ * file relocation process, but we still have to clean up...
+ */
+ if (dhp >= (struct defraghdr *)crctbl) {
+ if (defragRestart(SECTOR_DEFRAG_ALMOST_DONE,0)) {
+ return(SECTOR_DEFRAG_ALMOST_DONE);
+ }
+ else {
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+ }
+ }
+
+ if (addrtosector((unsigned char *)tdp->start,&firstsnum,0,0) < 0) {
+ errstate = 50;
+ goto state_error;
+ }
+ defragTouchedSectors(tdp,&first_touched_snum,&last_touched_snum);
+
+ /* If there are no touched sectors, then we will not continue with
+ * the defrag because we didn't start relocation of any of the files
+ * yet.
+ */
+ if (first_touched_snum == -1) {
+#if DEFRAG_TEST_ENABLED
+ printf("\ndefragGetState: inactive_3\n");
+#endif
+ return(SECTOR_DEFRAG_INACTIVE);
+ }
+
+ if (spare_is_erased)
+ snum_in_spare = -1;
+ else
+ snum_in_spare = defragSectorInSpare(tdp,crctbl);
+
+#if DEFRAG_TEST_ENABLED
+ printf("\ndefragGetState info: %d %d %d\n",
+ first_touched_snum, last_touched_snum, snum_in_spare);
+#endif
+
+ /* At this point we know what sector was the last to be touched.
+ * What we don't know is whether or not the "touch" was completed.
+ * So we don't know if the active sector is last_touched_snum or
+ * last_touched_snum+1.
+ * The only useful piece of data we 'might' have is the fact that
+ * the spare may contain the content of the last touched sector.
+ */
+
+ /* If the spare is erased, it may be because defrag was just getting
+ * ready to start working on the next sector (meaning that the active
+ * sector is last_touched_snum+1) or the sector was in the process of
+ * being modified. We use the post-crc in the DHT to determine what
+ * the active sector is...
+ */
+ if (spare_is_erased) {
+ if (last_touched_snum >= 0) {
+ if (defragPostCrcCheck(tdp,last_touched_snum)) {
+ *activesnum = last_touched_snum + 1;
+
+ if (defragRestart(SCANNING_ACTIVE_SECTOR_1,*activesnum))
+ return(SCANNING_ACTIVE_SECTOR_1);
+ else
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+ }
+ else {
+ if (defragSerase(2,last_touched_snum) < 0) {
+ errstate = 51;
+ goto state_error;
+ }
+ *activesnum = last_touched_snum;
+
+ if (defragRestart(SCANNING_ACTIVE_SECTOR_2,*activesnum))
+ return(SCANNING_ACTIVE_SECTOR_2);
+ else
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+ }
+
+ }
+ else {
+ errstate = 52;
+ goto state_error;
+ }
+ }
+
+ /* If the sector copied to spare is one greater than the last touched
+ * sector, then the active sector is last_touched_snum+1 and it was
+ * just copied to the spare. In this case we erase the spare and
+ * return indicating the active sector.
+ */
+ if (snum_in_spare == last_touched_snum+1) {
+ if (defragEraseSpare(tdp) < 0) {
+ errstate = 53;
+ goto state_error;
+ }
+ *activesnum = snum_in_spare;
+
+ if (defragRestart(SCANNING_ACTIVE_SECTOR_3,*activesnum))
+ return(SCANNING_ACTIVE_SECTOR_3);
+ else
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+ }
+
+ /* If the spare is not erased, but it does not match any of the
+ * sector CRCs, then we must have been in the process of copying
+ * the active sector to the spare, so we can erase it and return
+ * to the SCANNING_ACTIVE_SECTOR state.
+ */
+ if (snum_in_spare == -1) {
+ if (last_touched_snum >= 0) {
+ *activesnum = last_touched_snum + 1;
+
+ if (!defragRestart(SCANNING_ACTIVE_SECTOR_4,*activesnum))
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+
+ if (defragEraseSpare(tdp) < 0) {
+ errstate = 54;
+ goto state_error;
+ }
+ return(SCANNING_ACTIVE_SECTOR_4);
+ }
+ else {
+ errstate = 55;
+ goto state_error;
+ }
+ }
+
+ /* If the sector copied to spare is the number of the last touched
+ * sector, then we were in the middle of modifying the sector, so
+ * we have to erase that sector, copy the spare to it and return
+ * to the scanning state.
+ */
+ if (snum_in_spare == last_touched_snum) {
+ int ssize;
+ uchar *sbase;
+
+ *activesnum = snum_in_spare;
+
+ if (!defragRestart(SCANNING_ACTIVE_SECTOR_5,*activesnum))
+ return(SECTOR_DEFRAG_ABORT_RESTART);
+
+ if (defragSerase(3,snum_in_spare) < 0) {
+ errstate = 56;
+ goto state_error;
+ }
+ if (sectortoaddr(snum_in_spare,&ssize,&sbase) < 0) {
+ errstate = 57;
+ goto state_error;
+ }
+ if (defragFwrite(1,sbase,(uchar *)tdp->spare,ssize) < 0) {
+ errstate = 58;
+ goto state_error;
+ }
+ if (defragEraseSpare(tdp) < 0) {
+ errstate = 59;
+ goto state_error;
+ }
+ return(SCANNING_ACTIVE_SECTOR_5);
+ }
+
+ /* If we got here, then we are confused, so don't do any defrag
+ * continuation...
+ */
+ errstate = 90;
+
+state_error:
+ printf("DEFRAG_STATE_ERROR: #%d.\n",errstate);
+ return(SECTOR_DEFRAG_INACTIVE);
+}
+
+/* inSector():
+ * We are trying to figure out if the address space that we want to copy
+ * from is within the active sector. If it is, then we need to adjust
+ * our pointers so that we retrieve the at least some of data from the
+ * spare.
+ * If the range specified by 'i_base' and 'i_size' overlays (in any way)
+ * the address space used by the sector specified by 'snum',
+ * then return the address in the spare and the size of the overlay.
+ */
+static int
+inSector(TDEV *tdp,int snum,uchar *i_base,int i_size,uchar **saddr,int *ovlysz)
+{
+ int s_size;
+ uchar *s_base, *s_end, *i_end;
+
+ /* Retrieve information about the sector: */
+ if (sectortoaddr(snum,&s_size,&s_base) == -1)
+ return(TFSERR_MEMFAIL);
+
+ i_end = i_base + i_size;
+ s_end = s_base + s_size;
+
+ if ((i_end < s_base) || (i_base > s_end)) {
+ *ovlysz = 0;
+ return(0);
+ }
+
+ if (i_base < s_base) {
+ if (i_end > s_end) {
+ *ovlysz = s_size;
+ }
+ else {
+ *ovlysz = (i_size - (s_base - i_base));
+ }
+ *saddr = (uchar *)tdp->spare;
+ }
+ else {
+ if (i_end > s_end) {
+ *ovlysz = (i_size - (i_end - s_end));
+ }
+ else {
+ *ovlysz = i_size;
+ }
+ *saddr = (uchar *)tdp->spare + (i_base - s_base);
+ }
+ return(0);
+}
+
+/* struct fillinfo & FILLMODE definitions:
+ * Structure used by the "Fill" functions below.
+ */
+#define FILLMODE_FWRITE 1 /* Do the flash write */
+#define FILLMODE_SPAREOVERLAP 2 /* Determine if there is SPARE overlap */
+#define FILLMODE_CRCONLY 3 /* Calculate a 32-bit crc on the data */
+
+struct fillinfo {
+ struct defraghdr *dhp; /* pointer to defrag header table */
+ TDEV *tdp; /* pointer to TFS device */
+ ulong crc; /* used in FILLMODE_CRCONLY mode */
+ int crcsz; /* size of crc calculation */
+ int fhdr; /* set if we're working on a file header */
+ int asnum; /* the active sector */
+ int mode; /* see FILLMODE_xxx definitions */
+};
+
+/* defragFillFlash():
+ * This function is called by the defragFillActiveSector() function
+ * below. It covers the four different cases of a file spanning over
+ * the active sector, plus it deals with the possibility that the source
+ * of the file data may be the same sector as the active one (meaning that
+ * the source is taken from the spare). It is within this function that
+ * the active sector is actually modified and it assumes that the portion
+ * of the active sector to be written to is already erased.
+ *
+ *
+ * SPANTYPE_BCEC:
+ * In this case, the file starts in the active sector and ends in
+ * the active sector...
+ * -----------|----------|----------|----------|---------|---------|----------
+ * | | | | | | | |
+ * | | |<-active->| | | | SPARE |
+ * | | | sector | | | | SECTOR |
+ * | | | | | | | |
+ * | | | newfile | | | | |
+ * | | | |<-->| | | | | |
+ * -----------|----------|----------|----------|---------|---------|----------
+ *
+ *
+ * SPANTYPE_BPEC:
+ * In this case, the file starts in a sector prior to the currently active
+ * sector and ends in the active sector...
+ * -----------|----------|----------|----------|---------|---------|----------
+ * | | | | | | | |
+ * | | | |<-active->| | | SPARE |
+ * | | | | sector | | | SECTOR |
+ * | | | | | | | |
+ * | | |<----newfile----->| | | | |
+ * | | | | | | | |
+ * -----------|----------|----------|----------|---------|---------|----------
+ *
+ *
+ * SPANTYPE_BPEL:
+ * In this case, the file starts in some sector prior to the currently
+ * active sector and ends in some sector after the currently active
+ * sector...
+ * -----------|----------|----------|----------|---------|---------|----------
+ * | | | | | | | |
+ * | | |<-active->| | | | SPARE |
+ * | | | sector | | | | SECTOR |
+ * | | | | | | | |
+ * | |<---------- newfile------------------->| | | |
+ * | | | | | | | |
+ * -----------|----------|----------|----------|---------|---------|----------
+ *
+ *
+ * SPANTYPE_BCEL:
+ * In this case, the file starts in the active sector and ends in
+ * a later sector.
+ * -----------|----------|----------|----------|---------|---------|----------
+ * | | | | | | | |
+ * | |<-active->| | | | | SPARE |
+ * | | sector | | | | | SECTOR |
+ * | | | | | | | |
+ * | | |<----newfile----->| | | | |
+ * | | ****| | | | | |
+ * -----------|----------|----------|----------|---------|---------|----------
+ */
+static int
+defragFillFlash(struct fillinfo *fip,int spantype,char **activeaddr,int verbose)
+{
+ char *hp;
+ TFILE nfhdr;
+ struct defraghdr *dhp;
+ int ohdroffset, nhdroffset;
+ uchar *ovly, *src, *activesbase;
+ int ovlysz, srcsz, activessize;
+
+ src = 0;
+ ovly = 0;
+ srcsz = 0;
+ nhdroffset = ohdroffset = 0;
+ dhp = fip->dhp;
+
+ if (verbose >= 2) {
+ printf(" defragFillFlash %s %s (%s %d)\n",fip->fhdr ? "hdr" : "dat",
+ defragGetSpantypeStr(spantype), dhp->fname,fip->asnum);
+ }
+
+ if (spantype == SPANTYPE_BCEC) {
+ if (fip->fhdr) {
+ src = (uchar *)dhp->ohdr;
+ srcsz = TFSHDRSIZ;
+ }
+ else {
+ src = (uchar *)dhp->ohdr+TFSHDRSIZ;
+ srcsz = dhp->filsize;
+ }
+ }
+ else if (spantype == SPANTYPE_BPEC) {
+ if (fip->fhdr) {
+ /* Calculate the offset into the header at which point a
+ * sector boundary occurs. Do this for both the old (before
+ * defrag relocation) and new (after defrag relocation)
+ * location of the header.
+ */
+ /* Changed as of Dec 2010, based on error found by Leon...
+ * We need to figure out how the header overlaps the sector
+ * boundary. Prior to 12/2010, this code did not account for
+ * the case where the file size spans beyond the currently
+ * active sector.
+ */
+ if ((dhp->neso > dhp->filsize) && (dhp->oeso > dhp->filsize)) {
+ nhdroffset = TFSHDRSIZ - (dhp->neso - dhp->filsize);
+ ohdroffset = TFSHDRSIZ - (dhp->oeso - dhp->filsize);
+ srcsz = (dhp->oeso - dhp->filsize) + (ohdroffset - nhdroffset);
+ src = (uchar *)dhp->ohdr + nhdroffset;
+ }
+ else {
+ int ssz;
+ int sno = dhp->nesn;
+ int fsz = dhp->filsize;
+ while(sno > fip->asnum) {
+ if (sectortoaddr(sno,&ssz,0) < 0)
+ return(TFSERR_MEMFAIL);
+ if (fsz == dhp->filsize)
+ fsz -= dhp->neso;
+ else
+ fsz -= ssz;
+ sno--;
+ }
+ if (sectortoaddr(fip->asnum,&ssz,0) < 0)
+ return(TFSERR_MEMFAIL);
+ srcsz = ssz - fsz;
+ src = (uchar *)dhp->ohdr;
+ src += (TFSHDRSIZ-srcsz);
+ nhdroffset = (TFSHDRSIZ-srcsz);
+ }
+ }
+ else {
+ src = (uchar *)dhp->ohdr + TFSHDRSIZ + (dhp->filsize - dhp->neso);
+ srcsz = dhp->neso;
+ }
+ }
+ else if (spantype == SPANTYPE_BCEL) {
+ if (sectortoaddr(fip->asnum,&activessize,&activesbase) == -1)
+ return(TFSERR_MEMFAIL);
+
+ if (fip->fhdr) {
+ src = (uchar *)dhp->ohdr;
+ }
+ else {
+ src = (uchar *)dhp->ohdr+TFSHDRSIZ;
+ }
+ srcsz = (activesbase + activessize) - (uchar *)*activeaddr;
+ }
+ else if (spantype == SPANTYPE_BPEL) {
+ if (sectortoaddr(fip->asnum,&activessize,0) == -1)
+ return(TFSERR_MEMFAIL);
+
+ if (fip->fhdr) {
+ src = (uchar *)dhp->ohdr;
+ }
+ else {
+ src = (uchar *)dhp->ohdr+TFSHDRSIZ;
+ }
+
+ src += ((*activeaddr - dhp->nda) - TFSHDRSIZ);
+ srcsz = activessize;
+ }
+ else {
+ return(0);
+ }
+
+ /* Do some error checking on the computed size:
+ */
+ if (srcsz < 0) {
+ printf("defragFillFlash: srcsz < 0\n");
+ return(TFSERR_MEMFAIL);
+ }
+
+ if (fip->fhdr) {
+ if (srcsz > TFSHDRSIZ) {
+ printf("defragFillFlash: srcsz > TFSHDRSIZ\n");
+ return(TFSERR_MEMFAIL);
+ }
+ }
+ else {
+ if (srcsz > dhp->filsize) {
+ printf("defragFillFlash: srcsz > filsize\n");
+ return(TFSERR_MEMFAIL);
+ }
+ }
+
+ /* Determine if any portion of the source was part of the sector that
+ * is now the active sector.. If yes (ovlysz > 0), then we must
+ * deal with the fact that some (or all) of the fill source is in the
+ * spare sector...
+ */
+ if (inSector(fip->tdp,fip->asnum,src,srcsz,&ovly,&ovlysz) < 0)
+ return(TFSERR_MEMFAIL);
+
+ /* If the mode is not FILLMODE_FWRITE, then we don't do any of the
+ * flash operations. We are in this function only to determine
+ * if we need to copy the active sector to the spare prior to
+ * starting the modification of the active sector.
+ */
+ if (fip->mode == FILLMODE_FWRITE) {
+ if (fip->fhdr) {
+ hp = (char *)&nfhdr;
+ if (ovlysz) {
+ memcpy((char *)hp+nhdroffset,(char *)ovly,ovlysz);
+ if (ovlysz != srcsz) {
+ memcpy(hp+nhdroffset+ovlysz,(char *)src+ovlysz,
+ srcsz-ovlysz);
+ }
+ }
+ else {
+ /* next line was <nfhdr = *dhp->ohdr> ... */
+ memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE));
+ }
+ nfhdr.next = dhp->nextfile;
+ if (defragFwrite(2,(uchar *)*activeaddr,(uchar *)hp+nhdroffset,srcsz) == -1)
+ return(TFSERR_FLASHFAILURE);
+ }
+ else {
+ if (ovlysz) {
+ if (defragFwrite(3,(uchar *)*activeaddr,(uchar *)ovly,ovlysz) == -1)
+ return(TFSERR_FLASHFAILURE);
+ if (ovlysz != srcsz) {
+ if (defragFwrite(4,(uchar *)*activeaddr+ovlysz,(uchar *)src+ovlysz,
+ srcsz-ovlysz) == -1)
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+ else {
+ if (defragFwrite(5,(uchar *)*activeaddr,(uchar *)src,srcsz) == -1)
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+ }
+ else if (fip->mode == FILLMODE_CRCONLY) {
+ register uchar *bp;
+ int sz, temp;
+
+ if (fip->fhdr) {
+ hp = (char *)&nfhdr;
+ /* next line was <nfhdr = *dhp->ohdr> ... */
+ memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE));
+ nfhdr.next = dhp->nextfile;
+ bp = (uchar *)hp + nhdroffset;
+ }
+ else {
+ bp = (uchar *)src;
+ }
+ sz = srcsz;
+ fip->crcsz += sz;
+ while(sz) {
+ temp = (fip->crc ^ *bp++) & 0x000000FFL;
+ fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
+ sz--;
+ }
+ }
+ *activeaddr += srcsz;
+
+ if ((spantype == SPANTYPE_BCEC || spantype == SPANTYPE_BPEC) &&
+ (!fip->fhdr) && ((ulong)*activeaddr & 0xf)) {
+ int sz, temp, modfixsize;
+
+ modfixsize = (TFS_FSIZEMOD - ((ulong)*activeaddr & (TFS_FSIZEMOD-1)));
+ *activeaddr += modfixsize;
+ if (fip->mode == FILLMODE_CRCONLY) {
+ sz = modfixsize;
+ fip->crcsz += sz;
+ while(sz) {
+ temp = (fip->crc ^ 0xff) & 0x000000FFL;
+ fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
+ sz--;
+ }
+ }
+ }
+
+ /* Return ovlysz so that the caller will know if this function
+ * needed the spare sector. This is used in the "mode = SPARE_OVERLAP"
+ * pass of defragFillActiveSector().
+ */
+ return(ovlysz);
+}
+
+/* defragFillActiveSector():
+ * This and defragFillFlash() are the workhorses of the tfsclean() function.
+ * The bulk of this function is used to determine if we need to do anything
+ * to the active sector and if so, do we need to copy the active sector to
+ * the spare prior to erasing it.
+ * The first loop in this function determines whether we need to do anything
+ * at all with this sector (it may not be touched by the defragmentation).
+ * The second loop determines if we have to copy the active sector to the
+ * spare prior to erasing the active sector.
+ * The final loop in this function does the call to defragFillFlash()
+ * to do the actual flash writes.
+ */
+static int
+defragFillActiveSector(TDEV *tdp, int ftot, int snum, int verbose)
+{
+ int firstsnum; /* number of first TFS sector */
+ int activesnum; /* number of sector currently being written to */
+ int activessize; /* size of active sector */
+ char *activeaddr; /* offset being written to in the active sector */
+ uchar *activesbase; /* base address of active sector */
+ char *activesend; /* end address of active sector */
+ struct defraghdr *sdhp;/* pointer into defrag hdr table in spare */
+ struct defraghdr *dhp; /* pointer into defrag header table */
+ int fullsize; /* size of file and header */
+ char *new_dend; /* new end of data */
+ char *new_dbase; /* new base of data */
+ char *new_hend; /* new end of header */
+ char *new_hbase; /* new base of header */
+ char *new_fend; /* new end of file */
+ char *new_fbase; /* new base of file */
+ int new_fspan; /* span type for new file */
+ int new_hspan; /* span type for new header */
+ int new_dspan; /* span type for new data */
+ int fillstat; /* result of defragFillFlash() function call */
+ int noreloctot; /* number of files spanning the active sector */
+ /* that do not have to be relocated */
+ int tmptot; /* temps used for the "SPARE_OVERLAP" mode */
+ char *tmpactiveaddr;
+ struct defraghdr *tmpdhp;
+ struct fillinfo finfo;
+ struct sectorcrc *crctbl;
+ int lastsnum, tot;
+ int copytospare;
+ int lastfileisnotrelocated;
+
+ /* Retrieve number of first TFS sector: */
+ if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+
+ activesnum = snum + firstsnum;
+ crctbl = defragCrcTable(tdp);
+
+ /* Retrieve information about active sector: */
+ if (sectortoaddr(activesnum,&activessize,&activesbase) == -1)
+ return(TFSERR_MEMFAIL);
+
+ if (verbose)
+ printf(" Active sector: %3d @ 0x%lx\n",activesnum,(ulong)activesbase);
+
+ if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+
+ /* Establish a pointer to the defrag header table.
+ * For the case when the active sector is the last sector, the defrag
+ * header table will be in the spare, so we also establish a pointer
+ * to that space...
+ */
+ dhp = (struct defraghdr *)crctbl;
+ dhp -= ftot;
+ sdhp = (struct defraghdr *)(tdp->spare+activessize -
+ (tdp->sectorcount * sizeof(struct sectorcrc)));
+ sdhp -= ftot;
+
+ activeaddr = (char *)activesbase;
+ tmpactiveaddr = (char *)activesbase;
+ activesend = (char *)activesbase + activessize - 1;
+
+ /* FIRST LOOP:
+ * See if we need to do anything...
+ * In this state, we are simply checking to see if anything is going
+ * to cause the currently active sector to be written to.
+ * If yes, then we need to copy it to the spare and start the
+ * modification process; else, we just return and do nothing
+ * to this sector.
+ * For each file in the defrag header table that is destined for
+ * the address space occupied by the currently active sector, copy
+ * that file (header and data) to the active sector...
+ * Note that it may only be a partial copy, depending on the size
+ * of the file and the amount of space left in the active sector.
+ */
+
+ noreloctot = 0;
+ new_fspan = SPANTYPE_UNDEF;
+ lastfileisnotrelocated = 0;
+ for(tot=0;tot<ftot;tot++,dhp++,sdhp++) {
+ fullsize = TFSHDRSIZ + dhp->filsize;
+ new_fbase = dhp->nda;
+ new_fend = (new_fbase + fullsize);
+
+ /* We must figure out how the new version of the file will
+ * span across the active sector.
+ * See defragGetSpantype() for details.
+ */
+ new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_fbase,(char *)new_fend);
+
+ /* If the file we are looking at entirely spans a sector that is
+ * prior to the currently active sector, then we just continue
+ * through the list.
+ * If the file entirely spans a sector that is after the
+ * currently active sector, then we are done with this active sector.
+ * If the file falls within the active sector in any way, and its
+ * new location does not match its old location, then we
+ * break out of this loop and begin the modification of this
+ * active sector...
+ */
+ if (new_fspan == SPANTYPE_BLEL)
+ return(0);
+
+ if (new_fspan != SPANTYPE_BPEP) {
+ if (dhp->nda == (char *)dhp->ohdr) {
+ noreloctot++;
+ if (tot == ftot-1) {
+ lastfileisnotrelocated = 1;
+ if (verbose > 1)
+ printf(" last file not relocated\n");
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ /* If tot == ftot, then we got through the entire loop above without
+ * finding a file that needs to be relocated into this active sector.
+ * This means one of two things: either all the files fall into a
+ * sector prior to this active sector, or the files in this active
+ * sector do not need to be relocated. In either case, we simply
+ * return without touching this sector.
+ * Note that we also keep track of the possibility that the last file
+ * may not be relocated. If this ends up to be the case, then we are
+ * simply cleaning up one or more dead files after a full set of active
+ * files, so we should clean up the sector.
+ */
+ if ((tot == ftot) && (lastfileisnotrelocated == 0))
+ return(0);
+
+ /* If tot != ftot, then we must subtract noreloctot from tot so that
+ * we establish 'tot' as the index into the first file that must be
+ * copied to the active sector...
+ */
+ if (noreloctot) {
+ tot -= noreloctot;
+ dhp -= noreloctot;
+ sdhp -= noreloctot;
+ }
+
+ /* Exit immediately before cleaning up the spare... */
+ defragExitTestPoint(10000+activesnum);
+
+ /* Since we got here, we know that we have to do some work on the
+ * currently active sector. We may not have to copy it to the spare,
+ * but we will erase the spare anyway because the sector erase is
+ * supposed to be smart enough to avoid the erase if it is already
+ * erased. This should be handled by the flash driver because in
+ * ALL cases the erase should be avoided if possible.
+ */
+ if (defragEraseSpare(tdp) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ /* Exit immediately after cleaning up the spare... */
+ defragExitTestPoint(10001+activesnum);
+
+ /* If the active sector is the last sector (which would contain the
+ * defrag header table), then we reference the copy of the table that
+ * is in the spare...
+ * Also, if this is the last sector, then we HAVE to copy it to
+ * spare, so we can skip the 2nd loop that attempts to determine
+ * if we need to do it.
+ */
+ if (activesnum == lastsnum) {
+ dhp = sdhp;
+ copytospare = 1;
+ }
+ else {
+ /* SECOND LOOP:
+ * See if we need to copy the active sector to the spare...
+ * We do this by continuing the loop we started above. Notice that
+ * we do an almost identical loop again below this.
+ * On this pass through the loop we are only checking to see if it is
+ * necessary to copy this active sector to the spare.
+ */
+ tmptot = tot;
+ tmpdhp = dhp;
+ copytospare = 0;
+ finfo.mode = FILLMODE_SPAREOVERLAP;
+ for(;tmptot<ftot;tmptot++,tmpdhp++) {
+ finfo.tdp = tdp;
+ finfo.dhp = tmpdhp;
+ finfo.asnum = activesnum;
+
+ fullsize = TFSHDRSIZ + tmpdhp->filsize;
+ new_fbase = tmpdhp->nda;
+ new_fend = (new_fbase + fullsize);
+
+ new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_fbase,(char *)new_fend);
+
+ if (new_fspan == SPANTYPE_BPEP)
+ continue;
+ else if (new_fspan == SPANTYPE_BLEL)
+ break;
+
+ /* Now retrieve span information about header and data
+ * portions of the file (new and orig)...
+ */
+ new_hbase = new_fbase;
+ new_hend = new_hbase + TFSHDRSIZ;
+ new_dbase = new_hbase + TFSHDRSIZ;
+ new_dend = new_fend;
+
+ new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_hbase,(char *)new_hend);
+ new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_dbase,(char *)new_dend);
+
+ /* If defragFillFlash() returns positive (with mode ==
+ * FILLMODE_SPAREOVERLAP set above), then we know that the
+ * spare sector must be loaded with a copy of this active
+ * sector, so we can break out of this loop at that point...
+ */
+ finfo.fhdr = 1;
+ fillstat = defragFillFlash(&finfo,new_hspan,&tmpactiveaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (fillstat > 0) {
+ copytospare = 1;
+ break;
+ }
+ if (new_hspan == SPANTYPE_BCEL)
+ break;
+
+ finfo.fhdr = 0;
+ fillstat = defragFillFlash(&finfo,new_dspan,&tmpactiveaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (fillstat > 0) {
+ copytospare = 1;
+ break;
+ }
+ if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
+ break;
+ }
+ }
+
+ finfo.mode = FILLMODE_FWRITE;
+
+ defragExitTestPoint(10002+activesnum);
+
+ if (copytospare) {
+ defragTick(verbose);
+#if DEFRAG_TEST_ENABLED
+ printf(" copying sector %d to spare\n",activesnum);
+#endif
+ if (defragFwrite(6,(uchar *)tdp->spare,activesbase,activessize) == -1) {
+ printf("Failed to copy active %d to spare\n",activesnum);
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+#if DEFRAG_TEST_ENABLED
+ else {
+ printf(" copy saved\n");
+ }
+#endif
+
+ defragTick(verbose);
+
+ /* We can now begin actual modification of the active sector,
+ * so start off by eraseing it...
+ */
+ defragExitTestPoint(10003+activesnum);
+
+ if (defragSerase(4,activesnum) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ defragExitTestPoint(10004+activesnum);
+
+ /* THIRD LOOP:
+ * Now we pass through the loop to do the real flash modifications...
+ */
+ for(;tot<ftot;tot++,dhp++) {
+ finfo.tdp = tdp;
+ finfo.dhp = dhp;
+ finfo.asnum = activesnum;
+
+ fullsize = TFSHDRSIZ + dhp->filsize;
+ new_fbase = dhp->nda;
+ new_fend = (new_fbase + fullsize);
+
+ new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_fbase,(char *)new_fend);
+
+ if (new_fspan == SPANTYPE_BPEP)
+ continue;
+ else if (new_fspan == SPANTYPE_BLEL)
+ break;
+
+ if (verbose)
+ printf(" File: %s\n",dhp->fname);
+
+ /* Now retrieve span information about header and data
+ * portions of the file (new and orig)...
+ */
+ new_hbase = new_fbase;
+ new_hend = new_hbase + TFSHDRSIZ;
+ new_dbase = new_hbase + TFSHDRSIZ;
+ new_dend = new_fend;
+
+ new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_hbase,(char *)new_hend);
+ new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_dbase,(char *)new_dend);
+
+ /* At this point we have all the information we need to copy
+ * the appropriate amount of the file from orignal space
+ * to new space.
+ * We have to break the write up into two parts, the header
+ * (new_hspan) and the data (new_dspan) so we have to look
+ * at the spantype for each to determine what part of the
+ * header and/or data we are going to copy.
+ *
+ * Also, we must consider the possibility that the source
+ * data may be in the spare sector. This would be the case
+ * if the active sector is the same sector that the original
+ * data was in. If the source data is in the spare sector,
+ * then an added complication is the fact that it may not
+ * all be there, we may have to copy some from the spare,
+ * then some from the original space.
+ */
+ finfo.fhdr = 1;
+ fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (new_hspan == SPANTYPE_BCEL)
+ break;
+
+ finfo.fhdr = 0;
+ fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
+ break;
+ defragTick(verbose);
+ }
+ return(0);
+}
+
+static int
+defragNewSectorCrc(TDEV *tdp, struct defraghdr *dht, int snum,
+ ulong *newcrc, int verbose)
+{
+ int firstsnum; /* number of first TFS sector */
+ int activesnum; /* number of sector currently being written to */
+ int activessize; /* size of active sector */
+ char *activeaddr; /* offset being written to in the active sector */
+ uchar *activesbase; /* base address of active sector */
+ char *activesend; /* end address of active sector */
+ struct defraghdr *dhp; /* pointer into defrag header table */
+ int fullsize; /* size of file and header */
+ char *new_dend; /* new end of data */
+ char *new_dbase; /* new base of data */
+ char *new_hend; /* new end of header */
+ char *new_hbase; /* new base of header */
+ char *new_fend; /* new end of file */
+ char *new_fbase; /* new base of file */
+ int new_fspan; /* span type for new file */
+ int new_hspan; /* span type for new header */
+ int new_dspan; /* span type for new data */
+ int fillstat; /* result of defragFillFlash() function call */
+ int ftot;
+ struct fillinfo finfo;
+ struct sectorcrc *crctbl;
+ int lastsnum, tot, sz, temp;
+
+ /* Retrieve number of first TFS sector: */
+ if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+
+ activesnum = snum + firstsnum;
+ crctbl = defragCrcTable(tdp);
+
+ /* Retrieve information about active sector: */
+ if (sectortoaddr(activesnum,&activessize,&activesbase) == -1)
+ return(TFSERR_MEMFAIL);
+
+ if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+
+ dhp = (struct defraghdr *)crctbl - 1;
+ ftot = dhp->idx + 1;
+ dhp = dht;
+ activeaddr = (char *)activesbase;
+ activesend = (char *)activesbase + activessize - 1;
+
+ finfo.tdp = tdp;
+ finfo.crcsz = 0;
+ finfo.crc = 0xffffffff;
+ finfo.asnum = activesnum;
+ finfo.mode = FILLMODE_CRCONLY;
+
+ for(tot=0;tot<ftot;tot++,dhp++) {
+ finfo.dhp = dhp;
+
+ fullsize = TFSHDRSIZ + dhp->filsize;
+ new_fbase = dhp->nda;
+ new_fend = (new_fbase + fullsize);
+
+ new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_fbase,(char *)new_fend);
+
+ if (new_fspan == SPANTYPE_BPEP)
+ continue;
+ else if (new_fspan == SPANTYPE_BLEL)
+ break;
+
+ /* Now retrieve span information about header and data
+ * portions of the file (new and orig)...
+ */
+ new_hbase = new_fbase;
+ new_hend = new_hbase + TFSHDRSIZ;
+ new_dbase = new_hbase + TFSHDRSIZ;
+ new_dend = new_fend;
+
+ new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_hbase,(char *)new_hend);
+ new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend,
+ (char *)new_dbase,(char *)new_dend);
+
+ finfo.fhdr = 1;
+ fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (new_hspan == SPANTYPE_BCEL)
+ break;
+
+ finfo.fhdr = 0;
+ fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose);
+ if (fillstat < 0)
+ return(fillstat);
+ if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL)
+ break;
+ }
+ sz = activessize - finfo.crcsz;
+
+ /* If this is the last sector, then we must not include the space used
+ * for defrag state storage in the crc calculation.
+ * We deduct size of CRC table, DHT table and the crc of the DSI space...
+ */
+ if (activesnum == lastsnum) {
+ sz -= (tdp->sectorcount * sizeof(struct sectorcrc));
+ sz -= (ftot * DEFRAGHDRSIZ);
+ sz -= 4;
+ }
+ while(sz) {
+ temp = (finfo.crc ^ 0xff) & 0x000000FFL;
+ finfo.crc = ((finfo.crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp];
+ sz--;
+ }
+ *newcrc = ~finfo.crc;
+ return(0);
+}
+
+/* defragBuildCrcTable():
+ * Build the table of sector crcs.
+ * This consists of a set of CRCs representing each sector
+ * before defrag starts and after defrag has completed.
+ * One set for each sector. This table is then used if the
+ * defrag process is interrupted to determine the state of
+ * the interrupted defragmentation process.
+ */
+int
+defragBuildCrcTable(TDEV *tdp, struct defraghdr *dht, int verbose)
+{
+ ulong crc;
+ uchar *sbase;
+ int i, ssize, dhstsize;
+ struct sectorcrc *crctbl;
+
+ dhstsize = (ulong)(tdp->end+1) - (ulong)dht + 4;
+ crctbl = defragCrcTable(tdp);
+
+ /* The pre-defrag crc table...
+ * This one's easy because it is simply a crc for each of the current
+ * sectors.
+ */
+ sbase = (uchar *)tdp->start;
+ for(i=0;i<tdp->sectorcount;i++) {
+ if (addrtosector(sbase,0,&ssize,0) < 0)
+ return(-1);
+
+ if (i == tdp->sectorcount-1)
+ ssize -= dhstsize;
+
+ /* The pre-defrag crc: */
+ crc = crc32(sbase,ssize);
+ if (defragFwrite(7,(uchar *)&crctbl[i].precrc,
+ (uchar *)&crc,4) == -1) {
+ return(-1);
+ }
+
+ /* The post-defrag crc: */
+ if (defragNewSectorCrc(tdp,dht,i,&crc,verbose) < 0)
+ return(-1);
+
+ if (defragFwrite(8,(uchar *)&crctbl[i].postcrc,
+ (uchar *)&crc,4) == -1) {
+ return(-1);
+ }
+
+ sbase += ssize;
+
+ defragTick(0);
+ }
+ return(0);
+}
+
+/* _tfsclean():
+ * This is the front-end of the defragmentation process, following are the
+ * basic steps of defragmentation...
+ *
+ * Build the Defrag State Information (DSI) area:
+ * 1. Create a table of 32-bit CRCs, two for each sector. One is the CRC
+ * of the sector prior to beginning defragmentation and the other is
+ * what will be the CRC of the sector after defragmentation has completed.
+ * These CRCs are used to help recover from an interrupted defragmentation.
+ * 2. Create a table of struct defraghdr structures, one for each file in
+ * TFS that is currently active (not dead).
+ * 3. Create a CRC of the tables created in steps 1 & 2.
+ *
+ * The data created in steps 1-3 is stored at the end of the last sector
+ * used by TFS for file storage. After this is created, the actual flash
+ * defragmentation process starts.
+ *
+ * File relocation:
+ * 4. Step through each sector in TFS flash space, process each file whose
+ * relocated space overlaps with that sector. As each sector is being
+ * re-built, the original version of that sector is stored in the spare.
+ *
+ * End of flash cleanup:
+ * 5. Run through the remaining, now unsused, space in TFS flash and make
+ * sure it is erased.
+ *
+ * File check:
+ * 6. Run a check of all of the relocated files to make sure everything is
+ * still sane.
+ *
+ * Defragmentation success depends on some coordination with tfsadd()...
+ * Whenever a file is added to TFS, tfsadd() must verify that the space
+ * needed for defrag overhead (defrag state & header tables) will be
+ * available. Also, tfsadd() must make sure that the defrag overhead will
+ * always fit into one sector (the sector just prior to the spare).
+ */
+
+int
+_tfsclean(TDEV *tdp, int restart, int verbose)
+{
+ int dhstsize; /* Size of state table overhead */
+ int firstsnum; /* Number of first sector in TFS device. */
+ int lastsnum; /* Number of last sector in TFS device. */
+ int lastssize; /* Size of last sector in TFS device. */
+ uchar *lastsbase; /* Base address of last sector in TFS device. */
+ int sectorcheck; /* Used to verify proper TFS configuration. */
+ struct defraghdr *dht; /* Pointer to defrag header table. */
+ int chkstat; /* Result of tfscheck() after defrag is done. */
+ int ftot; /* Total number of active files in TFS. */
+ int dtot; /* Total number of deleted files in TFS. */
+ int fcnt; /* Running file total, used in hdrtbl build. */
+ TFILE *tfp; /* Misc file pointer */
+ char *newaddress; /* Used to calculate "new" location of file. */
+ struct defraghdr dfhdr; /* Used to build defrag header table. */
+ int activesnum; /* Sector being worked on restarted defrag. */
+ struct sectorcrc *crctbl; /* Pointer to table of per-sector crcs. */
+ int defrag_state;
+ int sidx, snum;
+ char *end;
+
+ if (TfsCleanEnable < 0)
+ return(TFSERR_CLEANOFF);
+
+ /* If incoming TFS device pointer is NULL, return error
+ */
+ if (!tdp)
+ return(TFSERR_BADARG);
+
+ activesnum = 0;
+
+ /* If the 'restart' flag is set, then we only want to do a defrag if
+ * we determine that one is already in progress; so we have to look at
+ * the current state of the defrag state table to figure out if a defrag
+ * was active. If not, just return.
+ */
+ if (restart) {
+ defrag_state = defragGetState(tdp,&activesnum);
+ switch(defrag_state) {
+ case SECTOR_DEFRAG_INACTIVE:
+ case SECTOR_DEFRAG_ABORT_RESTART:
+ return(TFS_OKAY);
+ case SCANNING_ACTIVE_SECTOR_1:
+ case SCANNING_ACTIVE_SECTOR_2:
+ case SCANNING_ACTIVE_SECTOR_3:
+ case SCANNING_ACTIVE_SECTOR_4:
+ case SCANNING_ACTIVE_SECTOR_5:
+ defrag_state = SCANNING_ACTIVE_SECTOR;
+ break;
+ }
+ }
+ else {
+ defrag_state = SECTOR_DEFRAG_INACTIVE;
+ }
+
+ if (verbose || restart || (!MFLAGS_NODEFRAGPRN())) {
+ printf("TFS device '%s' powersafe defragmentation\n",tdp->prefix);
+ if ((restart) && pollConsole("ok?")) {
+ printf("aborted\n");
+ return(TFS_OKAY);
+ }
+ }
+
+ if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+ lastsnum = firstsnum + tdp->sectorcount - 1;
+ if (addrtosector((uchar *)tdp->end,&sectorcheck,0,0) < 0)
+ return(TFSERR_MEMFAIL);
+ if (lastsnum != sectorcheck) {
+ /* If this error occurs, it is an indication that TFS was not
+ * properly configured in config.h, this error should not occur
+ * if TFS is properly configured.
+ */
+ printf("%s: SECTORCOUNT != TFSSTART <-> TFSEND\n", tdp->prefix);
+ printf("First TFS sector = %d, last = %d\n",firstsnum,sectorcheck);
+ return(TFSERR_MEMFAIL);
+ }
+
+ if (defrag_state == SECTOR_DEFRAG_INACTIVE) {
+ activesnum = firstsnum;
+ }
+
+ /* Retrieve information about last sector:
+ */
+ if (sectortoaddr(lastsnum,&lastssize,&lastsbase) == -1)
+ return(TFSERR_MEMFAIL);
+
+ /* Establish a pointer to a table of CRCs that will contain
+ * one 32-bit CRC for each sector (prior to starting the defrag).
+ */
+ crctbl = defragCrcTable(tdp);
+
+ /* Retrieve the number of "dead" and "living" files:
+ * If there are no dead files, then there is no need to defrag.
+ * If there are no "living" files, then we can just init the flash.
+ */
+ ftot = dtot = 0;
+ if (restart && defragValidDSI(tdp,0)) {
+ dht = (struct defraghdr *)crctbl - 1;
+ ftot = dht->idx + 1;
+ }
+ else {
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp))
+ ftot++;
+ else
+ dtot++;
+ tfp = nextfp(tfp,tdp);
+ }
+ if (dtot == 0) {
+ if (verbose)
+ printf("No dead files in %s.\n",tdp->prefix);
+ if (tfsflasherased(tdp,verbose))
+ return(0);
+ if (verbose)
+ printf("Cleaning up end of flash...\n");
+ }
+ }
+ if (ftot == 0) {
+ if (verbose)
+ printf("No active files detected, erasing all %s flash...\n",
+ tdp->prefix);
+ _tfsinit(tdp);
+ return(0);
+ }
+
+ /* Now that we know how many files are in TFS, we can establish
+ * a pointer to the defrag header table, and the size of the table...
+ */
+ dht = (struct defraghdr *)crctbl - ftot;
+ dhstsize = (ulong)(tdp->end+1) - (ulong)dht;
+ dhstsize += 4; /* Account for the CRC of the state tables. */
+
+ if (defrag_state == SECTOR_DEFRAG_INACTIVE) {
+ ulong crc;
+
+ if (verbose) {
+ printf("TFS defrag: building DSI space...\n");
+ }
+
+ /* We start by making sure that the space needed by the
+ * defrag header and state table at the end of the last
+ * sector is clear...
+ */
+ if (!flasherased((uchar *)dht, (uchar *)(tdp->end))) {
+ if (defragEraseSpare(tdp) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ if (defragFwrite(9,(uchar *)(tdp->spare),lastsbase,
+ lastssize-dhstsize) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ if (defragSerase(5,lastsnum) < 0) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ if (defragFwrite(10,lastsbase,(uchar *)(tdp->spare),
+ lastssize) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+
+ /* Erase the spare then copy the portion of the last TFS
+ * sector that does not overlap with the defrag header and
+ * state table area to the spare. We do this so that the spare
+ * sector contains a defrag header and state table area that
+ * is erased.
+ */
+ if (defragEraseSpare(tdp) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ if (defragFwrite(11,(uchar *)tdp->spare,
+ lastsbase,lastssize-dhstsize) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+
+ /* At this point we have a valid copy of the last sector in
+ * the spare. If any portion of the last sector is not identical
+ * to what is in the spare, then we need to erase the last sector
+ * and re-copy what is in the spare to the last sector. This is
+ * necessary because an interrupt may have occurred while writing
+ * to the last sector, and it may have corrupted something.
+ */
+
+ if ((memcmp((char *)lastsbase,(char *)(tdp->spare),lastssize-dhstsize)) ||
+ (!flasherased((uchar *)dht,(uchar *)tdp->end))) {
+ if (defragSerase(6,lastsnum) < 0) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ if (defragFwrite(12,lastsbase,(uchar *)(tdp->spare),
+ lastssize) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+ /* Build the header table:
+ */
+ fcnt = 0;
+ tfp = (TFILE *)tdp->start;
+ newaddress = (char *)tdp->start;
+
+ if (verbose > 2) {
+ printf("\nDEFRAG HEADER DATA (dht=0x%lx, ftot=%d):\n",
+ (ulong)dht,ftot);
+ }
+
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ uchar *base, *eof, *neof, *nbase;
+ int size, slot;
+ struct tfsdat *slotptr;
+
+ strcpy(dfhdr.fname,TFS_NAME(tfp));
+ dfhdr.ohdr = tfp;
+ dfhdr.ohdrcrc = tfp->hdrcrc;
+ dfhdr.filsize = TFS_SIZE(tfp);
+ if (addrtosector((uchar *)tfp,0,0,&base) < 0)
+ return(TFSERR_MEMFAIL);
+
+ eof = (uchar *)(tfp+1)+TFS_SIZE(tfp)-1;
+ if (addrtosector((uchar *)eof,0,0,&base) < 0)
+ return(TFSERR_MEMFAIL);
+ dfhdr.oeso = eof - base + 1;
+
+ neof = (uchar *)newaddress+TFSHDRSIZ+TFS_SIZE(tfp)-1;
+ if (addrtosector((uchar *)neof,&dfhdr.nesn,0,&nbase) < 0)
+ return(TFSERR_MEMFAIL);
+ dfhdr.neso = neof - nbase + 1;
+
+ dfhdr.crc = 0;
+ dfhdr.idx = fcnt;
+ dfhdr.nda = newaddress;
+
+ /* If the file is currently opened, adjust the base address. */
+ slotptr = tfsSlots;
+ for (slot=0;slot<TFS_MAXOPEN;slot++,slotptr++) {
+ if (slotptr->offset != -1) {
+ if (slotptr->base == (uchar *)(TFS_BASE(tfp))) {
+ slotptr->base = (uchar *)(newaddress+TFSHDRSIZ);
+ }
+ }
+ }
+ size = TFS_SIZE(tfp) + TFSHDRSIZ;
+ if (size & 0xf) {
+ size += TFS_FSIZEMOD;
+ size &= ~(TFS_FSIZEMOD-1);
+ }
+ newaddress += size;
+ dfhdr.nextfile = (TFILE *)newaddress;
+ dfhdr.crc = crc32((uchar *)&dfhdr,DEFRAGHDRSIZ);
+ if (verbose > 2) {
+ printf(" File %s (sz=%d):\n",TFS_NAME(tfp),TFS_SIZE(tfp));
+ printf(" nda= 0x%08lx, ohdr= 0x%08lx, nxt= 0x%08lx\n",
+ (ulong)(dfhdr.nda),(ulong)(dfhdr.ohdr),
+ (ulong)(dfhdr.nextfile));
+ printf(" oeso= 0x%08lx, nesn= 0x%08lx, neso= 0x%08lx\n",
+ (ulong)(dfhdr.oeso),(ulong)(dfhdr.nesn),
+ (ulong)(dfhdr.neso));
+ }
+ if (defragFwrite(13,(uchar *)(&dht[fcnt]),
+ (uchar *)(&dfhdr),DEFRAGHDRSIZ) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+ fcnt++;
+ defragTick(0);
+ }
+ tfp = nextfp(tfp,tdp);
+ }
+
+ if (defragBuildCrcTable(tdp,dht,verbose) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ /* Now, the last part of the state table build is to store a
+ * 32-bit crc of the data we just wrote...
+ */
+ crc = crc32((uchar *)dht,(uchar *)tdp->end - (uchar *)dht);
+ if (defragFwrite(14,(uchar *)((ulong *)dht-1),(uchar *)&crc,4) == -1) {
+ return(TFSERR_FLASHFAILURE);
+ }
+
+ defrag_state = SCANNING_ACTIVE_SECTOR;
+ }
+
+ /* Exit here to have a complete defrag header installed. */
+ defragExitTestPoint(1000);
+
+ if (defrag_state == SCANNING_ACTIVE_SECTOR) {
+
+ if (verbose) {
+ printf("TFS: updating sectors %d-%d...\n",
+ activesnum,lastsnum);
+ }
+
+ /* Now we begin the actual defragmentation. We have built enough
+ * state information (defrag header and state table) into the last
+ * TFS sector, so now we can start the cleanup.
+ */
+ for(sidx = activesnum - firstsnum; sidx < tdp->sectorcount; sidx++) {
+ if (defragFillActiveSector(tdp,ftot,sidx,verbose) < 0)
+ return(TFSERR_FLASHFAILURE);
+ }
+
+ defrag_state = SECTOR_DEFRAG_ALMOST_DONE;
+ }
+
+ /* Exit here to test "almost-done" state detection. */
+ defragExitTestPoint(1001);
+
+ if (defrag_state == SECTOR_DEFRAG_ALMOST_DONE) {
+
+ /* We've completed the relocation of all files into a defragmented
+ * area of TFS flash space. Now we have to erase all sectors after
+ * the sector used by the last file in TFS (including the spare)...
+ * If the last file in TFS uses the last sector, then the defrag
+ * header table will be erased and there is nothing left to do
+ * except erase the spare.
+ */
+ if (verbose) {
+ printf("TFS: clearing available space...\n");
+ }
+ if (dht[ftot-1].crc != ERASED32) {
+ end = (dht[ftot-1].nda + dht[ftot-1].filsize + TFSHDRSIZ) - 1;
+ if (addrtosector((uchar *)end,&snum,0,0) < 0)
+ return(TFSERR_FLASHFAILURE);
+ snum++;
+ while(snum <= lastsnum) {
+ if (defragSerase(7,snum) < 0)
+ return(TFSERR_FLASHFAILURE);
+ snum++;
+ defragTick(0);
+ }
+ }
+ if (defragEraseSpare(tdp) < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ /* All defragmentation is done, so verify sanity of files... */
+ chkstat = tfscheck(tdp,verbose);
+ }
+ else {
+ chkstat = TFS_OKAY;
+ }
+
+ if ((verbose) || (!MFLAGS_NODEFRAGPRN()))
+ printf("Defragmentation complete\n");
+
+ return(chkstat);
+}
+
+/* tfsfixup():
+ * Called at system startup to finish up a TFS defragmentation if one
+ * was in progress.
+ */
+int
+tfsfixup(int verbose, int dontquery)
+{
+ TDEV *tdp;
+
+ /* Clear test data... */
+ DefragTestType = 0;
+ DefragTestPoint = 0;
+ DefragTestSector = 0;
+
+#if !DEFRAG_TEST_ENABLED
+ tfsTrace = 99;
+#endif
+
+ /* For each TFS device, run defrag with "fixup" flag set to let
+ * the defragger know that it should only defrag if a defrag was
+ * in progress.
+ */
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ /* Call tfsclean() with fixup flag set... */
+#if TFS_VERBOSE_STARTUP
+ if (StateOfMonitor == INITIALIZE)
+ printf("TFS Scanning %s...\n",tdp->prefix);
+#endif
+ _tfsclean(tdp,1,99);
+ }
+
+#if !DEFRAG_TEST_ENABLED
+ tfsTrace = 0;
+#endif
+ return(0);
+}
+
+#if DEFRAG_TEST_ENABLED
+int
+dumpDhdr(DEFRAGHDR *dhp)
+{
+ printf("ohdr: 0x%08lx\n",(ulong)dhp->ohdr);
+ printf("nextfile: 0x%08lx\n",(ulong)dhp->nextfile);
+ printf("filsize: 0x%08lx\n",(ulong)dhp->filsize);
+ printf("crc: 0x%08lx\n",(ulong)dhp->crc);
+ printf("idx: 0x%08lx\n",(ulong)dhp->idx);
+ printf("nesn: 0x%08lx\n",(ulong)dhp->nesn);
+ printf("neso: 0x%08lx\n",(ulong)dhp->neso);
+ printf("nda: 0x%08lx\n",(ulong)dhp->nda);
+ printf("fname: %s\n",dhp->fname);
+ return(TFS_OKAY);
+}
+
+int
+dumpDhdrTbl(DEFRAGHDR *dhp, int ftot)
+{
+ TDEV *tdp;
+ uchar *sbase;
+ ulong *crc, calccrc;
+ int i, ssize, snum;
+ struct sectorcrc *crctbl;
+
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+
+ if (!dhp) {
+ crctbl = defragCrcTable(tdp);
+ printf("Device %s...\n",tdp->prefix);
+ dhp = (struct defraghdr *)crctbl - 1;
+ ftot = dhp->idx + 1;
+ printf("(%d files):\n",ftot);
+ dhp = (struct defraghdr *)crctbl - ftot;
+ crc = (ulong *)dhp-1;
+ if (*crc != crc32((uchar *)dhp,(uchar *)tdp->end - (uchar *)dhp)) {
+ printf("Table CRC failure\n");
+ return(TFS_OKAY);
+ }
+ }
+ else
+ crctbl = (struct sectorcrc *)(dhp + ftot);
+
+ printf("dhp=0x%lx, ftot=%d\n",(ulong)dhp,ftot);
+
+ while(dhp < (struct defraghdr *)crctbl) {
+ printf(" %s (dhp=0x%lx, idx=%ld):\n",
+ dhp->fname,(ulong)dhp,dhp->idx);
+ printf(" nda: 0x%08lx, ohdr: 0x%08lx\n",
+ (ulong)dhp->nda,(ulong)dhp->ohdr);
+ dhp++;
+ }
+
+ sbase = (uchar *)tdp->start;
+ printf("crctbl at 0x%lx\n",(ulong)crctbl);
+ for(i=0;i<tdp->sectorcount;i++) {
+ if (addrtosector(sbase,&snum,&ssize,0) < 0)
+ return(0);
+ if (i == tdp->sectorcount-1) {
+ ssize -= /* CRC table */
+ (tdp->sectorcount * sizeof(struct sectorcrc));
+ ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */
+ ssize -= 4; /* Crc of the tables */
+ }
+ calccrc = crc32(sbase,ssize);
+ if (calccrc == crctbl[i].precrc)
+ printf("crctbl[%d] (snum=%d) pre-pass\n",i,snum);
+ else if (calccrc == crctbl[i].postcrc)
+ printf("crctbl[%d] (snum=%d) post-pass\n",i,snum);
+ else {
+ printf("crctbl[%d] (snum=%d) test failed\n",i,snum);
+ printf("pre: 0x%lx, post: 0x%lx,calc: 0x%lx\n",
+ crctbl[i].precrc,crctbl[i].postcrc,calccrc);
+ }
+ sbase += ssize;
+ }
+ }
+ return(TFS_OKAY);
+}
+#endif /* DEFRAG_TEST_ENABLED */
+#endif /* INCLUDE_TFS */
diff --git a/main/common/tfsclean2.c b/main/common/tfsclean2.c
new file mode 100644
index 0000000..e304f88
--- /dev/null
+++ b/main/common/tfsclean2.c
@@ -0,0 +1,180 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsclean2.c:
+ *
+ * This version of defragmentation is not power-hit safe and does not
+ * require any flash overhead. The defragmentation simply copies all
+ * good files to an allocated block of ram erases the flash, then copies
+ * the concatenated data back to the flash. Simple but dangerous.
+ *
+ * If automatic defragmentation (through tfsadd()) is to be used in this
+ * mode, then the application must reside in ram space that is above
+ * APPRAMSTART + SIZEOF_TFSFLASH. This version of defragmentation assumes
+ * that the ram space needed for defrag will start at APPRAMBASE.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "flash.h"
+#include "monflags.h"
+
+#if INCLUDE_TFS
+
+int
+tfsfixup(int verbose, int dontquery)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+#if DEFRAG_TEST_ENABLED
+int
+dumpDhdr(DEFRAGHDR *dhp)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+dumpDhdrTbl(DEFRAGHDR *dhp, int ftot)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+#endif
+
+
+/* _tfsclean():
+ * This is an alternative to the complicated defragmentation above.
+ * It simply scans through the file list and copies all valid files
+ * to RAM; then flash is erased and the RAM is copied back to flash.
+ * <<< WARNING >>>
+ * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY
+ * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE.
+ */
+int
+_tfsclean(TDEV *tdp, int notused, int verbose)
+{
+ TFILE *tfp;
+ ulong appramstart;
+ uchar *tbuf, *cp1, *cp2;
+ int dtot, nfadd, len, chkstat;
+#if INCLUDE_FLASH
+ TFILE *lasttfp;
+#endif
+
+ if (TfsCleanEnable < 0)
+ return(TFSERR_CLEANOFF);
+
+ appramstart = getAppRamStart();
+
+ /* Determine how many "dead" files exist. */
+ dtot = 0;
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ if (!TFS_FILEEXISTS(tfp))
+ dtot++;
+ tfp = nextfp(tfp,tdp);
+ }
+
+ if (dtot == 0)
+ return(TFS_OKAY);
+
+ printf("TFS device '%s' non-powersafe defragmentation\n",tdp->prefix);
+
+ tbuf = (uchar *)appramstart;
+ tfp = (TFILE *)(tdp->start);
+#if INCLUDE_FLASH
+ lasttfp = tfp;
+#endif
+ nfadd = tdp->start;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ len = TFS_SIZE(tfp) + sizeof(struct tfshdr);
+ if (len % TFS_FSIZEMOD)
+ len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD);
+ nfadd += len;
+ if (s_memcpy((char *)tbuf,(char *)tfp,len,0,0) != 0)
+ return(TFSERR_MEMFAIL);
+
+ ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd;
+ tbuf += len;
+ }
+#if INCLUDE_FLASH
+ lasttfp = tfp;
+#endif
+ tfp = nextfp(tfp,tdp);
+ }
+
+ /* We've now copied all of the active files from flash to ram.
+ * Now we want to see how much of the flash space needs to be
+ * erased. We only need to erase the sectors that have changed...
+ */
+ cp1 = (uchar *)tdp->start;
+ cp2 = (uchar *)appramstart;
+ while(cp2 < tbuf) {
+ if (*cp1 != *cp2)
+ break;
+ cp1++; cp2++;
+ }
+#if INCLUDE_FLASH
+ if ((cp2 != tbuf) || (!TFS_FILEEXISTS(lasttfp))) {
+ int first, last;
+
+ if (addrtosector(cp1,&first,0,0) == -1)
+ return(TFSERR_FLASHFAILURE);
+
+ if (addrtosector((uchar *)tdp->end,&last,0,0) == -1)
+ return(TFSERR_FLASHFAILURE);
+ printf("Erasing sectors %d-%d...\n",first,last);
+ while(first<last) {
+ if (flasherase(first++) == 0)
+ return(TFSERR_FLASHFAILURE);
+ }
+ }
+#endif
+
+ /* Copy data placed in RAM back to flash: */
+ printf("Restoring flash...\n");
+ if (TFS_DEVTYPE_ISRAM(tdp)) {
+ memcpy((char *)(tdp->start),(char *)appramstart,
+ (tbuf-(uchar*)appramstart));
+ }
+ else {
+#if INCLUDE_FLASH
+ int err;
+
+ err = AppFlashWrite((uchar *)(tdp->start),(uchar *)appramstart,
+ (tbuf-(uchar*)appramstart));
+ if (err < 0)
+#endif
+ return(TFSERR_FLASHFAILURE);
+ }
+
+ /* All defragmentation is done, so verify sanity of files... */
+ chkstat = tfscheck(tdp,verbose);
+
+ return(chkstat);
+}
+#endif
diff --git a/main/common/tfsclean3.c b/main/common/tfsclean3.c
new file mode 100644
index 0000000..af095b0
--- /dev/null
+++ b/main/common/tfsclean3.c
@@ -0,0 +1,153 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsclean3.c:
+ *
+ * --- NOT READY YET ---
+ *
+ * This version of defragmentation is power-hit safe and requires
+ * that there be double the amount of flash as is needed for use by
+ * TFS. The basic idea is similar to tfsclean2.c...
+ * Copy all of the good files over to the "other" flash bank, then have
+ * TFS use the "other" bank as the storage area.
+ * The idea is that the defrag is simply a copy of the good stuff to
+ * the alternate flash block. This requires that after the
+ * good stuff is copied, the now-dirty flash block must be erased in
+ * the background prior to the next tfsclean() call. The fact that
+ * there is no sector erase is what makes this faster.
+ *
+ * If both of these flash banks are in the same flash device, then
+ * having a background erase in progress means that it must be an
+ * interruptible erase (device specific). This is necessary because
+ * while the background erase is in progress there may be a need to
+ * interact with the flash and most devices don't let you do both at the
+ * same time.
+ *
+ * Note that this "background-erase" is what makes this method the
+ * fastest defrag method. It does require that the erase operation be
+ * interruptible, and it requires that the application will provide the
+ * hooks to do this...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "flash.h"
+#include "monflags.h"
+
+#if INCLUDE_TFS
+
+int
+tfsfixup(int verbose, int dontquery)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+#if DEFRAG_TEST_ENABLED
+int
+dumpDhdr(DEFRAGHDR *dhp)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+
+int
+dumpDhdrTbl(DEFRAGHDR *dhp, int ftot)
+{
+ return(TFSERR_NOTAVAILABLE);
+}
+#endif
+
+
+/* _tfsclean():
+ * This is an alternative to the complicated defragmentation above.
+ * It simply scans through the file list and copies all valid files
+ * to RAM; then flash is erased and the RAM is copied back to flash.
+ * <<< WARNING >>>
+ * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY
+ * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE.
+ */
+int
+_tfsclean(TDEV *tdp, int notused, int verbose)
+{
+ TFILE *tfp;
+ uchar *tbuf;
+ ulong appramstart;
+ int dtot, nfadd, len, err, chkstat;
+
+ if (TfsCleanEnable < 0)
+ return(TFSERR_CLEANOFF);
+
+ appramstart = getAppRamStart();
+
+ /* Determine how many "dead" files exist. */
+ dtot = 0;
+ tfp = (TFILE *)tdp->start;
+ while(validtfshdr(tfp)) {
+ if (!TFS_FILEEXISTS(tfp))
+ dtot++;
+ tfp = nextfp(tfp,tdp);
+ }
+
+ if (dtot == 0)
+ return(TFS_OKAY);
+
+ printf("Reconstructing device %s with %d dead file%s removed...\n",
+ tdp->prefix, dtot,dtot>1 ? "s":"");
+
+ tbuf = (char *)appramstart;
+ tfp = (TFILE *)(tdp->start);
+ nfadd = tdp->start;
+ while(validtfshdr(tfp)) {
+ if (TFS_FILEEXISTS(tfp)) {
+ len = TFS_SIZE(tfp) + sizeof(struct tfshdr);
+ if (len % TFS_FSIZEMOD)
+ len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD);
+ nfadd += len;
+ if (s_memcpy(tbuf,(uchar *)tfp,len,0,0) != 0)
+ return(TFSERR_MEMFAIL);
+
+ ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd;
+ tbuf += len;
+ }
+ tfp = nextfp(tfp,tdp);
+ }
+
+ /* Erase the flash device: */
+ err = _tfsinit(tdp);
+ if (err != TFS_OKAY)
+ return(err);
+
+ /* Copy data placed in RAM back to flash: */
+ err = AppFlashWrite((ulong *)(tdp->start),(ulong *)appramstart,
+ (tbuf-(uchar*)appramstart));
+ if (err < 0)
+ return(TFSERR_FLASHFAILURE);
+
+ /* All defragmentation is done, so verify sanity of files... */
+ chkstat = tfscheck(tdp,verbose);
+
+ return(chkstat);
+}
+#endif
diff --git a/main/common/tfscli.c b/main/common/tfscli.c
new file mode 100644
index 0000000..754d20c
--- /dev/null
+++ b/main/common/tfscli.c
@@ -0,0 +1,939 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfscli.c:
+ *
+ * This file contains the TFS code that is only needed if the "tfs" command
+ * is included in the command set.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+
+#if INCLUDE_TFSCLI
+
+/* tfsprflags():
+ * Print the specified set of flags.
+ */
+static void
+tfsprflags(long flags, int verbose)
+{
+ struct tfsflg *tfp;
+
+ if (verbose)
+ printf(" Flags: ");
+ tfp = tfsflgtbl;
+ while(tfp->sdesc) {
+ if ((flags & tfp->mask) == tfp->flag) {
+ if (verbose) {
+ printf("%s", tfp->ldesc);
+ if ((tfp+1)->flag)
+ printf(", ");
+ }
+ else
+ putchar(tfp->sdesc);
+ }
+ tfp++;
+ }
+ if (!(flags & TFS_NSTALE))
+ printf("stale");
+
+ if (verbose)
+ printf("\n");
+}
+
+static char *
+tfsmodebtoa(ulong mode,char *buf)
+{
+ char *pipe, *bp;
+
+ pipe = "";
+ bp = buf;
+ *bp = 0;
+ if (mode & TFS_RDONLY) {
+ bp += sprintf(bp,"rdonly");
+ pipe = "|";
+ }
+ if (mode & TFS_CREATE) {
+ bp += sprintf(bp,"%screate",pipe);
+ pipe = "|";
+ }
+ if (mode & TFS_APPEND)
+ sprintf(bp,"%sappend",pipe);
+
+ return(buf);
+}
+
+/* tfsld():
+ * If the filename specified is AOUT, COFF or ELF, then load it.
+ */
+static int
+tfsld(char *name,int verbose,char *sname,int verifyonly)
+{
+ int err;
+ TFILE *fp;
+
+ err = TFS_OKAY;
+ fp = tfsstat(name);
+
+ if (!fp)
+ return (TFSERR_NOFILE);
+
+ if (TFS_USRLVL(fp) > getUsrLvl())
+ return(TFSERR_USERDENIED);
+
+ if (fp->flags & TFS_EBIN) {
+ long entry;
+
+ err = tfsloadebin(fp,verbose,&entry,sname,verifyonly);
+ if (err == TFS_OKAY) {
+ char buf[16];
+ sprintf(buf,"0x%lx",entry);
+ setenv("ENTRYPOINT",buf);
+ }
+ else
+ setenv("ENTRYPOINT",0);
+ }
+ else {
+ err = TFSERR_NOTEXEC;
+ }
+
+ return(err);
+}
+
+/* listfilter():
+ * If the incoming filename (fname) passes the incoming filter, then
+ * return 1; else return 0.
+ *
+ * Examples:
+ * if filter is "*.html" and fname is "index.html" return 1.
+ * if filter is "dir SLASH ASTERISK" and fname is "dir/abc" return 1.
+ * if filter is "abc" and fname is "abc" return 1.
+ *
+ * Notes:
+ * * A valid filter will have the asterisk as either the first or last
+ * character of the filter. If first, assume filter is a suffix,
+ * if last (or none at all), assume filter is a prefix.
+ * * If there is an asterisk in the middle of the filter, it is chopped
+ * at the asterisk without warning.
+ */
+static int
+listfilter(char *filter,char *fname)
+{
+ int flen;
+ char *prefix, *suffix, *asterisk, *sp;
+
+ if (!filter) /* No filter means match everything. */
+ return(1);
+
+ flen = 0;
+ prefix = suffix = (char *)0;
+ asterisk = strchr(filter,'*');
+
+ /* If no asterisk, then just compare filter to fname... */
+ if (!asterisk) {
+ if (!strcmp(filter,fname))
+ return(1);
+ }
+ else if (asterisk == filter) {
+ suffix = asterisk+1;
+ flen = strlen(suffix);
+ sp = fname + strlen(fname) - flen;
+ if (!strcmp(suffix,sp))
+ return(1);
+ }
+ else {
+ *asterisk = 0;
+ prefix = filter;
+ flen = strlen(prefix);
+ if (!strncmp(prefix,fname,flen)) {
+ *asterisk = '*';
+ return(1);
+ }
+ *asterisk = '*';
+ }
+ return(0);
+}
+
+/* tfsvlist(): verbose list...
+ * Display all files currently stored. Do not put them in alphabetical
+ * order; display them as they are physically listed in the file system.
+ * Display complete structure of file header for each file.
+ * Note1: This version of file listing is only called if "tfs -vv ls"
+ * or "tfs -vvv ls" is called. The first level of verbosity is handled
+ * by tfsqlist to simply display the "dot" files.
+ */
+static int
+tfsvlist(char *filter[], int verbose, int more)
+{
+ TDEV *tdp;
+ TFILE *fp;
+ int tot, sizetot;
+ char tbuf[32], **fltrptr;
+
+ tot = 0;
+ sizetot = 0;
+ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
+ fltrptr = filter;
+ while(1) {
+ fp = (TFILE *)tdp->start;
+ while(validtfshdr(fp)) {
+
+ if ((TFS_DELETED(fp)) && (verbose < 3)) {
+ fp = nextfp(fp,tdp);
+ continue;
+ }
+ if (!listfilter(*fltrptr,TFS_NAME(fp))) {
+ fp = nextfp(fp,tdp);
+ continue;
+ }
+ if ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp)>getUsrLvl())) {
+ fp = nextfp(fp,tdp);
+ continue;
+ }
+ printf(" Name: '%s'%s\n",
+ fp->name,TFS_DELETED(fp) ? " (deleted)" : "");
+ printf(" Info: '%s'\n", fp->info);
+ if (TFS_FILEEXISTS(fp))
+ tfsprflags(fp->flags, 1);
+ printf(" Addr: 0x%lx (hdr @ 0x%lx, nxtptr = 0x%lx)\n",
+ (ulong)(TFS_BASE(fp)),(ulong)fp,(ulong)(fp->next));
+ printf(" Size: %ld bytes (crc=0x%lx)",
+ fp->filsize,fp->filcrc);
+#if INCLUDE_FLASH
+ if ((tdp->devinfo & TFS_DEVTYPE_MASK) != TFS_DEVTYPE_RAM) {
+ int start_sector, end_sector;
+ addrtosector((uchar *)fp,&start_sector,0,0);
+ addrtosector((uchar *)fp+fp->filsize+TFSHDRSIZ,
+ &end_sector,0,0);
+ if (start_sector == end_sector) {
+ printf(" in sector %d",start_sector);
+ }
+ else {
+ printf(" spanning sectors %d-%d",
+ start_sector,end_sector);
+ }
+ }
+#endif
+ putchar('\n');
+ sizetot += (fp->filsize + TFSHDRSIZ + DEFRAGHDRSIZ);
+ if (TFS_TIME(fp) != TIME_UNDEFINED)
+ printf(" Time: %s\n",
+ tfsGetAtime(TFS_TIME(fp),tbuf,sizeof(tbuf)));
+ printf("\n");
+ tot++;
+ fp = nextfp(fp,tdp);
+ if ((more) && ((tot % more) == 0)) {
+ if (!More())
+ return(TFS_OKAY);
+ }
+ }
+ /* If this or the next pointer is null, terminate loop now... */
+ if (!*fltrptr) break;
+ fltrptr++;
+ if (!*fltrptr) break;
+ }
+ }
+ printf("Total: %d accessible file%s (%d bytes).\n",
+ tot,tot == 1 ? "" : "s",sizetot);
+ return (TFS_OKAY);
+}
+
+/* tfsqlist(): quick list...
+ * Display list of files in alphabetical order.
+ * Display only the name and flag summary.
+ *
+ * To support listing of files in a bit of an orderly manner, if this
+ * function sees that a filename has a slash in it, it will only print the
+ * characters upto and including the first slash. This gives the appearance
+ * of a directory structure, even though there really isn't one.
+ * For example, if there are three files...
+ * CONFIG/file1
+ * CONFIG/file2
+ * CONFIG/file3
+ * then if no filter is specified, then that listing will be replaced with
+ * CONFIG/
+ * printed only once. To display all the files prefixed with CONFIG/, the
+ * user must type "tfs ls CONFIG/\*".
+ *
+ * Note: a file with a leading dot ('.') is invisible unless verbose is set.
+ */
+static int
+tfsqlist(char *filter[], int verbose, int more)
+{
+ TFILE *fp;
+ char dirname[TFSNAMESIZE+1], tmpname[TFSNAMESIZE+1];
+ char *name, fbuf[16], **fltrptr, *slash, *flags;
+ int idx, sidx, filelisted, err, sizetot;
+
+ if ((err = tfsreorder()) < 0)
+ return(err);
+
+ filelisted = 0;
+ sizetot = 0;
+ dirname[0] = 0;
+ fltrptr = filter;
+ printf(" Name Size Location Flags Info\n");
+ while(1) {
+ idx = 0;
+ while((fp = tfsAlist[idx])) {
+ name = TFS_NAME(fp);
+ if (((name[0] == '.') && (!verbose)) ||
+ (!listfilter(*fltrptr,name)) ||
+ ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl()))) {
+ idx++;
+ continue;
+ }
+
+ /* If name contains a slash, process it differently (but ignore */
+ /* any leading slashes) */
+ strcpy(tmpname,TFS_NAME(fp));
+ for(sidx=0;sidx<TFSNAMESIZE;sidx++) {
+ if (tmpname[sidx] != '/')
+ break;
+ }
+ slash = strchr(&tmpname[sidx],'/');
+ if (slash && !*fltrptr) {
+ char tmp;
+
+ tmp = *(slash+1);
+ *(slash+1) = 0;
+ if (strcmp(dirname,tmpname)) {
+ filelisted++;
+ printf(" %-34s (dir)\n",tmpname);
+ strcpy(dirname,tmpname);
+ *(slash+1) = tmp;
+ }
+ else {
+ idx++;
+ *(slash+1) = tmp;
+ continue;
+ }
+ }
+ else {
+ filelisted++;
+ sizetot += TFS_SIZE(fp);
+ flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf);
+ if ((!flags) || (!fbuf[0]))
+ flags = " ";
+ printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp),
+ TFS_SIZE(fp),(ulong)(TFS_BASE(fp)),flags,TFS_INFO(fp));
+ }
+ idx++;
+ if ((more) && !(filelisted % more)) {
+ if (!More())
+ return(TFS_OKAY);
+ }
+ }
+ /* If this or the next pointer is null, terminate loop now... */
+ if (!*fltrptr) break;
+ fltrptr++;
+ if (!*fltrptr) break;
+ }
+ printf("\nTotal: %d item%s listed (%d bytes).\n",filelisted,
+ filelisted == 1 ? "" : "s",sizetot);
+ return (TFS_OKAY);
+}
+
+/* tfsrm():
+ * Remove all files that pass the incoming filter.
+ * This replaces the older tfs rm stuff in Tfs().
+ */
+static int
+tfsrm(char *filter[])
+{
+ TFILE *fp;
+ char *name, **fltrptr;
+ int idx, err, rmtot;
+
+ if ((err = tfsreorder()) < 0)
+ return(err);
+
+ fltrptr = filter;
+ while (*fltrptr) {
+ idx = rmtot = 0;
+ while((fp = tfsAlist[idx])) {
+ name = TFS_NAME(fp);
+ if (listfilter(*fltrptr,name)) {
+ if ((err = tfsunlink(name)) != TFS_OKAY)
+ printf("%s: %s\n",name,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ rmtot++;
+ }
+ idx++;
+ }
+ /* This function will potentially delete many files, but if the */
+ /* filter doesn't match at least one file, indicate that... */
+ if (!rmtot)
+ printf("%s: file not found\n",*fltrptr);
+ fltrptr++;
+ }
+
+ return(TFS_OKAY);
+}
+
+/* tfscat():
+ * Print each character of the file until NULL terminate. Replace
+ * each instance of CR or LF with CRLF.
+ */
+static void
+tfscat(TFILE *fp, int more)
+{
+ int i, lcnt;
+ char *cp;
+
+ lcnt = 0;
+ cp = (char *) (TFS_BASE(fp));
+ for(i=0;i<fp->filsize;i++) {
+ if (*cp == 0x1a) /* EOF or ctrl-z */
+ break;
+ putchar(*cp);
+ if ((*cp == '\r') || (*cp == '\n')) {
+ lcnt++;
+ if (lcnt == more) {
+ if (More() == 0)
+ break;
+ lcnt = 0;
+ }
+ }
+ cp++;
+ }
+}
+
+int
+dumpFhdr(TFILE *fhp)
+{
+ int crcok;
+
+ if (tfshdrcrc(fhp) == fhp->hdrcrc)
+ crcok = 1;
+ else
+ crcok = 0;
+ printf("hdrsize: 0x%04x (%s)\n",fhp->hdrsize,
+ fhp->hdrsize == TFSHDRSIZ ? "ok" : "bad");
+ printf("hdrvrsn: 0x%04x\n",fhp->hdrvrsn);
+ printf("filsize: 0x%08lx\n",fhp->filsize);
+ printf("flags : 0x%08lx\n",fhp->flags);
+#if 0
+ printf("filcrc : 0x%08lx (%s)\n",fhp->filcrc,
+ crc32((uchar *)(fhp+1),fhp->filsize) == fhp->filcrc ? "ok" : "bad");
+#else
+ printf("filcrc : 0x%08lx\n",fhp->filcrc);
+#endif
+ printf("hdrcrc : 0x%08lx (%s)\n",fhp->hdrcrc,crcok ? "ok" : "bad");
+ printf("modtime: 0x%08lx\n",fhp->modtime);
+ printf("next : 0x%08lx\n",(ulong)fhp->next);
+ if (crcok) {
+ printf("name : %s\n",fhp->name);
+ printf("info : %s\n",fhp->info ? fhp->info : "");
+ }
+ else {
+ printf("name at: 0x%08lx\n",(ulong)fhp->name);
+ printf("info at: 0x%08lx\n",(ulong)fhp->info);
+ }
+ printf("data at: 0x%08lx\n",(ulong)(fhp+1));
+ return(TFS_OKAY);
+}
+
+char *TfsHelp[] = {
+ "Tiny File System Interface",
+ "-[df:i:mv] operation [args]...",
+#if INCLUDE_VERBOSEHELP
+ "",
+ "Options:",
+ " -d tfs device",
+ " -f flags (see below)",
+ " -i info",
+ " -m enable more throttle",
+ " -v enable verbosity",
+ "",
+ "Operations (alphabetically):",
+ " add {name} {src_addr} {size}, base {file} {var}, cat {name}",
+ " cfg {start | restore} [{end} [spare_addr]], check [var], clean",
+ " cp {from} {to_name | addr}, fhdr {addr}, freemem [var]",
+ " info {file} {var}, init, ld[v] {name} [sname]",
+ " log {on|off} {msg}, ln {src} {lnk}, ls [filter]",
+ " qclean [ramstart] [ramlen], ramdev {name} {base} {size}",
+ " rm {filter}, run {name}, size {file} {var}, stat",
+ " trace [lvl], uname {prefix} {var}",
+#if DEFRAG_TEST_ENABLED
+ "",
+ "Operations for testing TFS defragmentation:",
+ " clean {E|S|F} {tag#} {sector#}",
+ " E=Exit, S=SectorErase F=FlashWrite",
+ " rms {size} [exclude_file1] [exclude_file2] ...",
+ " dhdr {address}",
+ " dht",
+#endif
+ "",
+ "Flags:",
+ " E=exec_"
+#if TFS_EBIN_AOUT
+ "aout"
+#elif TFS_EBIN_COFF
+ "coff"
+#elif TFS_EBIN_ELF
+ "elf"
+#elif TFS_EBIN_MSBIN
+ "msbin"
+#elif TFS_EBIN_ELFMSBIN
+ "elf|msbin"
+#else
+#error: No TFS EBIN format specified.
+#endif
+ ", e=exec_script, c=compressed, l=symlink",
+ " b=run_at_boot, B=qry_run_at_boot, i=inplace_modifiable",
+ " 0-3=usrlvl_0-3, u=ulvl_unreadable",
+#endif
+ 0,
+};
+
+/* Tfs():
+ * Entry point for the tfs command through the monitor's command line
+ * interface. This function provides access to most TFS functionality
+ * through the CLI.
+ */
+
+int
+Tfs(int argc, char *argv[])
+{
+ TDEV *tdp, *tdptmp;
+ TFILE *fp;
+ TINFO tinfo;
+ long size;
+ int err, opt, verbose, i, more, retval, status;
+ char *src, *name, *info, *flags, *to, *from, *devprefix;
+ char *arg1, *arg2, *arg3, *arg4;
+
+ tdp = 0;
+ more = 0;
+ retval = CMD_SUCCESS;
+ verbose = 0;
+ status = TFS_OKAY;
+ info = (char *)0;
+ flags = (char *)0;
+ devprefix = (char *)0;
+ while ((opt = getopt(argc, argv, "d:vmf:i:")) != -1) {
+ switch (opt) {
+ case 'd':
+ devprefix = optarg;
+ tdp = gettfsdev_fromprefix(devprefix,1);
+ if (!tdp)
+ return(CMD_FAILURE);
+ break;
+ case 'f':
+ flags = optarg;
+ break;
+ case 'i':
+ info = optarg;
+ break;
+ case 'm':
+ more++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ arg1 = argv[optind];
+ arg2 = argv[optind+1];
+ arg3 = argv[optind+2];
+ arg4 = argv[optind+3];
+
+ if (argc == optind) {
+ retval = CMD_PARAM_ERROR;
+ }
+ else if (strcmp(arg1, "trace") == 0) {
+ if (argc == (optind+2))
+ tfsTrace = strtoul(arg2,0,0);
+ else if (argc == (optind+1))
+ printf("Current trace mode: 0x%lx\n",tfsTrace);
+ else
+ retval = CMD_PARAM_ERROR;
+ }
+ else if (strcmp(arg1, "init") == 0) {
+ if (getUsrLvl() < MAXUSRLEVEL) {
+ status = showTfsError(TFSERR_USERDENIED,0);
+ }
+ else {
+ status = _tfsinit(tdp);
+ showTfsError(status,"init");
+ if (status == TFS_OKAY)
+ tfsclear(tdp);
+ }
+ }
+ else if ((strcmp(arg1,"ramdev") == 0) && (argc == (optind+4))) {
+ err = tfsramdevice(arg2,strtol(arg3,0,0),strtol(arg4,0,0));
+ if (err != TFS_OKAY) {
+ printf("%s: %s\n",arg2,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ retval = CMD_FAILURE;
+ }
+ }
+ else if (strcmp(arg1, "log") == 0) {
+ retval = tfsLogCmd(argc,argv,optind);
+ }
+ else if (strcmp(arg1, "cfg") == 0) {
+ /* args:
+ * tfsstart tfsend spare_address
+ */
+ ulong start, end, spare;
+
+ if ((argc == (optind+2)) && !strcmp(arg2,"restore")) {
+ status = tfscfgrestore();
+ showTfsError(status,"cfg");
+ }
+ else if ((argc == (optind+3)) || (argc == (optind+4))) {
+ start = strtol(arg2,0,0);
+ end = strtol(arg3,0,0);
+ if (argc == (optind+4))
+ spare = strtol(arg4,0,0);
+ else
+ spare = 0xffffffff;
+ status = tfscfg(devprefix,start,end,spare);
+ showTfsError(status,"cfg");
+ }
+ else {
+ retval = CMD_PARAM_ERROR;
+ }
+ }
+ else if (strcmp(arg1, "stat") == 0) {
+ char buf[32];
+ int opencnt;
+ struct tfsdat *slot;
+
+ /* Display current TFS memory usage: */
+ tfsmemuse(tdp,&tinfo,1);
+ printf("TFS Hdr size: %d\n",TFSHDRSIZ);
+
+ /* Display currently opened files: */
+ opencnt = 0;
+ slot = tfsSlots;
+ for (i=0;i<TFS_MAXOPEN;i++,slot++) {
+ if (slot->offset >= 0) {
+ printf("%3d: 0x%08lx %s %s\n",i,(ulong)(slot->base),
+ tfsmodebtoa(slot->flagmode,buf),slot->hdr.name);
+ opencnt++;
+ }
+ }
+ printf("Total files currently opened: %d\n",opencnt);
+ }
+ else if (strcmp(arg1, "freemem") == 0) {
+ char *prefix;
+
+ tfsmemuse(tdp,&tinfo,0);
+ if (tdp)
+ prefix = tdp->prefix;
+ else
+ prefix = "";
+ if (argc == (optind+1)) {
+ printf("0x%x (%d) bytes available to TFS %s\n",
+ tinfo.memfordata,tinfo.memfordata,prefix);
+ }
+ else if (argc == (optind+2)) {
+ shell_sprintf(arg2,"0x%x",tinfo.memfordata);
+ }
+ else
+ retval = CMD_PARAM_ERROR;
+ }
+#if DEFRAG_TEST_ENABLED
+ else if (strcmp(arg1, "dht") == 0) {
+ if (argc == (optind+1)) {
+ status = dumpDhdrTbl(0,0);
+ showTfsError(status,"dht");
+ }
+ else if (argc == (optind+3)) {
+ status = dumpDhdrTbl((DEFRAGHDR *)strtol(arg2,0,0),
+ atoi(arg3));
+ showTfsError(status,"dht");
+ }
+ else
+ retval = CMD_PARAM_ERROR;
+ }
+ else if ((strcmp(arg1, "dhdr") == 0) && (argc == (optind+2))) {
+ status = dumpDhdr((DEFRAGHDR *)strtol(arg2,0,0));
+ showTfsError(status,"dhdr");
+ }
+#endif
+ else if ((strcmp(arg1, "fhdr") == 0) && (argc == (optind+2))) {
+ status = dumpFhdr((TFILE *)strtol(arg2,0,0));
+ showTfsError(status,"fhdr");
+ }
+ else if (((strcmp(arg1, "base") == 0) ||
+ (strcmp(arg1, "info") == 0) ||
+ (strcmp(arg1, "size") == 0)) && (argc == (optind+3))) {
+ fp = tfsstat(arg2);
+ if ((!fp) ||
+ ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl())))
+ setenv(arg3,0);
+ else {
+ switch(arg1[0]) {
+ case 'b':
+ shell_sprintf(arg3,"0x%x",(char *)fp+TFSHDRSIZ);
+ break;
+ case 'i':
+ setenv(arg3,fp->info);
+ break;
+ case 's':
+ shell_sprintf(arg3,"%ld",fp->filsize);
+ break;
+ }
+ }
+ }
+ else if ((strcmp(arg1, "uname") == 0) && (argc == (optind+3))) {
+ char uname[TFSNAMESIZE];
+ for(i=0;;i++) {
+ sprintf(uname,"%s%d",arg2,i);
+ if (!tfsstat(uname)) {
+ setenv(arg3,uname);
+ break;
+ }
+ }
+ }
+ else if (strcmp(arg1, "ls") == 0) {
+ if (verbose > 1)
+ status = tfsvlist(&argv[optind+1],verbose,more << 1);
+ else
+ status = tfsqlist(&argv[optind+1],verbose,more << 3);
+
+ showTfsError(status,"ls");
+ }
+ else if ((strcmp(arg1, "ln") == 0) && (argc == optind+3)) {
+ from = arg2;
+ to = arg3;
+ status = tfslink(from,to);
+ showTfsError(status,from);
+ }
+ else if ((strcmp(arg1, "cp") == 0) && (argc == (optind+3))) {
+ char buf[16], linfo[TFSINFOSIZE];
+
+ from = arg2;
+ to = arg3;
+ fp = tfsstat(from);
+ if (fp) {
+ if (flags) {
+ if (strcmp(flags,"0") == 0)
+ flags = (char *)0;
+ }
+ else {
+ flags = tfsflagsbtoa(fp->flags,buf);
+ }
+ if (!info)
+ strcpy(linfo,fp->info);
+ else
+ strcpy(linfo,info);
+ if ((fp->flags & TFS_UNREAD) &&
+ (TFS_USRLVL(fp) > getUsrLvl())) {
+ status = showTfsError(TFSERR_USERDENIED,from);
+ }
+ else if (to[0] == '0' && to[1] == 'x') {
+ memcpy((char *)strtol(to,0,16),TFS_BASE(fp),TFS_SIZE(fp));
+ flushDcache((char *)strtol(to,0,16), TFS_SIZE(fp));
+ invalidateIcache((char *)strtol(to,0,16), TFS_SIZE(fp));
+ }
+ else {
+ int freespace;
+
+ /* First check to see if a defrag is needed...
+ */
+ freespace = tfsctrl(TFS_MEMAVAIL,0,0);
+ if (freespace <= TFS_SIZE(fp)) {
+ tfsctrl(TFS_DEFRAG,0,0);
+ fp = tfsstat(from);
+ }
+ status = tfsadd(to,linfo,flags,(uchar *)TFS_BASE(fp),
+ TFS_SIZE(fp));
+ showTfsError(status,to);
+ }
+ }
+ else
+ status = showTfsError(TFSERR_NOFILE,from);
+ }
+ else if ((strcmp(arg1, "cat") == 0) && (argc >= (optind+2))) {
+ for(i=optind+1;i<argc;i++) {
+ name = argv[i];
+ fp = tfsstat(name);
+ if (fp) {
+ if ((fp->flags & TFS_UNREAD) &&
+ (TFS_USRLVL(fp) > getUsrLvl())) {
+ status = showTfsError(TFSERR_USERDENIED,name);
+ }
+ else {
+ tfscat(fp,more << 3); /* more times 8 */
+ }
+ }
+ else
+ status = showTfsError(TFSERR_NOFILE,name);
+ }
+ }
+#if DEFRAG_TEST_ENABLED
+ /* rms: "remove space". Used for testing only... Keep removing files
+ * until the number of bytes freed up is greater than the argument
+ * to rms. Skip over all files listed after the first size argument.
+ * Arglist to tfs rms is...
+ *
+ * tfs rms {SIZE} [EXCLUDEFILE1] [EXCLUDEFILE2] ...
+ * where SIZE is the amount of space to freeup and EXCLUDEFILEN is
+ * a filename that is not to be removed.
+ */
+ else if ((strcmp(arg1, "rms") == 0) && (argc >= (optind+2))) {
+ int insize, totsize;
+
+ totsize = 0;
+ insize = strtol(arg2,0,0);
+ tfsreorder();
+ for(i=0;tfsAlist[i];i++) {
+ int j;
+
+ for(j=optind+1;j<argc;j++) {
+ if (!strcmp(TFS_NAME(tfsAlist[i]),argv[j]))
+ break;
+ }
+ if (j != argc) {
+ continue;
+ }
+ if (devprefix &&
+ strncmp(TFS_NAME(tfsAlist[i]),devprefix,strlen(devprefix)))
+ continue;
+ totsize += (TFS_SIZE(tfsAlist[i]) + TFSHDRSIZ);
+ if (verbose)
+ printf("rms: removing %s (%ld)\n",TFS_NAME(tfsAlist[i]),
+ TFS_SIZE(tfsAlist[i]) + TFSHDRSIZ);
+ _tfsunlink(TFS_NAME(tfsAlist[i]));
+ if (totsize > insize)
+ break;
+ totsize += TFSHDRSIZ;
+ }
+ }
+#endif
+ else if ((strcmp(arg1, "rm") == 0) && (argc >= (optind+2))) {
+ status = tfsrm(&argv[optind+1]);
+ showTfsError(status,0);
+ }
+ else if (strcmp(arg1, "fix") == 0) {
+ tfsfixup(verbose,1);
+ }
+ else if (strcmp(arg1, "qclean") == 0) {
+ char *ramstart = 0;
+ ulong ramlen = 0;
+
+ if (argc >= optind+2)
+ ramstart = (char *)strtoul(arg2,0,0);
+ if (argc >= optind+3)
+ ramlen = strtoul(arg2,0,0);
+
+ for (tdptmp=tfsDeviceTbl;tdptmp->start != TFSEOT;tdptmp++) {
+ if (!tdp || (tdp == tdptmp)) {
+ status = tfsclean_nps(tdptmp,ramstart,ramlen);
+ showTfsError(status,tdptmp->prefix);
+ }
+ }
+ }
+ else if (strcmp(arg1, "clean") == 0) {
+ int otrace;
+
+#if DEFRAG_TEST_ENABLED
+ DefragTestPoint = DefragTestSector = DefragTestType = 0;
+ if (argc == (optind+4)) {
+ if (arg2[0] == 'S')
+ DefragTestType = DEFRAG_TEST_SERASE;
+ else if (arg2[0] == 'F')
+ DefragTestType = DEFRAG_TEST_FWRITE;
+ else if (arg2[0] == 'E')
+ DefragTestType = DEFRAG_TEST_EXIT;
+ else
+ return(CMD_PARAM_ERROR);
+ DefragTestPoint = atoi(arg3);
+ DefragTestSector = atoi(arg4);
+ printf("Testtype=%c, Testpoint=%d, Testsector=%d\n",
+ arg2[0],DefragTestPoint,DefragTestSector);
+ }
+ else
+#endif
+ if (argc != optind+1)
+ return(CMD_PARAM_ERROR);
+
+ /* If verbosity request is extreme, then turn on TFS trace also...
+ */
+ otrace = tfsTrace;
+ if (verbose >= 5)
+ tfsTrace = 99;
+
+ /* If tdp has been set by the -d option, only defrag the affected
+ * device; else, defrag all devices...
+ */
+ for (tdptmp=tfsDeviceTbl;tdptmp->start != TFSEOT;tdptmp++) {
+ if (!tdp || (tdp == tdptmp)) {
+ status = tfsclean(tdptmp,verbose+1);
+ showTfsError(status,tdptmp->prefix);
+ }
+ }
+ tfsTrace = otrace;
+ }
+ else if (strcmp(arg1, "check") == 0) {
+ if (argc == optind+1)
+ verbose = 1;
+
+ if (tfscheck(tdp,verbose) != TFS_OKAY)
+ status = TFSERR_CORRUPT;
+
+ /* If an additional argument is provided after the "check" command
+ * then assume it is a shell variable name that is to be populated
+ * with the pass/fail status of the check...
+ */
+ if (argc == optind+2)
+ setenv(arg2,status == TFS_OKAY ? "PASS" : "FAIL");
+ }
+ else if ((!strncmp(arg1, "ld",2)) &&
+ ((argc == optind+2) || (argc == optind+3))) {
+ int vfy = 0;
+
+ if (arg1[2] == 'v')
+ vfy = 1;
+ else if (arg1[2] != 0)
+ return(CMD_PARAM_ERROR);
+ status = tfsld(arg2,verbose,arg3,vfy);
+ showTfsError(status,arg2);
+ }
+ else if ((strcmp(arg1, "run") == 0) && (argc >= (optind+2))) {
+ status = tfsrun(&argv[optind+1],verbose);
+ showTfsError(status,arg2);
+ }
+ else if ((!(strcmp(arg1, "add"))) && (argc == (optind+4))) {
+ src = (char *) strtol(arg3, (char **) 0, 0);
+ size = strtol(arg4, (char **) 0, 0);
+ status = tfsadd(arg2, info, flags, (uchar *)src, size);
+ showTfsError(status,arg2);
+ if (status != TFS_OKAY)
+ retval = CMD_FAILURE;
+ }
+ else {
+ retval = CMD_PARAM_ERROR;
+ }
+ return(retval);
+}
+#endif
diff --git a/main/common/tfsloader.c b/main/common/tfsloader.c
new file mode 100644
index 0000000..1b3d8ac
--- /dev/null
+++ b/main/common/tfsloader.c
@@ -0,0 +1,523 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsloader.c:
+ *
+ * This file contains the code that is specific to each of the file types
+ * supported by TFS as the binary executable type.
+ * Currently, COFF, ELF, A.OUT and MSBIN are supported. This requires that
+ * TFS_EBIN_COFF, TFS_EBIN_ELF, TFS_EBIN_AOUT or TFS_EBIN_MSBIN
+ * respectively, be set in the monitor's config.h file. Also, defining
+ * TFS_EBIN_ELFMSBIN will allow TFS to support both ELF and MSBIN.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "coff.h"
+#include "elf.h"
+#include "aout.h"
+#include "msbin.h"
+#if INCLUDE_TFS
+
+
+/* tfsld_memcpy(), tfsld_memset() & tfsld_decompress():
+ * Front end to all bulk memory modification calls done by the
+ * loader. Each function just does a quick check to make sure that
+ * the address ranged being copied to is not part of the monitor's
+ * own .bss space...
+ * Then after the memory transfer, caches are flushed/invalidated.
+ *
+ * How we return here depends on the verbosity level. If verbosity
+ * is greater than 1, then assume that this pass through tfsld_memcpy()
+ * is to dump out map information, not to actually do a memcpy().
+ * This same logic is used within the s_memcpy() routine and must remain
+ * consistent to work properly.
+ */
+#ifdef USE_ALTERNATE_TFSLD_MEMCPY
+extern int tfsld_memcpy(char *to,char *from,int count,int verbose,int verify);
+#else
+int
+tfsld_memcpy(char *to, char *from, int count, int verbose, int verify)
+{
+ int rc;
+
+ if (verbose <= 1) {
+ if (inUmonBssSpace(to,to+count-1))
+ return(-1);
+ }
+
+ rc = s_memcpy(to,from,count,verbose,verify);
+
+ if (verbose <= 1) {
+ flushDcache(to,count);
+ invalidateIcache(to,count);
+ }
+
+ return(rc);
+}
+#endif
+
+int
+tfsld_memset(uchar *to,uchar val,int count,int verbose,int verifyonly)
+{
+ int rc;
+
+ if (verbose <= 1) {
+ if (inUmonBssSpace((char *)to, (char *)to+count-1))
+ return(-1);
+ }
+
+ rc = s_memset(to,val,count,verbose,verifyonly);
+
+ if (verbose <= 1) {
+ flushDcache((char *)to, count);
+ invalidateIcache((char *)to, count);
+ }
+
+ return(rc);
+}
+
+void
+showEntrypoint(unsigned long entrypoint)
+{
+ printf(" entrypoint: 0x%lx\n",entrypoint);
+}
+
+void
+showSection(char *sname)
+{
+ printf(" %-10s: ",sname);
+}
+
+#if TFS_EBIN_AOUT
+
+/* tfsloadaout():
+ * The file pointed to by fp is assumed to be an AOUT
+ * formatted file. This function loads the sections of that file into
+ * the designated locations and returns the address of the entry point.
+ */
+int
+tfsloadaout(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly)
+{
+ uchar *tfrom, *dfrom;
+ struct exec *ehdr;
+
+ if (tfsTrace)
+ printf("tfsloadaout(%s)\n",TFS_NAME(fp));
+
+ /* Establish file header pointer... */
+ ehdr = (struct exec *)(tfsBase(fp));
+
+ /* Return error if relocatable... */
+ if ((ehdr->a_trsize) || (ehdr->a_drsize))
+ return(TFSERR_BADHDR);
+
+ /* Establish locations from which text and data are to be */
+ /* copied from ... */
+ tfrom = (uchar *)(ehdr+1);
+ dfrom = tfrom+ehdr->a_text;
+
+ /* Copy/verify text and data sections to RAM: */
+ if (verbose)
+ showSection("text");
+
+ if (tfsld_memcpy((char *)(ehdr->a_entry),(char *)tfrom,
+ ehdr->a_text,verbose,verifyonly) != 0)
+ return(TFSERR_MEMFAIL);
+
+ if (verbose)
+ showSection("data");
+
+ if (tfsld_memcpy((char *)(ehdr->a_entry+ehdr->a_text),(char *)dfrom,
+ ehdr->a_data,verbose,verifyonly) != 0)
+ return(TFSERR_MEMFAIL);
+
+ /* Clear out bss space: */
+ if (verbose)
+ showSection("bss");
+
+ if (tfsld_memset((char *)(ehdr->a_entry+ehdr->a_text+ehdr->a_data),
+ 0,ehdr->a_bss,verbose,verifyonly) != 0)
+ return(TFSERR_MEMFAIL);
+
+
+ if (verbose & !verifyonly)
+ showEntrypoint(ehdr->a_entry);
+
+ /* Store entry point: */
+ if (entrypoint)
+ *entrypoint = (long)(ehdr->a_entry);
+
+ return(TFS_OKAY);
+}
+#endif
+
+#if TFS_EBIN_COFF
+
+/* tfsloadcoff():
+ * The file pointed to by fp is assumed to be a COFF file.
+ * This function loads the sections of that file into the designated
+ * locations.
+ */
+int
+tfsloadcoff(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly)
+{
+ int i, err;
+ FILHDR *fhdr;
+ AOUTHDR *ahdr;
+ SCNHDR *shdr;
+
+ if (tfsTrace)
+ printf("tfsloadcoff(%s)\n",TFS_NAME(fp));
+
+ /* Establish file header pointers... */
+ fhdr = (FILHDR *)(tfsBase(fp));
+ if ((fhdr->f_opthdr == 0) || ((fhdr->f_flags & F_EXEC) == 0))
+ return(TFSERR_BADHDR);
+
+ err = 0;
+ ahdr = (AOUTHDR *)(fhdr+1);
+ shdr = (SCNHDR *)((uchar *)ahdr + fhdr->f_opthdr);
+
+ /* For each section header, relocate or clear if necessary... */
+ for (i=0;!err && i<fhdr->f_nscns;i++) {
+ if (shdr->s_size == 0) {
+ shdr++;
+ continue;
+ }
+
+ /* If incoming section name is specified, then we only load the
+ * section with that name...
+ */
+ if ((sname != 0) && (strcmp(sname,shdr->s_name) != 0))
+ continue;
+
+ if (verbose)
+ showSection(shdr->s_name);
+
+ if (ISLOADABLE(shdr->s_flags)) {
+ if (tfsld_memcpy((char *)(shdr->s_paddr),
+ (char *)(shdr->s_scnptr+(int)fhdr),
+ shdr->s_size,verbose,verifyonly) != 0)
+ err++;
+ }
+ else if (ISBSS(shdr->s_flags)) {
+ if (tfsld_memset((char *)(shdr->s_paddr),0,shdr->s_size,
+ verbose,verifyonly) != 0)
+ err++;
+ }
+ else if (verbose)
+ printf("???\n");
+ shdr++;
+ }
+
+ if (verbose && !verifyonly && !sname)
+ showEntrypoint(ahdr->entry);
+
+ if (err)
+ return(TFSERR_MEMFAIL);
+
+ /* Store entry point: */
+ if (entrypoint)
+ *entrypoint = (long)(ahdr->entry);
+
+ return(TFS_OKAY);
+}
+#endif
+
+#if TFS_EBIN_ELF | TFS_EBIN_ELFMSBIN
+
+/* tfsloadelf():
+ * The file pointed to by fp is assumed to be an ELF file.
+ * This function loads the sections of that file into the designated
+ * locations.
+ */
+int
+tfsloadelf(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly)
+{
+ Elf32_Word size, notproctot;
+ int i, j, err;
+ char *shname_strings, *name;
+ Elf32_Addr sh_addr;
+ ELFFHDR *ehdr;
+ ELFSHDR *shdr;
+ ELFPHDR *phdr;
+
+ if (tfsTrace)
+ printf("tfsloadelf(%s)\n",TFS_NAME(fp));
+
+ /* Establish file header pointers... */
+ /* If the first reserved entry isn't 0xffffffff, then assume this is a
+ * 'fake' header, and it contains the base address of the file data...
+ * See tfsld() for more info.
+ */
+ ehdr = (ELFFHDR *)(tfsBase(fp));
+ shdr = (ELFSHDR *)((int)ehdr + ehdr->e_shoff);
+ err = 0;
+
+ /* Verify basic file sanity... */
+ if ((ehdr->e_ident[0] != 0x7f) || (ehdr->e_ident[1] != 'E') ||
+ (ehdr->e_ident[2] != 'L') || (ehdr->e_ident[3] != 'F'))
+ return(TFSERR_BADHDR);
+
+ /* Store the section name string table base: */
+ shname_strings = (char *)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
+ notproctot = 0;
+
+ /* For each section header, relocate or clear if necessary... */
+ for (i=0;!err && i<ehdr->e_shnum;i++,shdr++) {
+ if ((size = shdr->sh_size) == 0)
+ continue;
+
+ name = shname_strings + shdr->sh_name;
+
+ /* If incoming section name is specified, then we only load the
+ * section with that name...
+ */
+ if ((sname != 0) && (strcmp(sname,name) != 0))
+ continue;
+
+ if ((verbose) && (ehdr->e_shstrndx != SHN_UNDEF))
+ showSection(shname_strings + shdr->sh_name);
+
+ if (!(shdr->sh_flags & SHF_ALLOC)) {
+ notproctot += size;
+ if (verbose)
+ printf(" %7ld bytes not processed (tot=%ld)\n",
+ size,notproctot);
+ continue;
+ }
+
+ sh_addr = shdr->sh_addr;
+
+ /* Look to the program header to see if the destination address
+ * of this section needs to be adjusted. If this section is
+ * within a program header and that program header's members
+ * p_vaddr & p_paddr are not equal, then adjust the section
+ * address based on the delta between p_vaddr and p_paddr...
+ */
+ phdr = (ELFPHDR *)((int)ehdr + ehdr->e_phoff);
+ for (j=0;j<ehdr->e_phnum;j++,phdr++) {
+ if ((phdr->p_type == PT_LOAD) &&
+ (sh_addr >= phdr->p_vaddr) &&
+ (sh_addr < phdr->p_vaddr+phdr->p_filesz) &&
+ (phdr->p_vaddr != phdr->p_paddr)) {
+ sh_addr += (phdr->p_paddr - phdr->p_vaddr);
+ break;
+ }
+ }
+
+ if (shdr->sh_type == SHT_NOBITS) {
+ if (tfsld_memset((uchar *)(sh_addr),0,size,
+ verbose,verifyonly) != 0)
+ err++;
+ }
+ else {
+ if (tfsld_memcpy((char *)(sh_addr),
+ (char *)((int)ehdr+shdr->sh_offset),
+ size,verbose,verifyonly) != 0)
+ err++;
+ }
+ }
+
+ if (err)
+ return(TFSERR_MEMFAIL);
+
+ if (verbose && !verifyonly && !sname)
+ showEntrypoint(ehdr->e_entry);
+
+ /* Store entry point: */
+ if (entrypoint)
+ *entrypoint = (long)(ehdr->e_entry);
+
+ return(TFS_OKAY);
+}
+
+#endif
+
+#if TFS_EBIN_ELFMSBIN | TFS_EBIN_MSBIN
+
+/* tfsloadmsbin():
+ * This loader is a bit different than the others.
+ * The model for AOUT, COFF & ELF is simply to load each section from
+ * the stored location in flash to the location specifed by the section
+ * header. The sections may be compressed.
+ * The MSBIN loader supports a few additional options because of the
+ * fact that WinCE files can be formatted as .bin or .nbo. When
+ * the file is the ".bin" type, then this loader is used similar to
+ * the AOUT, COFF & ELF loaders. When the file is the ".nbo" type,
+ * then it is simply loaded into the starting address of the target's
+ * DRAM and the entrypoint is that base address.
+ * To support this scheme, TFS uses both the 'c' flag (compressed)
+ * and the extension on the filename as follows...
+ *
+ * 1 filename.bin with 'c' flag inactive:
+ * Load the file as specified by the sections within the file
+ * header.
+ * 2 filename.bin with 'c' flag active:
+ * Load the file as specified by the sections within the file
+ * header and assume each section is compressed.
+ * 3 filename.nbo with 'c' flag inactive:
+ * Copy the entire content of the file from TFS flash space to
+ * APPRAMBASE and return the address APPRAMBASE as the entrypoint.
+ * 4 filename.nbo with 'c' flag active:
+ * Decompress the entire content of the file from TFS flash space
+ * to APPRAMBASE and return the address APPRAMBASE as the entrypoint.
+ *
+ * In three of the 4 cases above (1,2&3) some level of sanity checking
+ * can be done on the file prior to beginning the load. For the 4th
+ * case there is no sanity check, this function assumes the file is
+ * compressed and is destined for the base of DRAM.
+ */
+int
+tfsloadmsbin(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly)
+{
+ ulong offset;
+ MSBINFHDR filhdr;
+ MSBINSHDR scnhdr;
+ char *dot;
+ int err, snum;
+
+ if (tfsTrace)
+ printf("tfsloadmsbin(%s)\n",TFS_NAME(fp));
+
+ dot = strrchr(TFS_NAME(fp),'.');
+ if (!dot)
+ return(TFSERR_BADEXTENSION);
+
+ /* Check the filename extension for ".bin" or ".nbo" and process
+ * accordingly...
+ */
+ if (strcmp(dot,".bin") == 0) {
+ /* Verify basic file sanity... */
+ if (memcmp((char *)tfsBase(fp),MSBIN_SYNC_DATA,MSBIN_SYNC_SIZE) != 0)
+ return(TFSERR_BADHDR);
+
+ /* The file header is at offset MSBIN_SYNC_SIZE in the
+ * file, so copy it from the file to a local structure...
+ */
+ memcpy((char *)&filhdr,(tfsBase(fp) + MSBIN_SYNC_SIZE),
+ sizeof(MSBINFHDR));
+
+ /* Start by clearing the entire image space to zero...
+ */
+ if (verbose)
+ printf("MsbinImage: ");
+
+ tfsld_memset((uchar *)filhdr.imageaddr,0,(int)filhdr.imagelen,verbose,
+ verifyonly);
+
+ err = snum = 0;
+ offset = (ulong)(tfsBase(fp) + MSBIN_SYNC_SIZE + sizeof(MSBINFHDR));
+
+ /* Walk through all sections within the file. For each section,
+ * copy the structure out of TFS to local space, then process it.
+ */
+ for(snum = 1;err==0;snum++) {
+ memcpy((char *)&scnhdr,(char *)offset,sizeof(MSBINSHDR));
+ offset += sizeof(MSBINSHDR);
+
+ /* The image terminates with an image record header with the
+ * physical address and checksum set to zero...
+ */
+ if ((scnhdr.addr == 0) && (scnhdr.csum == 0))
+ break;
+
+ if (verbose)
+ printf("section %02d: ", snum);
+
+ if (tfsld_memcpy((char *)(scnhdr.addr),
+ (char *)offset,scnhdr.len,verbose,verifyonly) != 0)
+ err++;
+
+ offset += scnhdr.len;
+ }
+
+ if (err)
+ return(TFSERR_MEMFAIL);
+
+ if (verbose && !verifyonly && !sname)
+ showEntrypoint(filhdr.imageaddr);
+
+ /* Store entry point: */
+ if (entrypoint)
+ *entrypoint = (long)(filhdr.imageaddr);
+ }
+ else if (strcmp(dot,".nb0") == 0) {
+ char *drambase;
+
+ drambase = (char *)getAppRamStart();
+
+ tfsld_memcpy(drambase,(char *)tfsBase(fp),(int)TFS_SIZE(fp),
+ verbose,verifyonly);
+
+ /* Store entry point: */
+ if (entrypoint)
+ *entrypoint = (long)(drambase);
+ }
+ else {
+ return(TFSERR_BADEXTENSION);
+ }
+
+ return(TFS_OKAY);
+}
+
+#endif
+
+int
+tfsloadebin(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly)
+{
+#if TFS_EBIN_ELFMSBIN
+ int err;
+#endif
+
+ /* If verbosity is greater than one and verifyonly is not set, then
+ * we are simply dumping a map, so start with an appropriate
+ * header...
+ */
+ if ((verbose > 1) && (verifyonly == 0))
+ printf("Load map:\n");
+
+#if TFS_EBIN_AOUT
+ return(tfsloadaout(fp,verbose,entrypoint,sname,verifyonly));
+#elif TFS_EBIN_COFF
+ return(tfsloadcoff(fp,verbose,entrypoint,sname,verifyonly));
+#elif TFS_EBIN_ELF
+ return(tfsloadelf(fp,verbose,entrypoint,sname,verifyonly));
+#elif TFS_EBIN_MSBIN
+ return(tfsloadmsbin(fp,verbose,entrypoint,sname,verifyonly));
+#elif TFS_EBIN_ELFMSBIN
+ err = tfsloadelf(fp,verbose,entrypoint,sname,verifyonly);
+ if (err == TFSERR_BADHDR)
+ return(tfsloadmsbin(fp,verbose,entrypoint,sname,verifyonly));
+ else
+ return(err);
+#else
+#error Invalid TFS_EBIN type.
+#endif
+}
+
+
+#endif /* INCLUDE_TFS */
diff --git a/main/common/tfslog.c b/main/common/tfslog.c
new file mode 100644
index 0000000..a31b8fa
--- /dev/null
+++ b/main/common/tfslog.c
@@ -0,0 +1,171 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfslog.c:
+ *
+ * Optional facility for TFS that supports the ability to log all
+ * tfs actions that affect flash, to a log file.
+ *
+ * This function is called by tfsadd(), tfsunlink() and tfsipmod() to
+ * write to a log file indicating that something in tfs has been changed.
+ * Note that the function can be called at any user level, but it must be
+ * able to modify the TFS_CHANGELOG_FILE that has "u3" flags. The
+ * user level must be temporarily forced to MAXUSRLEVEL for this.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+
+#if TFS_CHANGELOG_SIZE
+static int tfsLogging;
+#endif
+
+void
+tfslog(int action, char *string)
+{
+#if TFS_CHANGELOG_SIZE
+ static char *tfslogaction[] = { "ADD", "DEL", "IPM", " ON", "OFF" };
+
+ extern void *setTmpMaxUsrLvl();
+ static char buf[TFS_CHANGELOG_SIZE];
+ TFILE *tfp;
+ int (*fptr)();
+ char *eol, *eob, *logaction, tbuf[32];
+ int newfsize, fsize, lsize, tfd, err, len, tbuflen;
+
+ switch(action) {
+ case TFSLOG_ADD: /* Return here if logging is off, */
+ case TFSLOG_DEL: /* or this tfslog() call is on the */
+ case TFSLOG_IPM: /* TFS_CHANGELOG_FILE itself. */
+ if (!tfsLogging || !strcmp(string,TFS_CHANGELOG_FILE))
+ return;
+ break;
+ case TFSLOG_ON:
+ if (tfsLogging == 1)
+ return;
+ tfsLogging = 1;
+ break;
+ case TFSLOG_OFF:
+ if (tfsLogging == 0)
+ return;
+ tfsLogging = 0;
+ break;
+ }
+
+ /* Force the getUsrLvl() function to return MAX: */
+ fptr = (int(*)())setTmpMaxUsrLvl();
+
+ logaction = tfslogaction[action];
+ tfp = tfsstat(TFS_CHANGELOG_FILE);
+ tfsGetAtime(0,tbuf,sizeof(tbuf));
+ tbuflen = strlen(tbuf);
+
+ if (tfp) {
+ tfd = tfsopen(TFS_CHANGELOG_FILE,TFS_RDONLY,0);
+ fsize = tfsread(tfd,buf,TFS_CHANGELOG_SIZE);
+ tfsclose(tfd,0);
+
+ newfsize = (fsize+strlen(logaction)+strlen(string)+3);
+ if (tbuflen)
+ newfsize += tbuflen + 3;
+
+ eob = buf + fsize;
+
+ /* If newfsize is greater than the maximum size the file is
+ * allowed to grow, then keep removing the first line
+ * (oldest entry) until new size is within the limit...
+ */
+ if (newfsize > TFS_CHANGELOG_SIZE) {
+ lsize = 0;
+ eol = buf;
+ while ((newfsize-lsize) > TFS_CHANGELOG_SIZE) {
+ while((*eol != '\r') && (*eol != '\n')) eol++;
+ while((*eol == '\r') || (*eol == '\n')) eol++;
+ lsize = eol-buf;
+ }
+ fsize -= lsize;
+ newfsize -= lsize;
+ eob -= lsize;
+ memcpy(buf,eol,fsize);
+ }
+ if (tbuflen)
+ sprintf(eob,"%s: %s @ %s\n",logaction,string,tbuf);
+ else
+ sprintf(eob,"%s: %s\n",logaction,string);
+ err = _tfsunlink(TFS_CHANGELOG_FILE);
+ if (err < 0)
+ printf("%s: %s\n",TFS_CHANGELOG_FILE,
+ (char *)tfsctrl(TFS_ERRMSG,err,0));
+ err = tfsadd(TFS_CHANGELOG_FILE,0,"u3",buf,newfsize);
+ if (err < 0)
+ printf("%s: %s\n",TFS_CHANGELOG_FILE,
+ (char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+ else {
+ if (tbuflen)
+ len = sprintf(buf,"%s: %s @ %s\n",logaction,string,tbuf);
+ else
+ len = sprintf(buf,"%s: %s\n",logaction,string);
+ err = tfsadd(TFS_CHANGELOG_FILE,0,"u3",buf,len);
+ if (err < 0)
+ printf("%s: %s\n",TFS_CHANGELOG_FILE,
+ (char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+
+ /* Restore the original getUsrLvl() functionality: */
+ clrTmpMaxUsrLvl(fptr);
+#endif
+}
+
+int
+tfsLogCmd(int argc,char *argv[], int optind)
+{
+#if TFS_CHANGELOG_SIZE
+ int status;
+ int retval = 0;
+
+ if (getUsrLvl() < MAXUSRLEVEL) {
+ status = showTfsError(TFSERR_USERDENIED,0);
+ }
+ else {
+ if (argc == optind + 3) {
+ if (!strcmp(argv[optind+1],"on"))
+ tfslog(TFSLOG_ON,argv[optind+2]);
+ else if (!strcmp(argv[optind+1],"off"))
+ tfslog(TFSLOG_OFF,argv[optind+2]);
+ else
+ retval = CMD_PARAM_ERROR;
+ }
+ else if (argc == optind + 1)
+ printf("TFS logging %sabled\n",tfsLogging ? "en" : "dis");
+ else
+ retval = CMD_PARAM_ERROR;
+ }
+ return(retval);
+#else
+ return(CMD_FAILURE);
+#endif
+}
diff --git a/main/common/tfsprivate.h b/main/common/tfsprivate.h
new file mode 100644
index 0000000..7cfb840
--- /dev/null
+++ b/main/common/tfsprivate.h
@@ -0,0 +1,328 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tfsprivate.h:
+ *
+ * Header file for TFS used only by the monitor code.
+ * (that is... this should not be used by anything under umon_apps)
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _TFSPRIVATE_H_
+#define _TFSPRIVATE_H_
+
+#define SANITY 0xBEEF
+#define ERASED16 0xFFFF
+#define ERASED32 0xFFFFFFFF
+#define TFS_MAXOPEN 10 /* Maximum of 10 open files */
+#define TFS_QRYTMOUT 100000 /* Timeout for QRYBRUN */
+#define TFS_FSIZEMOD 16 /* File size must be a multiple of this value */
+#define MINUSRLEVEL 0 /* Minimum user level supported. */
+#define MAXUSRLEVEL 3 /* Maximum user level supported. */
+
+#define TFSHDRVERSION 1 /* Increment this if TFS header changes. */
+
+#if TFS_EBIN_COFF
+#define TFS_EBIN_NAME "coff"
+#elif TFS_EBIN_AOUT
+#define TFS_EBIN_NAME "aout"
+#elif TFS_EBIN_ELF
+#define TFS_EBIN_NAME "elf"
+#elif TFS_EBIN_MSBIN
+#define TFS_EBIN_NAME "msbin"
+#elif TFS_EBIN_ELFMSBIN
+#define TFS_EBIN_NAME "elf_msbin"
+#else
+#define TFS_EBIN_NAME "NA"
+#endif
+
+/* Two different types of Defragmentation tests:
+ * sector erase and flash write.
+ */
+#define DEFRAG_TEST_SERASE 1
+#define DEFRAG_TEST_FWRITE 2
+#define DEFRAG_TEST_EXIT 3
+
+/* Masks used to allow flags and modes to be part of the same long word. */
+#define TFS_FLAGMASK 0x0000ffff
+#define TFS_MODEMASK 0xffff0000
+
+/* Definitions related to tfslog: */
+#define TFSLOG_ADD 0
+#define TFSLOG_DEL 1
+#define TFSLOG_IPM 2
+#define TFSLOG_ON 3
+#define TFSLOG_OFF 4
+#define TIME_UNDEFINED 0xffffffff
+
+/* Used by tfsscript.. */
+#define EXIT_SCRIPT (1 << 0)
+#define REMOVE_SCRIPT (1 << 1)
+#define EXECUTE_AFTER_EXIT (1 << 2)
+#define EXIT_ALL_SCRIPTS (1 << 3)
+
+/* Device Table structure and definitions:
+ * The Device table is typically only one entry in length. It is defined
+ * on a per-target basis in the file tfsdev.h. In the simplest case, the
+ * table in tfsdev.h has all of the information in it. This is fine as long
+ * as there is no need to support different devices with the same monitor
+ * binary. To support the ability to have a device-table that is constructed
+ * based on the type of flash on-board, the TFS_DEVINFO_DYNAMIC bit must
+ * be set in the devinfo member of tfsdevtbl (in tfsdev.h). This tells TFS
+ * to figure out the addresses based on a few assumptions...
+ * * Regardless of the device type, the start address will be the same.
+ * * The spare sector starts immediately after the end of TFS storage space.
+ * In dynamic mode, all that needs to be specified in the tfsdevtbl of
+ * tfsdev.h is a prefix, start and devinfo fields. The other fields will
+ * be built based on information taken from the flash interface.
+ * One important note: if there is a block of contiguous flash space that
+ * spans accross multiple flash banks, then the bank # of the LAST bank in
+ * that block is what should be specified in the devinfo BANKMASK field.
+ */
+
+#define TFSEOT 0xffffffff
+#define TDEV struct tfsdev
+
+#define TFS_DEVTYPE_RAM 0x00100000
+#define TFS_DEVTYPE_FLASH 0x00200000
+#define TFS_DEVTYPE_NVRAM 0x00300000
+#define TFS_DEVTYPE_MASK 0x00f00000
+#define TFS_DEVINFO_DYNAMIC 0x00080000
+#define TFS_DEVINFO_AUTOINIT 0x00040000
+#define TFS_DEVINFO_BANKMASK 0x00000fff
+#define TFSDEVTOT ((sizeof(tfsdevtbl))/(sizeof(struct tfsdev)))
+
+#define TFS_DEVTYPE_ISRAM(tdp) \
+ (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM) || \
+ ((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_NVRAM))
+
+struct tfsdev {
+ char *prefix; /* Device name prefix. */
+ unsigned long start; /* First location into which TFS can */
+ /* begin to store files. */
+ unsigned long end; /* Last address into which TFS can */
+ /* place file data. This is usually */
+ /* one unit below the start of the */
+ /* spare sector. */
+ unsigned long spare; /* Start address of device spare */
+ /* sector. */
+ unsigned long sparesize; /* Size of device spare sector. */
+ unsigned long sectorcount; /* Number of sectors in this device. */
+ unsigned long devinfo; /* RAM or FLASH, etc... */
+};
+
+/* TFS defragmentation header:
+ * This header is used during defragmentation to record the state of the
+ * files in flash prior to the start of the defragmentation process.
+ */
+struct defraghdr {
+ struct tfshdr *ohdr; /* Original location of header. */
+ struct tfshdr *nextfile; /* Location of next file. */
+ long filsize; /* Size of file. */
+ unsigned long crc; /* 32 bit crc of this header. */
+ unsigned long ohdrcrc; /* Copy of file's original hdrcrc. */
+ long idx; /* Index into defrag hdr table. */
+ int nesn; /* New end sector number. */
+ long neso; /* New end sector offset. */
+ long oeso; /* Original end sector offset. */
+ char *nda; /* New destination address. */
+ char fname[TFSNAMESIZE+1]; /* Name of file. */
+};
+
+/* sectorcrc:
+ * This structure is used to store the crc of the sectors before and
+ * after a defragmentation. A table of these structures is built prior
+ * to startup of any file relocation.
+ */
+struct sectorcrc {
+ unsigned long precrc;
+ unsigned long postcrc;
+};
+
+#define DEFRAGHDRSIZ sizeof(struct defraghdr)
+#define DEFRAGHDR struct defraghdr
+
+/* States used during defragmentation: */
+#define SECTOR_DEFRAG_INACTIVE 1
+#define SCANNING_ACTIVE_SECTOR 2
+#define SCANNING_ACTIVE_SECTOR_1 3
+#define SCANNING_ACTIVE_SECTOR_2 4
+#define SCANNING_ACTIVE_SECTOR_3 5
+#define SCANNING_ACTIVE_SECTOR_4 6
+#define SCANNING_ACTIVE_SECTOR_5 7
+#define SECTOR_DEFRAG_ALMOST_DONE 8
+#define SECTOR_DEFRAG_ABORT_RESTART 9
+
+/* Different ways in which a file can span across the active sector. */
+#define SPANTYPE_UNDEF 0 /* Span type undefined */
+#define SPANTYPE_BPEP 1 /* Begin-previous/end-previous */
+#define SPANTYPE_BPEC 2 /* Begin-previous/end-current */
+#define SPANTYPE_BPEL 3 /* Begin-previous/end-later */
+#define SPANTYPE_BCEC 4 /* Begin-current/end-current */
+#define SPANTYPE_BCEL 5 /* Begin-current/end-later */
+#define SPANTYPE_BLEL 6 /* Begin-later/end-later */
+
+/* struct tfsdat:
+ Used by TFS to keep track of an opened file.
+*/
+struct tfsdat {
+ long offset; /* Current offset into file. */
+ long hwp; /* High water point for modified file. */
+ unsigned char *base; /* Base address of file. */
+ long flagmode; /* Flags & mode file was opened with. */
+ struct tfshdr hdr; /* File structure. */
+};
+
+/* struct tfsdfg, tfsflg & tfserr:
+ Structures provide an easy means of translation between values and
+ strings that explain those values.
+*/
+struct tfsflg {
+ long flag;
+ char sdesc;
+ char *ldesc;
+ long mask;
+};
+
+struct tfserr {
+ long err;
+ char *msg;
+};
+
+struct tfsdfg {
+ long state;
+ char *msg;
+};
+
+struct tfsinfo {
+ int liveftot; /* Number of live files. */
+ int livedata; /* Space used by living file data. */
+ int liveovrhd; /* Space used by living file overhead. */
+ int deadftot; /* Number of dead files. */
+ int deaddata; /* Space used by dead file data. */
+ int deadovrhd; /* Space used by dead file overhead. */
+ int pso; /* Per-sector (not per file) TFS overhead. */
+ int sos; /* Size of spare sector(s). */
+ int memtot; /* Total tfs memory space in device(s). */
+ int memfree; /* Memory space available for new file data. */
+ int memused; /* Total memory space used by files & overhead. */
+ int memfordata; /* Total memory available for new file data. */
+ int sectortot; /* Total number of sectors in this tfs device. */
+};
+typedef struct tfsinfo TINFO;
+
+
+/* Extern data: */
+extern long tfsTrace;
+extern long tfsFmodCount;
+extern TFILE **tfsAlist;
+extern TDEV tfsDeviceTbl[];
+#ifdef TFS_ALTDEVTBL_BASE
+extern TDEV *alt_tfsdevtbl;
+#endif
+extern TDEV alt_tfsdevtbl_base;
+extern struct tfsdat tfsSlots[];
+extern struct tfsflg tfsflgtbl[];
+extern int ScriptExitFlag;
+extern int TfsCleanEnable;
+extern int DefragTestPoint;
+extern int DefragTestType;
+extern int DefragTestSector;
+
+/* Extern functions: */
+extern int tfseof(int);
+extern int tfsinit(void);
+extern int _tfsinit(TDEV *);
+extern int tfsreorder(void);
+extern int tfsrunboot(void);
+extern int tfsfixup(int,int);
+extern int tfsunlink(char *);
+extern int tfslink(char *,char *);
+extern int tfsclean_on(void);
+extern int tfsclean_off(void);
+extern int _tfsunlink(char *);
+extern int tfsflasherase(int);
+extern int tfsrun(char **,int);
+extern int tfscheck(TDEV *,int);
+extern int validtfshdr(TFILE *);
+extern int tfstruncate(int,long);
+extern int tfsclose(int, char *);
+extern int tfsscript(TFILE *,int);
+extern int tfsseek(int, int, int);
+extern int tfsread(int,char *,int);
+extern int tfsspace(char *);
+extern int showTfsError(int,char *);
+extern int tfsflasheraseall(TDEV *);
+extern int tfsflasherased(TDEV *,int);
+extern int tfswrite(int, char *, int);
+extern int tfsgetline(int,char *,int);
+extern int tfsLogCmd(int,char **,int);
+extern int tfsopen(char *,long,char *);
+extern int tfsfstat(char *name,TFILE *);
+extern int tfsmemuse(TDEV *,TINFO *,int);
+extern int tfsipmod(char *,char *,int,int);
+extern int tfsclean_nps(TDEV *, char *, unsigned long);
+extern int tfsloadebin(TFILE *,int,long *,char *,int);
+extern int tfsloadebin_l(TFILE *,int,long *,int);
+extern int tfsadd(char *,char *,char *,unsigned char *,int);
+extern int tfsflashwrite(unsigned char *,unsigned char *,long);
+extern int tfsclean(TDEV *,int);
+extern int _tfsclean(TDEV *,int,int);
+extern int tfsautoclean(TDEV *,int);
+extern int (*tfsDocommand)(char *,int);
+extern int dumpDhdr(struct defraghdr *), dumpDhdrTbl(struct defraghdr *,int);
+extern int dumpFhdr(TFILE *);
+extern int tfsRunningMonrc(void);
+extern int tfsramdevice(char *,long,long);
+extern int tfscfg(char *,unsigned long, unsigned long, unsigned long);
+extern int tfscfgrestore(void);
+extern int tfsflagsatob(char *, long *);
+
+
+extern TDEV *gettfsdev_fromprefix(char *,int);
+
+extern TFILE *tfsnext(TFILE *);
+extern TFILE *tfsstat(char *name);
+extern TFILE *_tfsstat(char *name,int uselink);
+extern TFILE *nextfp(TFILE *,TDEV *);
+
+extern long tfstell(int);
+extern long (*tfsGetLtime)(void);
+extern long tfsctrl(int,long,long);
+
+extern unsigned long tfshdrcrc(TFILE *);
+
+extern char *tfsBase(TFILE *);
+extern char *tfserrmsg(int);
+extern char *tfsscriptname(void);
+extern char *tfsflagsbtoa(long,char *);
+extern char *(*tfsGetAtime)(long,char *,int);
+
+extern void tfsclear(TDEV *);
+extern void gototag(char *);
+extern void gosubtag(char *);
+extern void gosubret(char *);
+extern void exitscript(char *);
+extern void tfsstartup(void);
+extern void tfslog(int,char *);
+extern void tfsFacilityUnavailable(char *);
+extern void tfsrunrcfile(void);
+#endif
diff --git a/main/common/tftp.c b/main/common/tftp.c
new file mode 100644
index 0000000..f4b9130
--- /dev/null
+++ b/main/common/tftp.c
@@ -0,0 +1,1542 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tftp.c:
+ *
+ * This code supports the monitor's TFTP server.
+ * TFTP is covered under RFC 783.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_TFTP
+#include <stdarg.h>
+#include "endian.h"
+#include "genlib.h"
+#include "cpuio.h"
+#include "ether.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "monflags.h"
+#include "stddefs.h"
+#include "flash.h"
+#include "cli.h"
+#include "timer.h"
+
+/* To reduce uMon footprint size, INCLUDE_TFTPSRVR can be set to 0 in
+ * config.h...
+ */
+#ifndef INCLUDE_TFTPSRVR
+#define INCLUDE_TFTPSRVR 1
+#endif
+
+#if INCLUDE_ETHERVERBOSE
+#define TFTPVERBOSE(a) a
+#else
+#define TFTPVERBOSE(a)
+#endif
+
+
+#define MODE_NULL 0
+#define MODE_NETASCII 1
+#define MODE_OCTET 2
+
+void ShowTftpStats(void);
+static int SendTFTPData(struct ether_header *,ushort,uchar *,int);
+static int SendTFTPErr(struct ether_header *,short,int,char *fmt, ...);
+static int SendTFTPAck(struct ether_header *,ushort);
+static int SendTFTPRRQ(uchar *,uchar *,char *,char *,uchar *);
+static int SendTFTPWRQ(uchar *,uchar *,char *,char *);
+
+
+static struct elapsed_tmr tftpTmr;
+
+static ushort tftpPrevBlock; /* Keeps the value of the block number of
+ * the previous TFTP transaction.
+ */
+static int TftpWrqMode; /* Set to MODE_NETASCII, MODE_OCTET or
+ * MODE_NULL based on the incoming WRQ
+ * request
+ */
+static int TftpChopCount; /* Number of characters chopped from the
+ * incoming file because of NETASCII
+ * conversion (remove 0x0d).
+ */
+static short TftpLastPktSize;
+static uchar TftpLastPkt[TFTP_PKTOVERHEAD+TFTP_DATAMAX+4];
+ /* Storage of last packet sent. This is
+ * used if it is determined that the packet
+ * most recently sent must be sent again.
+ */
+
+static long TftpRetryTimeout; /* Count used during a TFTP transfer to
+ * kick off a retransmission of a packet.
+ */
+static ushort TftpRmtPort; /* Remote port of tftp transfer */
+static uchar *TftpAddr; /* Current destination address used for tftp
+ * file transfer to/from local memory.
+ */
+static char *TftpLTMptr; /* List-to-mem pointer used when filename
+ * for RRQ is ".".
+ */
+static int TftpCount; /* Running total number of bytes transferred
+ * for a particular tftp transaction.
+ */
+static char TftpState; /* Used to keep track of the current state
+ * of a tftp transaction.
+ */
+static char TftpTurnedOff; /* If non-zero, then tftp is disabled. */
+static char TftpGetActive; /* If non-zero, then 'get' is in progress. */
+static char TftpPutActive; /* If non-zero, then 'put' is in progress. */
+static char TftpErrString[32]; /* Used to post a tftp error message. */
+static char TftpTfsFname[TFSNAMESIZE+64]; /* Store name of WRQ destination
+ * file (plus flags & info).
+ */
+#if INCLUDE_TFTPSRVR
+/* ls_to_mem():
+ * Turn the list of files into a string buffer that contains
+ * each filename followed by a newline. Each filename is the "full"
+ * name, meaning that it will contain commas to delimit the flags and
+ * info fields of the file.
+ * Return a pointer to the allocated space.
+ */
+static char *
+ls_to_mem(void)
+{
+#if INCLUDE_TFS
+ int size;
+ TFILE *tfp;
+ char *base, *bp, *info, *flags, fbuf[16];
+
+ /* First determine how much memory will be needed to store
+ * the list of files... Each filename in the list will consist
+ * of the string formatted as "name,flags,info\n"...
+ */
+ size = 0;
+ tfp = (TFILE *)0;
+ while((tfp = tfsnext(tfp))) {
+ /* Increment size to include filename, 2 commas and a newline...
+ */
+ size += (strlen(TFS_NAME(tfp)) + 3);
+
+ /* Determine if flags and/or info field is to be present in
+ * the name, and add that to the size appropriately...
+ */
+ flags = tfsflagsbtoa(TFS_FLAGS(tfp),fbuf);
+ if (!fbuf[0])
+ flags = 0;
+ if (flags)
+ size += strlen(flags);
+ if (TFS_INFO(tfp))
+ size += strlen(TFS_INFO(tfp));
+ }
+
+ if (size == 0)
+ return(0);
+
+ /* Allocate the space. Add one additional byte to the size to
+ * account for the NULL termination at the end of the string...
+ */
+ base = bp = malloc(size+1);
+ if (bp == (char *)0)
+ return(0);
+
+ /* Load the buffer with the list of names with their
+ * TFS extensions...
+ */
+ tfp = (TFILE *)0;
+ while((tfp = tfsnext(tfp))) {
+ flags = tfsflagsbtoa(TFS_FLAGS(tfp),fbuf);
+ if (!flags || !fbuf[0])
+ flags = "";
+ if (TFS_INFO(tfp))
+ info = TFS_INFO(tfp);
+ else
+ info = "";
+
+ bp += sprintf(bp,"%s,%s,%s\n",TFS_NAME(tfp),flags,info);
+ }
+
+ return(base);
+#else
+ return(0);
+#endif
+}
+#endif
+
+static char *
+tftpStringState(int state)
+{
+ switch(state) {
+ case TFTPOFF:
+ return("OFF");
+ case TFTPIDLE:
+ return("IDLE");
+ case TFTPACTIVE:
+ return("ACTIVE");
+ case TFTPERROR:
+ return("ERROR");
+ case TFTPHOSTERROR:
+ return("HOSTERROR");
+ case TFTPSENTRRQ:
+ return("SENTRRQ");
+ case TFTPSENTWRQ:
+ return("SENTWRQ");
+ case TFTPTIMEOUT:
+ return("TIMEOUT");
+ default:
+ return("???");
+ }
+}
+
+static int
+tftpGotoState(int state)
+{
+ int ostate;
+
+ ostate = TftpState;
+ TftpState = state;
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) && (state != ostate))
+ printf(" TFTP State change %s -> %s\n",
+ tftpStringState(ostate), tftpStringState(state));
+#endif
+ return(ostate);
+}
+
+/* tftpGet():
+ * Return size of file if successful; else 0.
+ */
+int
+tftpGet(ulong addr,char *tftpsrvr,char *mode, char *hostfile,char *tfsfile,
+ char *tfsflags,char *tfsinfo)
+{
+ int done;
+ uchar binip[8], binenet[8], *enetaddr;
+
+ setenv("TFTPGET",0);
+
+ /* Convert IP address to binary: */
+ if (IpToBin(tftpsrvr,binip) < 0)
+ return(0);
+
+ /* Get the ethernet address for the IP: */
+ /* Give ARP the same verbosity (if any) set up for TFTP: */
+ TFTPVERBOSE(if (EtherVerbose & SHOW_TFTP_STATE) EtherVerbose |= SHOW_ARP);
+ enetaddr = ArpEther(binip,binenet,0);
+ TFTPVERBOSE(EtherVerbose &= ~SHOW_ARP);
+ if (!enetaddr) {
+ printf("ARP failed for %s\n",tftpsrvr);
+ return(0);
+ }
+
+ printf("Retrieving %s from %s...\n",hostfile,tftpsrvr);
+
+ /* Send the TFTP RRQ to initiate the transfer. */
+ if (SendTFTPRRQ(binip,binenet,hostfile,mode,(uchar *)addr) < 0) {
+ printf("RRQ failed\n");
+ return(0);
+ }
+
+ TftpGetActive = 1;
+
+ /* Wait for TftpState to indicate that the transaction has completed... */
+ done = 0;
+ while(!done) {
+ pollethernet();
+ switch(TftpState) {
+ case TFTPIDLE:
+ printf("Rcvd %d bytes",TftpCount);
+ done = 1;
+ break;
+ case TFTPERROR:
+ printf("TFTP Terminating\n");
+ done = 2;
+ break;
+ case TFTPHOSTERROR:
+ printf("Host error: %s\n",TftpErrString);
+ done = 2;
+ break;
+ case TFTPTIMEOUT:
+ printf("Timing out (%d bytes rcvd)\n",TftpCount);
+ done = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ TftpGetActive = 0;
+
+ if (done == 2) {
+ tftpInit();
+ return(0);
+ }
+
+ if (tfsfile) {
+ int err, filesize;
+
+ filesize = TftpCount - TftpChopCount;
+ printf("\nAdding %s (size=%d) to TFS...",tfsfile,filesize);
+ err = tfsadd(tfsfile,tfsinfo,tfsflags,(uchar *)addr,filesize);
+ if (err != TFS_OKAY)
+ printf("%s: %s\n",tfsfile,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+ printf("\n");
+ shell_sprintf("TFTPGET","%d",TftpCount);
+ return(TftpCount);
+}
+
+/* tftpPut():
+ * Return size of file if successful; else 0.
+ *
+ * Simple steps from RFC 1350 for PUT are:
+ * 1. Send WRQ to port 69 of remote server
+ * 2. Receive ACK 0 from Server RemotePort (not 69)
+ * 3. Send data less than 512 bytes to RemotePort which closes it out.
+ * 4. Reinit if error (above in GET errors if done == 2)
+ *
+ * This 'put' capability was contributed by Steve Shireman.
+ */
+
+int
+tftpPut(char *tftpsrvr,char *mode,char *hostfile,char *tfsfile,
+ char *tfsflags,char *tfsinfo)
+{
+#if INCLUDE_TFS
+ int done, tot;
+ TFILE *tfp;
+ uchar binip[8], binenet[8], *enetaddr;
+
+ setenv("TFTPPUT",0);
+
+ if ((tfp = tfsstat(tfsfile)) == (TFILE *)0)
+ return(0);
+
+ /* For 'put', the address increments and the count decrements as
+ * the transfer progresses.
+ */
+ TftpAddr = (uchar *)TFS_BASE(tfp);
+ TftpCount = tot = TFS_SIZE(tfp);
+
+ /* Convert IP address to binary: */
+ if (IpToBin(tftpsrvr,binip) < 0)
+ return(0);
+
+ /* Get the ethernet address for the IP:
+ * (give ARP the same verbosity set up for TFTP)
+ */
+ TFTPVERBOSE(if (EtherVerbose & SHOW_TFTP_STATE) EtherVerbose |= SHOW_ARP);
+ enetaddr = ArpEther(binip,binenet,0);
+ TFTPVERBOSE(EtherVerbose &= ~SHOW_ARP);
+
+ if (!enetaddr) {
+ printf("ARP failed for %s\n",tftpsrvr);
+ return(0);
+ }
+
+ printf("Sending %s to %s:%s...\n",tfsfile,tftpsrvr,hostfile);
+ TftpPutActive = 1;
+ tftpPrevBlock = 0;
+
+ /* Send the TFTP WRQ to initiate the transfer. */
+ if (SendTFTPWRQ(binip,binenet,hostfile,mode) < 0) {
+ printf("WRQ failed\n");
+ return(0);
+ }
+
+ /* Wait for TftpState to indicate that the transaction has completed... */
+ done = 0;
+ while(!done) {
+ pollethernet();
+ switch(TftpState) {
+ case TFTPIDLE:
+ printf("Sent %d bytes",tot);
+ done = 1;
+ break;
+ case TFTPERROR:
+ printf("TFTP Terminating\n");
+ done = 2;
+ break;
+ case TFTPHOSTERROR:
+ printf("Host error: %s\n",TftpErrString);
+ done = 2;
+ break;
+ case TFTPTIMEOUT:
+ printf("Timing out (%d bytes sent)\n",TftpCount);
+ done = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ TftpPutActive = 0;
+
+ if (done == 2) {
+ tftpInit();
+ return(0);
+ }
+ printf("\n");
+ shell_sprintf("TFTPPUT","%d",tot);
+ return(tot);
+#else
+ printf("TFTP 'put' requires TFS\n");
+ return(0);
+#endif
+}
+
+/* tftpInit():
+ * Called by the ethenet initialization to initialize state variables.
+ */
+void
+tftpInit()
+{
+ TftpCount = -1;
+ TftpRmtPort = 0;
+ TftpTurnedOff = 0;
+ tftpGotoState(TFTPIDLE);
+ TftpAddr = (uchar *)0;
+}
+
+/* storePktAndSend():
+ * The final stage in sending a TFTP packet...
+ * 1. Compute IP and UDP checksums;
+ * 2. Copy ethernet packet to a buffer so that it can be resent
+ * if necessary (by tftpStateCheck()).
+ * 3. Store the size of the packet;
+ * 4. Send the packet out the interface.
+ * 5. Reset the timeout count and re-transmission delay variables.
+ */
+static void
+storePktAndSend(struct ip *ipp, struct ether_header *epkt,int size)
+{
+ ipChksum(ipp); /* Compute csum of ip hdr */
+ udpChksum(ipp); /* Compute UDP checksum */
+ /* Copy packet to static buffer */
+ memcpy((char *)TftpLastPkt,(char *)epkt,size);
+ TftpLastPktSize = size; /* Copy size to static location */
+ sendBuffer(size); /* Send buffer out ethernet i*/
+
+ /* Re-initialize the re-transmission delay variables.
+ */
+ TftpRetryTimeout = RetransmitDelay(DELAY_INIT_TFTP);
+ startElapsedTimer(&tftpTmr,TftpRetryTimeout * 1000);
+}
+
+/* getTftpSrcPort():
+ * Each time a TFTP RRQ goes out, use a new source port number.
+ * Cycle through a block of 256 port numbers...
+ */
+static ushort
+getTftpSrcPort(void)
+{
+ if (TftpSrcPort < (IPPORT_TFTPSRC+256))
+ TftpSrcPort++;
+ else
+ TftpSrcPort = IPPORT_TFTPSRC;
+ return(TftpSrcPort);
+}
+
+/* tftpStateCheck():
+ * Called by the pollethernet function to support the ability to retry
+ * on a TFTP transmission that appears to have terminated prematurely
+ * due to a lost packet. If a packet is sent and the response is not
+ * received within about 1-2 seconds, the packet is re-sent. The retry
+ * will repeat 8 times; then give up and set the TFTP state to idle.
+ *
+ * Taken from RFC 1350 section 2 "Overview of the Protocol"...
+ * ... If a packet gets lost in the network, the intended recipient will
+ * timeout and may retransmit his last packet (which may be data or an
+ * acknowledgement), thus causing the sender of the lost packet to retransmit
+ * the lost packet.
+ *
+ * Taken from RFC 1123 section 4.2.3.2 "Timeout Algorithms"...
+ * ... a TFTP implementation MUST use an adaptive timeout ...
+ */
+
+void
+tftpStateCheck(void)
+{
+ uchar *buf;
+ long delay;
+ ushort tftp_opcode;
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ struct ether_header *ehdr;
+
+ switch(TftpState) {
+ case TFTPIDLE:
+ case TFTPTIMEOUT:
+ case TFTPERROR:
+ return;
+ default:
+ break;
+ }
+
+ /* If timeout occurs, re-transmit the packet...
+ */
+ if (!msecElapsed(&tftpTmr))
+ return;
+
+ delay = RetransmitDelay(DELAY_INCREMENT);
+ if (delay == RETRANSMISSION_TIMEOUT) {
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" TFTP_RETRY giving up\n");
+#endif
+ tftpGotoState(TFTPTIMEOUT);
+ enableBroadcastReception();
+ return;
+ }
+
+ /* Get a transmit buffer and copy the packet that was last sent.
+ * Insert a new IP ID, recalculate the checksums and send it again...
+ * If the opcode of the packet to be re-transmitted is RRQ, then
+ * use a new port number.
+ */
+ buf = (uchar *)getXmitBuffer();
+ memcpy((char *)buf,(char *)TftpLastPkt,TftpLastPktSize);
+ ehdr = (struct ether_header *)buf;
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)(ihdr + 1);
+ tftp_opcode = *(ushort *)(uhdr + 1);
+ ihdr->ip_id = ipId();
+ if (tftp_opcode == ecs(TFTP_RRQ)) {
+ uhdr->uh_sport = getTftpSrcPort();
+ self_ecs(uhdr->uh_sport);
+ }
+ ipChksum(ihdr);
+ udpChksum(ihdr);
+ sendBuffer(TftpLastPktSize);
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" TFTP_RETRY (%ld secs)\n",TftpRetryTimeout);
+#endif
+
+ TftpRetryTimeout = delay;
+ startElapsedTimer(&tftpTmr,TftpRetryTimeout * 1000);
+ return;
+}
+
+#if INCLUDE_TFTPSRVR
+/* tftpStartSrvrFilter():
+ * Called when either a TFTP_RRQ or TFTP_WRQ is received indicating that
+ * a client wants to start up a transfer.
+ * If TftpState is IDLE, ERROR or TIMEOUT, this means it is safe to start
+ * up a new transfer through the server; otherwise return 0.
+ * Also, if the server has been disabled by "tftp off" at the command line
+ * (i.e. TftpTurnedOff == 1) then return 0.
+ */
+static int
+tftpStartSrvrFilter(struct ether_header *ehdr,struct Udphdr *uhdr)
+{
+ if (TftpTurnedOff) {
+ SendTFTPErr(ehdr,0,1,"TFTP srvr off");
+ return(0);
+ }
+
+ if ((TftpState == TFTPIDLE) || (TftpState == TFTPERROR) ||
+ (TftpState == TFTPTIMEOUT)) {
+ TftpTfsFname[0] = 0;
+ TftpRmtPort = ecs(uhdr->uh_sport);
+ tftpGotoState(TFTPACTIVE);
+ return(1);
+ }
+ /* If block is zero and the incoming WRQ request is from the same
+ * port as was previously recorded, then assume the ACK sent back
+ * to the requester was not received, and this is a WRQ that is
+ * being re-sent. That being the case, just send the Ack back.
+ */
+ else if ((tftpPrevBlock == 0) && (TftpRmtPort == uhdr->uh_sport)) {
+ SendTFTPAck(ehdr,0);
+ return(0);
+ }
+ else {
+ /* Note: the value of TftpState is not changed (final arg to
+ * SendTFTPErr is 0) to TFTPERROR. This is because
+ * we received a RRQ/WRQ request while processing a different
+ * TFTP transfer. We want to send the error response to the
+ * sender, but we don't want to stay in an error state because
+ * there is another valid TFTP transfer in progress.
+ */
+ SendTFTPErr(ehdr,0,0,"TFTP srvr busy");
+ return(0);
+ }
+}
+#endif
+
+/* tftpTransferComplete():
+ * Print a message indicating that the transfer has completed.
+ */
+static void
+tftpTransferComplete(void)
+{
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
+ printf("TFTP transfer complete.\n");
+#endif
+}
+
+/* processTFTP():
+ * This function handles the majority of the TFTP requests that a
+ * TFTP server must be able to handle. There is no real robust
+ * error handling, but it seems to work pretty well.
+ * Refer to Stevens' "UNIX Network Programming" chap 12 for details
+ * on TFTP.
+ * Note: During TFTP, promiscuity, broadcast & multicast reception
+ * are all turned off. This is done to speed up the file transfer.
+ */
+int
+processTFTP(struct ether_header *ehdr,ushort size)
+{
+ struct ip *ihdr;
+ struct Udphdr *uhdr;
+ uchar *data;
+ int count;
+ ushort opcode, block, errcode;
+ char *errstring, *tftpp;
+#if INCLUDE_TFTPSRVR
+ char *comma, *env, *filename, *mode;
+#endif
+
+ ihdr = (struct ip *)(ehdr + 1);
+ uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));
+ tftpp = (char *)(uhdr + 1);
+ opcode = *(ushort *)tftpp;
+
+ switch (opcode) {
+#if INCLUDE_TFTPSRVR
+ case ecs(TFTP_WRQ):
+ filename = tftpp+2;
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
+ printf("TFTP rcvd WRQ: file <%s>\n", filename);
+#endif
+ if (!tftpStartSrvrFilter(ehdr,uhdr))
+ return(0);
+
+ mode = filename;
+ while(*mode)
+ mode++;
+ mode++;
+
+ /* Destination of WRQ can be an address (0x...), environment
+ * variable ($...) or a TFS filename...
+ */
+ if (filename[0] == '$') {
+ env = getenv(&filename[1]);
+ if (env) {
+ TftpAddr = (uchar *)strtol(env,(char **)0,0);
+ }
+ else {
+ SendTFTPErr(ehdr,0,1,"Shell var not set");
+ return(0);
+ }
+ }
+ else if ((filename[0] == '0') && (filename[1] == 'x')) {
+ TftpAddr = (uchar *)strtol(filename,(char **)0,0);
+ }
+ else {
+ if (MFLAGS_NOTFTPOVW() && tfsstat(filename)) {
+ SendTFTPErr(ehdr,6,1,"File exists");
+ return(0);
+ }
+ TftpAddr = (uchar *)getAppRamStart();
+ strncpy(TftpTfsFname,filename,sizeof(TftpTfsFname)-1);
+ TftpTfsFname[sizeof(TftpTfsFname)-1] = 0;
+ }
+ TftpCount = -1; /* not used with WRQ, so clear it */
+
+ /* Convert mode to lower case... */
+ strtolower(mode);
+ if (!strcmp(mode,"netascii"))
+ TftpWrqMode = MODE_NETASCII;
+ else if (!strcmp(mode,"octet"))
+ TftpWrqMode = MODE_OCTET;
+ else {
+ SendTFTPErr(ehdr,0,1,"Mode '%s' not supported.",mode);
+ TftpWrqMode = MODE_NULL;
+ TftpCount = -1;
+ return(0);
+ }
+ block = 0;
+ tftpPrevBlock = block;
+ TftpChopCount = 0;
+ disableBroadcastReception();
+ break;
+ case ecs(TFTP_RRQ):
+ filename = tftpp+2;
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
+ printf("TFTP rcvd RRQ: file <%s>\n",filename);
+#endif
+ if (!tftpStartSrvrFilter(ehdr,uhdr))
+ return(0);
+ mode = filename;
+ while(*mode) mode++;
+ mode++;
+ comma = strchr(filename,',');
+ if (!comma) {
+ TFILE *tfp;
+
+ if (!strcmp(filename,".")) {
+ TftpLTMptr = (char *)ls_to_mem();
+ TftpAddr = (uchar *)TftpLTMptr;
+ if (TftpLTMptr)
+ TftpCount = strlen((char *)TftpAddr);
+ else
+ TftpCount = 0;
+ }
+ else {
+ tfp = tfsstat(filename);
+ if (!tfp) {
+ SendTFTPErr(ehdr,0,1,"File (%s) not found",filename);
+ TftpCount = -1;
+ return(0);
+ }
+ TftpAddr = (uchar *)TFS_BASE(tfp);
+ TftpCount = TFS_SIZE(tfp);
+ }
+ }
+ else {
+ *comma++ = 0;
+ if ((filename[0] == '$') && (getenv(&filename[1])))
+ TftpAddr = (uchar *)strtol(getenv(&filename[1]),(char **)0,0);
+ else
+ TftpAddr = (uchar *)strtol(filename,(char **)0,0);
+ TftpCount = strtol(comma,(char **)0,0);
+ }
+ if (strcmp(mode,"octet")) {
+ SendTFTPErr(ehdr,0,1,"Must use binary mode");
+ TftpCount = -1;
+ return(0);
+ }
+ block = tftpPrevBlock = 1;
+ disableBroadcastReception();
+ tftpGotoState(TFTPACTIVE);
+ SendTFTPData(ehdr,block,TftpAddr,TftpCount);
+ return(0);
+#endif
+ case ecs(TFTP_DAT):
+ block = ecs(*(ushort *)(tftpp+2));
+ count = ecs(uhdr->uh_ulen) - (sizeof(struct Udphdr)+4);
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Rcvd TFTP_DAT (%d,blk=%d)\n",count,block);
+ else if (EtherVerbose & SHOW_TFTP_TICKER)
+ ticktock();
+#endif
+
+ if (TftpState == TFTPSENTRRQ) { /* See notes in SendTFTPRRQ() */
+ tftpPrevBlock = 0;
+ if (block == 1) {
+ TftpRmtPort = ecs(uhdr->uh_sport);
+ tftpGotoState(TFTPACTIVE);
+ }
+ else {
+ SendTFTPErr(ehdr,0,1,"invalid block (%d)",block);
+ return(0);
+ }
+ }
+ /* Since we don't ACK the final TFTP_DAT from the server until after
+ * the file has been written, it is possible that we will receive
+ * a re-transmitted TFTP_DAT from the server. This is ignored by
+ * Sending another ACK...
+ */
+ else if ((TftpState == TFTPIDLE) && (block == tftpPrevBlock)) {
+ SendTFTPAck(ehdr,block);
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" (packet ignored)\n");
+#endif
+ return(0);
+ }
+ else if (TftpState != TFTPACTIVE) {
+ SendTFTPErr(ehdr,0,1,"Bad state (%s) for incoming TFTP_DAT",
+ tftpStringState(TftpState));
+ return(0);
+ }
+
+ if (ecs(uhdr->uh_sport) != TftpRmtPort) {
+ SendTFTPErr(ehdr,0,0,"TFTP_DAT porterr: rcvd %d, expected %d",
+ ecs(uhdr->uh_sport),TftpRmtPort);
+ return(0);
+ }
+ if (block == tftpPrevBlock) { /* If block didn't increment, assume */
+ SendTFTPAck(ehdr,block); /* retry. Ack it and return here. */
+ return(0); /* Otherwise, if block != tftpPrevBlock+1, */
+ } /* return an error, and quit now. */
+ else if ((block == 0) && ((tftpPrevBlock & 0xffff) == 0xffff)) {
+ /* This case occurs when the block number wraps.
+ * It is a legal case where the downloaded data exceeds
+ * 32Mg (blockno > 0xffff).
+ */
+ }
+ else if (block != tftpPrevBlock+1) {
+#ifdef DONT_IGNORE_OUT_OF_SEQUENCE_BLOCKS
+ SendTFTPErr(ehdr,0,1,"TFTP_DAT blockerr: rcvd %d, expected %d",
+ block,tftpPrevBlock+1);
+ TftpCount = -1;
+#endif
+ return(0);
+ }
+ TftpCount += count;
+ tftpPrevBlock = block;
+ data = (uchar *)(tftpp+4);
+
+ /* If count is less than TFTP_DATAMAX, this must be the last
+ * packet of the transfer, so clean up state here.
+ */
+ if (count < TFTP_DATAMAX) {
+ enableBroadcastReception();
+ tftpGotoState(TFTPIDLE);
+ }
+
+ /* Make sure the destination address for the data is not flash
+ * or BSS space...
+ */
+ if (inUmonBssSpace((char *)TftpAddr,(char *)(TftpAddr+count))) {
+ SendTFTPErr(ehdr,0,1,"TFTP can't write to uMon BSS space");
+ TftpCount = -1;
+ return(0);
+ }
+
+#if INCLUDE_FLASH
+ if (InFlashSpace(TftpAddr,count)) {
+ SendTFTPErr(ehdr,0,1,"TFTP can't write directly to flash");
+ TftpCount = -1;
+ return(0);
+ }
+#endif
+ /* Copy data from enet buffer to TftpAddr location.
+ * If netascii mode is active, then this transfer is much
+ * slower...
+ * If not netascii, then we use s_memcpy() because it does
+ * a verification of each byte written and will abort as soon
+ * as a failure is detected.
+ */
+ if (TftpWrqMode == MODE_NETASCII) {
+ int tmpcount = count;
+
+ while(tmpcount) {
+ if (*data == 0x0d) {
+ data++;
+ tmpcount--;
+ TftpChopCount++;
+ continue;
+ }
+
+ *TftpAddr = *data;
+ if (*TftpAddr != *data) {
+ SendTFTPErr(ehdr,0,1,"Write error at 0x%lx",
+ (ulong)TftpAddr);
+ TftpCount = -1;
+ return(0);
+ }
+ TftpAddr++;
+ data++;
+ tmpcount--;
+ }
+ }
+ else {
+ if (s_memcpy((char *)TftpAddr,(char *)data,count,0,0) != 0) {
+ SendTFTPErr(ehdr,0,1,"Write error at 0x%lx",(ulong)TftpAddr);
+ TftpCount = -1;
+ return(0);
+ }
+ TftpAddr += count;
+ }
+
+ /* Check for transfer complete (count < TFTP_DATAMAX)... */
+ if (count < TFTP_DATAMAX) {
+ if (TftpTfsFname[0]) {
+ char *fcomma, *icomma, *flags, *info;
+ int err;
+
+ /* If the transfer is complete and TftpTfsFname[0]
+ * is non-zero, then write the data to the specified
+ * TFS file... Note that a comma in the filename is
+ * used to find the start of (if any) the TFS flags
+ * string. A second comma, marks the info field.
+ */
+ info = (char *)0;
+ flags = (char *)0;
+ fcomma = strchr(TftpTfsFname,',');
+ if (fcomma) {
+ icomma = strchr(fcomma+1,',');
+ if (icomma) {
+ *icomma = 0;
+ info = icomma+1;
+ }
+ if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != -1) {
+ *fcomma = 0;
+ flags = fcomma+1;
+ }
+ else {
+ SendTFTPErr(ehdr,0,1,"Invalid flag '%s'",
+ TftpTfsFname);
+ TftpTfsFname[0] = 0;
+ break;
+ }
+ }
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
+ printf("TFTP adding file: '%s' to TFS.\n",TftpTfsFname);
+#endif
+ err = tfsadd(TftpTfsFname,info,flags,
+ (uchar *)getAppRamStart(),TftpCount+1-TftpChopCount);
+ if (err != TFS_OKAY) {
+ SendTFTPErr(ehdr,0,1,"TFS err: %s",
+ (char *)tfsctrl(TFS_ERRMSG,err,0));
+ }
+ TftpTfsFname[0] = 0;
+ }
+ else {
+ int cnt;
+ char *addr;
+
+ /* If the transfer is complete and no file add is to
+ * be done, then we flush d-cache and invalidate
+ * i-cache across the memory space that was just
+ * copied to. This is necessary in case the
+ * binary data that was just transferred is code.
+ */
+ cnt = TftpCount + 1;
+ addr = (char *)TftpAddr - cnt;
+ flushDcache(addr,cnt);
+ invalidateIcache(addr,cnt);
+ }
+ if (!TftpGetActive)
+ shell_sprintf("TFTPRCV","%d",TftpCount+1);
+ tftpTransferComplete();
+ }
+ break;
+ case ecs(TFTP_ACK):
+ block = ecs(*(ushort *)(tftpp+2));
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Rcvd TFTP_ACK (blk#%d)\n",block);
+#endif
+ if ((TftpState != TFTPACTIVE) && (TftpState != TFTPSENTWRQ)) {
+ SendTFTPErr(ehdr,0,1,"Bad state (%s) for incoming TFTP_ACK",
+ tftpStringState(TftpState));
+ return(0);
+ }
+ if (block == tftpPrevBlock) {
+ if (TftpCount > TFTP_DATAMAX) {
+ if (TftpState == TFTPACTIVE) {
+ TftpCount -= TFTP_DATAMAX;
+ TftpAddr += TFTP_DATAMAX;
+ }
+ SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);
+ if (TftpState == TFTPSENTWRQ) {
+ TftpCount -= TFTP_DATAMAX;
+ TftpAddr += TFTP_DATAMAX;
+ }
+ tftpPrevBlock++;
+ }
+ else if (TftpCount == TFTP_DATAMAX) {
+ if (TftpState == TFTPACTIVE)
+ TftpCount = 0;
+ SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);
+ if (TftpState == TFTPSENTWRQ) {
+ TftpCount = 0;
+ }
+ tftpPrevBlock++;
+ }
+ else {
+ if (TftpState == TFTPSENTWRQ) {
+ if (TftpCount == -1) {
+ TftpCount = 0;
+ tftpGotoState(TFTPIDLE);
+ enableBroadcastReception();
+ tftpTransferComplete();
+ }
+ else {
+ SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);
+ TftpAddr += TftpCount;
+ TftpCount = -1;
+ tftpPrevBlock++;
+ }
+ }
+ else {
+ TftpAddr += TftpCount;
+ TftpCount = 0;
+ tftpGotoState(TFTPIDLE);
+ if (TftpLTMptr) {
+ free(TftpLTMptr);
+ TftpLTMptr = (char *)0;
+ }
+ enableBroadcastReception();
+ tftpTransferComplete();
+ }
+ }
+ }
+ else if (block == tftpPrevBlock-1) {
+ SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);
+ }
+ else {
+#ifdef DONT_IGNORE_OUT_OF_SEQUENCE_BLOCKS
+ SendTFTPErr(ehdr,0,1,"TFTP_ACK blockerr: rcvd %d, expected %d",
+ block,tftpPrevBlock-1);
+ TftpCount = -1;
+#endif
+ return(0);
+ }
+ return(0);
+ case ecs(TFTP_ERR):
+ errcode = ecs(*(ushort *)(tftpp+2));
+ errstring = tftpp+4;
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Rcvd TFTP_ERR #%d (%s)\n",errcode,errstring);
+#endif
+ TftpCount = -1;
+ tftpGotoState(TFTPHOSTERROR);
+ strncpy(TftpErrString,errstring,sizeof(TftpErrString)-1);
+ TftpErrString[sizeof(TftpErrString)-1] = 0;
+ return(0);
+ default:
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Rcvd <%04x> unknown TFTP opcode\n", opcode);
+#endif
+ TftpCount = -1;
+ return(-1);
+ }
+ SendTFTPAck(ehdr,block);
+ return(0);
+}
+
+/* SendTFTPRRQ():
+ * Pass the ether and ip address of the TFTP server, along with the
+ * filename and mode to start up a target-initiated TFTP download.
+ * The initial TftpState value is TFTPSENTRRQ, this is done so that incoming
+ * TFTP_DAT packets can be verified...
+ * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then
+ * the block number should be 1. If this is true, then that server's
+ * source port is stored away in TftpRmtPort so that all subsequent
+ * TFTP_DAT packets will be compared to the initial source port. If no
+ * match, then respond with a TFTP error or ICMP PortUnreachable message.
+ * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then
+ * if the block number is not 1, generate a error.
+ */
+static int
+SendTFTPRRQ(uchar *ipadd,uchar *eadd,char *filename,char *mode,uchar *loc)
+{
+ uchar *tftpdat;
+ ushort ip_len;
+ struct ether_header *te;
+ struct ip *ti;
+ struct Udphdr *tu;
+
+ TftpChopCount = 0;
+ tftpGotoState(TFTPSENTRRQ);
+ TftpAddr = loc;
+ TftpCount = 0;
+
+ /* Retrieve an ethernet buffer from the driver and populate the
+ * ethernet level of packet:
+ */
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6);
+ memcpy((char *)&te->ether_dhost,(char *)eadd,6);
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it appropriately: */
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+ ip_len = sizeof(struct ip) +
+ sizeof(struct Udphdr) + strlen(filename) + strlen(mode) + 4;
+ ti->ip_len = ecs(ip_len);
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4);
+ memcpy((char *)&ti->ip_dst.s_addr,(char *)ipadd,4);
+
+ /* Now udp... */
+ tu = (struct Udphdr *) (ti + 1);
+ tu->uh_sport = getTftpSrcPort();
+ self_ecs(tu->uh_sport);
+ tu->uh_dport = ecs(TftpPort);
+ tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip)));
+
+ /* Finally, the TFTP specific stuff... */
+ tftpdat = (uchar *)(tu+1);
+ *(ushort *)(tftpdat) = ecs(TFTP_RRQ);
+ strcpy((char *)tftpdat+2,(char *)filename);
+ strcpy((char *)tftpdat+2+strlen((char *)filename)+1,mode);
+
+ if (!strcmp(mode,"netascii"))
+ TftpWrqMode = MODE_NETASCII;
+ else
+ TftpWrqMode = MODE_OCTET;
+
+ storePktAndSend(ti, te,TFTPACKSIZE+strlen(filename)+strlen(mode));
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf("\n Sent TFTP_RRQ (file=%s)\n",filename);
+#endif
+
+ return(0);
+}
+
+
+/* SendTFTPWRQ(): SSADDED
+ * Pass the ether and ip address of the TFTP server, along with the
+ * filename and mode to start up a target-initiated TFTP download.
+ * The initial TftpState value is TFTPSENTRRQ, this is done so that incoming
+ * TFTP_DAT packets can be verified...
+ * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then
+ * the block number should be 1. If this is true, then that server's
+ * source port is stored away in TftpRmtPort so that all subsequent
+ * TFTP_DAT packets will be compared to the initial source port. If no
+ * match, then respond with a TFTP error or ICMP PortUnreachable message.
+ * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then
+ * if the block number is not 1, generate a error.
+ */
+static int
+SendTFTPWRQ(uchar *ipadd,uchar *eadd,char *filename,char *mode)
+{
+ uchar *tftpdat;
+ ushort ip_len;
+ struct ether_header *te;
+ struct ip *ti;
+ struct Udphdr *tu;
+
+ TftpChopCount = 0;
+
+ /* Retrieve an ethernet buffer from the driver and populate the
+ * ethernet level of packet:
+ */
+ te = (struct ether_header *) getXmitBuffer();
+ memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6);
+ memcpy((char *)&te->ether_dhost,(char *)eadd,6);
+ te->ether_type = ecs(ETHERTYPE_IP);
+
+ /* Move to the IP portion of the packet and populate it appropriately: */
+ ti = (struct ip *) (te + 1);
+ ti->ip_vhl = IP_HDR_VER_LEN;
+ ti->ip_tos = 0;
+ ip_len = sizeof(struct ip) +
+ sizeof(struct Udphdr) + strlen(filename) + strlen(mode) + 4;
+ ti->ip_len = ecs(ip_len);
+ ti->ip_id = ipId();
+ ti->ip_off = 0;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4);
+ memcpy((char *)&ti->ip_dst.s_addr,(char *)ipadd,4);
+
+ /* Now udp... */
+ tu = (struct Udphdr *) (ti + 1);
+ tu->uh_sport = getTftpSrcPort();
+ self_ecs(tu->uh_sport);
+ tu->uh_dport = ecs(TftpPort);
+ tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip)));
+
+ /* Finally, the TFTP specific stuff... */
+ tftpdat = (uchar *)(tu+1);
+ *(ushort *)(tftpdat) = ecs(TFTP_WRQ);
+ strcpy((char *)tftpdat+2,(char *)filename);
+ strcpy((char *)tftpdat+2+strlen((char *)filename)+1,mode);
+
+ if (!strcmp(mode,"netascii"))
+ TftpWrqMode = MODE_NETASCII;
+ else
+ TftpWrqMode = MODE_OCTET;
+
+ storePktAndSend(ti, te,TFTPACKSIZE+strlen(filename)+strlen(mode));
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf("\n Sent TFTP_WRQ (file=%s)\n",filename);
+#endif
+
+ tftpGotoState(TFTPSENTWRQ);
+ return(0);
+}
+//ss END OF ADDED SendTRTPWRQ
+
+
+/* SendTFTPAck():
+ */
+static int
+SendTFTPAck(struct ether_header *re,ushort block)
+{
+ uchar *tftpdat;
+ ushort ip_len;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct Udphdr *tu, *ru;
+
+ te = EtherCopy(re);
+
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (re + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + 4;
+ ti->ip_len = ecs(ip_len);
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip)));
+
+ tftpdat = (uchar *)(tu+1);
+ *(ushort *)(tftpdat) = ecs(TFTP_ACK);
+ *(ushort *)(tftpdat+2) = ecs(block);
+
+ storePktAndSend(ti,te,TFTPACKSIZE);
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Sent TFTP_ACK (blk#%d)\n",block);
+#endif
+ return(0);
+}
+
+/* SendTFTPErr():
+ */
+static int
+SendTFTPErr(struct ether_header *re,short errno,int changestate,char *fmt, ...)
+{
+ va_list argp;
+ short len, tftplen, hdrlen;
+ uchar *tftpmsg;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct Udphdr *tu, *ru;
+ static char errmsg[128];
+
+ if (changestate)
+ tftpGotoState(TFTPERROR);
+
+ va_start(argp,fmt);
+ vsnprintf(errmsg,sizeof(errmsg),fmt,argp);
+ va_end(argp);
+
+#if INCLUDE_ETHERVERBOSE
+ if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
+ printf("TFTP err: %s\n",errmsg);
+#endif
+
+ tftplen = strlen(errmsg) + 1 + 4;
+ hdrlen = sizeof(struct ip) + sizeof(struct Udphdr);
+ len = tftplen + hdrlen ;
+
+ te = EtherCopy(re);
+
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (re + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ecs(len);
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = sizeof(struct Udphdr) + tftplen;
+ self_ecs(tu->uh_ulen);
+
+ tftpmsg = (uchar *)(tu+1);
+ *(ushort *)(tftpmsg) = ecs(TFTP_ERR);
+ * (ushort *)(tftpmsg+2) = ecs(errno);
+ strcpy((char *)tftpmsg+4,(char *)errmsg);
+
+ storePktAndSend(ti,te,TFTPACKSIZE + strlen(errmsg) + 1);
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Sent TFTP Err#%d (%s) \n",errno,errmsg);
+#endif
+
+ return(0);
+}
+
+/* SendTFTPData():
+ */
+static int
+SendTFTPData(struct ether_header *re,ushort block,uchar *data,int count)
+{
+ int len, tftplen, hdrlen;
+ uchar *tftpmsg;
+ struct ether_header *te;
+ struct ip *ti, *ri;
+ struct Udphdr *tu, *ru;
+
+ if (count > TFTP_DATAMAX)
+ count = TFTP_DATAMAX;
+
+ tftplen = count + 2 + 2; /* sizeof (data + opcode + blockno) */
+ hdrlen = sizeof(struct ip) + sizeof(struct Udphdr);
+ len = tftplen + hdrlen ;
+
+ te = EtherCopy(re);
+
+ ti = (struct ip *) (te + 1);
+ ri = (struct ip *) (re + 1);
+ ti->ip_vhl = ri->ip_vhl;
+ ti->ip_tos = ri->ip_tos;
+ ti->ip_len = ecs(len);
+ ti->ip_id = ipId();
+ ti->ip_off = ri->ip_off;
+ ti->ip_ttl = UDP_TTL;
+ ti->ip_p = IP_UDP;
+ memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr),
+ sizeof(struct in_addr));
+ memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr),
+ sizeof(struct in_addr));
+
+ tu = (struct Udphdr *) (ti + 1);
+ ru = (struct Udphdr *) (ri + 1);
+ tu->uh_sport = ru->uh_dport;
+ tu->uh_dport = ru->uh_sport;
+ tu->uh_ulen = sizeof(struct Udphdr) + tftplen;
+ self_ecs(tu->uh_ulen);
+
+ tftpmsg = (uchar *)(tu+1);
+ *(ushort *)(tftpmsg) = ecs(TFTP_DAT);
+ *(ushort *)(tftpmsg+2) = ecs(block);
+ memcpy((char *)tftpmsg+4,(char *)data,count);
+
+ len+=sizeof(struct ether_header);
+
+ storePktAndSend(ti,te,len);
+
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_TFTP_STATE)
+ printf(" Sent TFTP data blk#%d (%d bytes @ 0x%lx) \n",
+ block,count,(ulong)data);
+#endif
+ return(0);
+}
+
+#if 0
+THIS IS NOT YET TESTED
+/* parseLongFilename():
+ * Given a full filename that may contain up to three different
+ * comma-delimited tokens, this function will parse that string and
+ * return the requested tokens.
+ *
+ * The syntax of fullname can be...
+ * - name
+ * - name,flags
+ * - name,flags,info
+ * - name,,info
+ *
+ * Return 0 if successful, -1 if failure.
+ */
+int
+parseLongFilename(char *fullname,char *name, char *flags, char *info)
+{
+ char *comma, *cp;
+
+ /* Parse the fullname string looking for commas to determine what
+ * information is in the string. Then, based on the presence of
+ * the commas, populate the incoming pointers with the appropriate
+ * portion of the fullname string.
+ * If the pointer is NULL, then just skip over that portion of the
+ * algorithm.
+ */
+ cp = fullname;
+ comma = strchr(cp,',');
+ if (comma) {
+ if (name) {
+ while(cp != comma)
+ *name++ = *cp++;
+ *name = 0;
+ }
+ cp++;
+ comma = strchr(cp,',');
+ if (comma) {
+ if (flags) {
+ while(cp != comma)
+ *flags++ = *cp++;
+ *flags = 0;
+ }
+ cp++;
+ if (info) {
+ strcpy(info,cp);
+ }
+ }
+ else {
+ if (flags)
+ strcpy(flags,cp);
+ }
+ }
+ else {
+ if (name)
+ strcpy(name,fullname);
+ }
+ return(0);
+}
+#endif
+
+/* Tftp():
+ * Initiate a tftp transfer at the target (target is client).
+ * Command line:
+ * tftp [options] {IP} {get|put} {file|addr} [len]...
+ * tftp [options] {IP} get file dest_addr
+ * tftp [options] {IP} put addr dest_file len
+ * Currently, only "get" is supported.
+ */
+
+char *TftpHelp[] = {
+ "Trivial file transfer protocol",
+ "-[aF:f:i:vV] [on|off|IP] {get|put filename [addr]} ss",
+#if INCLUDE_VERBOSEHELP
+ " -a use netascii mode",
+ " -F {file} name of tfs file to copy to",
+ " -f {flgs} file flags (see tfs)",
+ " -i {info} file info (see tfs)",
+ " -v verbosity = ticker",
+ " -V verbosity = state",
+#endif
+ 0,
+};
+
+int
+Tftp(int argc,char *argv[])
+{
+ int opt, verbose;
+ char *mode, *file, *info, *flags;
+ ulong addr;
+
+ verbose = 0;
+ file = (char *)0;
+ info = (char *)0;
+ flags = (char *)0;
+ mode = "octet";
+ while ((opt=getopt(argc,argv,"aF:f:i:vV")) != -1) {
+ switch(opt) {
+ case 'a':
+ mode = "netascii";
+ break;
+ case 'f':
+ flags = optarg;
+ break;
+ case 'F':
+ file = optarg;
+ break;
+ case 'i':
+ info = optarg;
+ break;
+ case 'v':
+ verbose |= SHOW_TFTP_TICKER;
+ break;
+ case 'V':
+ verbose |= SHOW_TFTP_STATE;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ if (argc < (optind+1))
+ return(CMD_PARAM_ERROR);
+
+ if (argc == optind+1) {
+ if (!strcmp(argv[optind],"on")) {
+ TftpTurnedOff = 0;
+ TftpGetActive = 0;
+ TftpPutActive = 0; //ss ADDED
+ }
+ else if (!strcmp(argv[optind],"off")) {
+ TftpTurnedOff = 1;
+ TftpGetActive = 0;
+ tftpGotoState(TFTPIDLE);
+ TftpPutActive = 0; //ss ADDED
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ return(CMD_SUCCESS);
+ }
+
+ /* If either the info or flags field has been specified, but the */
+ /* filename is not specified, error here... */
+ if ((info || flags) && (!file)) {
+ printf("Filename missing\n");
+ return(CMD_FAILURE);
+ }
+
+ if (!strcmp(argv[optind+1],"get")) {
+
+ if (argc == optind+4)
+ addr = (ulong)strtol(argv[optind+3],0,0);
+ else if (argc == optind+3)
+ addr = getAppRamStart();
+ else
+ return(CMD_PARAM_ERROR);
+
+ TFTPVERBOSE(EtherVerbose |= verbose);
+ tftpGet(addr,argv[optind],mode,argv[optind+2],file,flags,info);
+ TFTPVERBOSE(EtherVerbose &= ~verbose);
+ }
+ else if (!strcmp(argv[optind+1],"put")) {
+
+ if (argc == (optind+3))
+ file = argv[optind+2];
+ else if (argc == (optind+4))
+ file = argv[optind+3];
+ else
+ return(CMD_PARAM_ERROR);
+
+ TFTPVERBOSE(EtherVerbose |= verbose);
+ tftpPut(argv[optind],mode,file,argv[optind+2],flags,info);
+ TFTPVERBOSE(EtherVerbose &= ~verbose);
+
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+
+void
+ShowTftpStats(void)
+{
+ printf("Current TFTP state: %s\n",tftpStringState(TftpState));
+}
+
+#endif
diff --git a/main/common/time.h b/main/common/time.h
new file mode 100755
index 0000000..f0ae1ce
--- /dev/null
+++ b/main/common/time.h
@@ -0,0 +1,42 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * time.h:
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+typedef long time_t;
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+struct tm *gmtime_r(const time_t t, struct tm* tout);
+char *asctime_r(const struct tm *t, char *buf);
diff --git a/main/common/timer.h b/main/common/timer.h
new file mode 100644
index 0000000..dab62df
--- /dev/null
+++ b/main/common/timer.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * timer.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+struct elapsed_tmr {
+ unsigned long start; // Start value of elapsed timeout.
+ unsigned long tmrval; // Running timer value
+ // (used by elapsed timeout)
+ unsigned long currenttmrval; // Current timer value
+ // (not used by elapsed timeout)
+ unsigned long tpm; // Ticks per millisecond
+
+ unsigned long elapsed_low;
+ unsigned long elapsed_high;
+
+ unsigned long timeout_low;
+ unsigned long timeout_high;
+
+ unsigned long tmrflags;
+};
+
+/* Timer flags:
+ */
+#define HWTMR_ENABLED (1 << 0)
+#define TIMEOUT_OCCURRED (1 << 1)
+
+/* Timer macros:
+ */
+#define HWRTMR_IS_ENABLED(tmr) \
+ ((tmr)->tmrflags & HWTMR_ENABLED)
+
+#define ELAPSED_TIMEOUT(tmr) \
+ ((tmr)->tmrflags & TIMEOUT_OCCURRED)
+
+/* uMon API timer commands:
+ */
+#define TIMER_START 1
+#define TIMER_ELAPSED 2
+#define TIMER_QUERY 3
+
+extern unsigned long target_timer(void);
+extern void startElapsedTimer(struct elapsed_tmr *tmr,long timeout);
+extern int msecElapsed(struct elapsed_tmr *tmr);
+extern unsigned long msecRemaining(struct elapsed_tmr *tmr);
+extern int monTimer(int cmd, void *arg);
+
+#endif
diff --git a/main/common/timestuff.c b/main/common/timestuff.c
new file mode 100755
index 0000000..5cab2d3
--- /dev/null
+++ b/main/common/timestuff.c
@@ -0,0 +1,386 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * timestuff.c
+ *
+ * These functions support the monitor's ability to deal with elapsed
+ * time on targets with or without hardware-timer support.
+ *
+ * The INCLUDE_HWTMR definition in config.h determines which mode
+ * the timer will run in.
+ *
+ * The monitor does not require any hardware-assist for maintaining
+ * elapsed time. With no hardware assist (INCLUDE_HWTMR set to 0),
+ * the value of LOOPS_PER_SECOND must be established in config.h, and
+ * can be calibrated using the '-c' option in the sleep command. Even
+ * with this calibration the accuracy of this mechanism is limited;
+ * however, since there is no code in the monitor that really requires
+ * extremely accurate timing this may be ok.
+ *
+ * On the other hand, it is preferrable to have accuracy, so on targets
+ * that have a pollable clock, the hooks can be put in place to allow
+ * that clock to be used as the hardware assist for the monitor's
+ * elapsed time measurements. The INCLUDE_HWTMR is set to 1, and
+ * TIMER_TICKS_PER_MSEC defines the number of ticks of the timer that
+ * correspond to 1 millisecond of elapsed time. The function target_timer()
+ * is assumed to be established and must return an unsigned long value
+ * that is the content of the polled hardware timer.
+ *
+ * Regardless of the hardware-assist or not, the following interface is
+ * used by the code in the monitor...
+ *
+ * #include "timer.h"
+ *
+ * struct elapsed_tmr tmr;
+ *
+ * startElapsedTimer(&tmr,TIMEOUT):
+ * do {
+ * SOMETHING();
+ * } while(!msecElapsed(&tmr));
+ *
+ * Refer to the functions startElapsedTimer() and msecElapsed() below for
+ * more details.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "genlib.h"
+#include "ether.h"
+#include "timer.h"
+#include "cpuio.h"
+
+/* startElapsedTimer() & msecElapsed():
+ * The timer is started by loading the values timeout_low and timeout_high
+ * with the number of ticks that must elapse for the timer to expire.
+ *
+ * In the case of the non-hardware-assisted timer, the expiration count
+ * is based on the value of LoopsPerMillisecond (derived from the
+ * LOOPS_PER_SECOND definition in config.h). Each time msecElapsed()
+ * is called the elapsed count is incremented until it exceeds the timeout
+ * timeout_low timeout_high values recorded by startElapsedTimer().
+ *
+ * The case of the hardware-assisted timer is similar except that now
+ * the number of ticks initialized in timeout_low and timeout_high are
+ * based on the tick rate of the hardware timer (TIMER_TICKS_PER_MSEC).
+ * This value is expected to be set in config.h. Each time msecElapsed()
+ * is called, it samples the timer and adds to the running total of ticks
+ * until it matches or exceeds the timeout_low and timeout_high values.
+ *
+ * Notice that 64-bit values are used (high & low) because a 32-bit value
+ * isn't large enough to deal with the tick rates (per second) of various
+ * CPUs.
+ */
+void
+startElapsedTimer(struct elapsed_tmr *tmr, long milliseconds)
+{
+ unsigned long new_tm_low;
+ unsigned long stepmsecs, stepticks, remainder;
+
+#if INCLUDE_HWTMR
+ tmr->tmrflags = HWTMR_ENABLED;
+ tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC;
+#else
+ tmr->tmrflags = 0;
+ tmr->tpm = (unsigned long)LoopsPerMillisecond;
+#endif
+
+ tmr->elapsed_low = 0;
+ tmr->elapsed_high = 0;
+ tmr->timeout_high = 0;
+ tmr->timeout_low = 0;
+
+ /* Convert incoming timeout from a millisecond count to a
+ * tick count...
+ * Maximum number of milliseconds and ticks before 32-bit
+ * (tick counter) unsigned long overlaps
+ */
+ stepmsecs = 0xffffffff / tmr->tpm;
+ stepticks = stepmsecs * tmr->tpm;
+ remainder = (milliseconds % stepmsecs);
+
+ /* Take care of the step remainder
+ */
+ tmr->timeout_low = remainder * tmr->tpm;
+ milliseconds -= remainder;
+
+ for (;milliseconds; milliseconds -= stepmsecs) {
+ new_tm_low = tmr->timeout_low + stepticks;
+
+ if (new_tm_low < tmr->timeout_low)
+ tmr->timeout_high++;
+ tmr->timeout_low = new_tm_low;
+ }
+
+#if INCLUDE_HWTMR
+ tmr->tmrval = target_timer();
+#else
+ tmr->tmrval = 0;
+#endif
+
+}
+
+int
+msecElapsed(struct elapsed_tmr *tmr)
+{
+ ulong new_elapsed_low, new_tmrval, elapsed;
+
+ /* If timeout has already occurred, then we can assume that this
+ * function being called without a matching startElapsedTimer() call.
+ */
+ if (ELAPSED_TIMEOUT(tmr))
+ return(1);
+
+#if INCLUDE_HWTMR
+ new_tmrval = target_timer();
+#else
+ new_tmrval = tmr->tmrval + 1;
+#endif
+
+ /* Record how many ticks elapsed since the last call to msecElapsed
+ * and add that value to the total number of ticks that have elapsed.
+ */
+ elapsed = new_tmrval - tmr->tmrval;
+ new_elapsed_low = tmr->elapsed_low + elapsed;
+
+ if (new_elapsed_low < tmr->elapsed_low)
+ tmr->elapsed_high++;
+
+ /* If the total elapsed number of ticks exceeds the timeout number
+ * of ticks, then we can return 1 to indicate that the requested
+ * amount of time has elapsed. Otherwise, we record the values and
+ * return 0.
+ */
+ if ((tmr->elapsed_high >= tmr->timeout_high) &&
+ (new_elapsed_low >= tmr->timeout_low)) {
+ tmr->tmrflags |= TIMEOUT_OCCURRED;
+ return(1);
+ }
+
+ tmr->tmrval = new_tmrval;
+ tmr->elapsed_low = new_elapsed_low;
+ return(0);
+}
+
+/* msecRemainging():
+ * Used to query how many milliseconds were left (if any) in the timeout.
+ */
+ulong
+msecRemaining(struct elapsed_tmr *tmr)
+{
+ ulong high, low, msectot, leftover, divisor;
+
+ if (ELAPSED_TIMEOUT(tmr))
+ return(0);
+
+ high = tmr->timeout_high - tmr->elapsed_high;
+ low = tmr->timeout_low - tmr->elapsed_low;
+
+ msectot = leftover = 0;
+
+#if INCLUDE_HWTMR
+ divisor = (ulong)TIMER_TICKS_PER_MSEC;
+#else
+ divisor = (ulong)LoopsPerMillisecond;
+#endif
+
+ while(1) {
+ while (low > divisor) {
+ msectot++;
+ low -= divisor;
+ }
+ leftover += low;
+ if (high == 0)
+ break;
+ else {
+ high--;
+ low = 0xffffffff;
+ }
+ }
+
+ while(leftover > divisor) {
+ msectot++;
+ low -= divisor;
+ }
+ return(msectot);
+}
+
+/* monDelay():
+ * Delay for specified number of milliseconds.
+ * Refer to msecElapsed() description for a discussion on the
+ * accuracy of this delay.
+ */
+void
+monDelay(int milliseconds)
+{
+ struct elapsed_tmr tmr;
+
+ startElapsedTimer(&tmr,milliseconds);
+ while(!msecElapsed(&tmr)) {
+ WATCHDOG_MACRO;
+ pollethernet();
+ }
+}
+
+/* monTimer():
+ * Provide the API with the ability to start a millisecond-granularity
+ * timer with some countdown value, and poll it waiting for completion.
+ */
+int
+monTimer(int cmd, void *arg)
+{
+ int rc = 0;
+ struct elapsed_tmr *tmr = (struct elapsed_tmr *)arg;
+
+ switch(cmd) {
+ case TIMER_START:
+ startElapsedTimer(tmr,tmr->start);
+ break;
+ case TIMER_ELAPSED:
+ msecElapsed(tmr);
+ if (ELAPSED_TIMEOUT(tmr))
+ rc = 1;
+ break;
+ case TIMER_QUERY:
+#if INCLUDE_HWTMR
+ tmr->tmrflags = HWTMR_ENABLED;
+ tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC;
+ tmr->currenttmrval = target_timer();
+#else
+ tmr->tmrflags = 0;
+ tmr->tpm = (unsigned long)LoopsPerMillisecond;
+ tmr->currenttmrval = 0;
+#endif
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+ return(rc);
+}
+
+#if INCLUDE_TFSSCRIPT
+
+/* Sleep():
+ * Simple delay loop accessible by the command line.
+ * This loop count is dependent on the underlying hardware.
+ * The LoopsPerMillisecond count is loaded with a default at startup, or
+ * it can be calibrated by the user via the -c option.
+ * Note that this LoopsPerMillisecond value is used in a few other places
+ * in the monitor also for time-dependent stuff.
+ * NOTES:
+ * - This is obviously not real accurate (not intended to be), but allows the
+ * monitor to be independent of the underlying hardware.
+ * - The delay time is very dependent on ethernet activity, since the call
+ * to pollethernet() part of the loop.
+ */
+
+
+char *SleepHelp[] = {
+ "Second or msec delay (not precise)",
+ "-[clmv:] {count}",
+#if INCLUDE_VERBOSEHELP
+ " -c calibrate new LPS count",
+ " -l store LPS count",
+ " -m millisecond",
+ " -v {LPSvarname}",
+#endif
+ 0,
+};
+
+int
+Sleep(int argc,char *argv[])
+{
+ int opt, calibrate, count, multiplier;
+
+ multiplier = 1000;
+ calibrate = 0;
+ while ((opt=getopt(argc,argv,"clmv:")) != -1) {
+ switch(opt) {
+ case 'c':
+ calibrate = 2;
+ break;
+ case 'l':
+ calibrate = 1;
+ break;
+ case 'm':
+ multiplier = 1;
+ break;
+ case 'v':
+ shell_sprintf(optarg,"%d",LoopsPerMillisecond*1000);
+ return(CMD_SUCCESS);
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ /* If no args, just print the current LPS value and return... */
+ if (argc == 1) {
+#if INCLUDE_HWTMR
+ printf("Hardware-based timer, LPS not applicable\n");
+#else
+ printf("Current LPS = %ld\n",LoopsPerMillisecond * 1000);
+#endif
+ return(CMD_SUCCESS);
+ }
+
+ /* For calibration, take in the count on the command line, then use
+ * it to put out 5 dots dot at the rate of the loop to allow the user
+ * to adjust it to be about 1 second.
+ */
+ if (calibrate) {
+#if INCLUDE_HWTMR
+ printf("Hardware-based timer, doesn't calibrate\n");
+#else
+ long lps;
+
+ if (argc != optind+1)
+ return(CMD_PARAM_ERROR);
+
+ printf("Current LPS: %ld\n",LoopsPerMillisecond * 1000);
+ lps = strtol(argv[optind],0,0);
+ LoopsPerMillisecond = lps/1000;
+ printf("New LPS: %ld%s\n",LoopsPerMillisecond * 1000,
+ lps % 1000 ? " (truncated by 1000)" : "");
+
+ if (calibrate == 2) {
+ count = 10;
+ while(count-- > 0) {
+ monDelay(1000);
+ putstr(".\007");
+ }
+ putchar('\n');
+ }
+#endif
+ return(CMD_SUCCESS);
+ }
+
+ if (argc == optind)
+ count = 1;
+ else
+ count = strtol(argv[optind],(char **)0,0);
+
+ monDelay(count * multiplier);
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/tsi.c b/main/common/tsi.c
new file mode 100755
index 0000000..dd5a53e
--- /dev/null
+++ b/main/common/tsi.c
@@ -0,0 +1,231 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tsi.c:
+ *
+ * Touch Screen Interface...
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_TSI & INCLUDE_FBI
+#include "genlib.h"
+#include "cli.h"
+#include "fbi.h"
+#include "tsi.h"
+#include "timer.h"
+
+
+int
+tsi_scribble(int width, long color)
+{
+ int x, y, xx, yy, done, last_x, last_y;
+ static int xadjust, yadjust;
+
+ printf("Entering 'scribble' mode, hit any key to terminate...\n");
+
+ last_x = last_y = done = 0;
+ while (!done) {
+ /* Use 'a', 'd', 'w' and 'x' as special input to adjust the
+ * coordinates between touch and frame buffer.
+ */
+ if (gotachar()) {
+ switch(getchar()) {
+ case 'a': // LEFT
+ xadjust--;
+ break;
+ case 'd': // RIGHT
+ xadjust++;
+ break;
+ case 'w': // UP
+ yadjust--;
+ break;
+ case 'x': // DOWN
+ yadjust++;
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+ if (tsi_active()) {
+ x = tsi_getx();
+ y = tsi_gety();
+
+ /* If incoming coordinate is ever more than 'PEN_MOVE_FILTER'
+ * pixels away from the previous position, then assume it
+ * to be noise and don't display it.
+ */
+ if ((x < (last_x + PEN_MOVE_FILTER)) &&
+ (x > (last_x - PEN_MOVE_FILTER)) &&
+ (y < (last_y + PEN_MOVE_FILTER)) &&
+ (y > (last_y - PEN_MOVE_FILTER)))
+ {
+ x += xadjust;
+ y += yadjust;
+ for(xx = x-width;xx <= x+width;xx++) {
+ for(yy = y-width;yy <= y+width;yy++)
+ fbi_setpixel(xx,yy,color);
+ }
+ }
+ last_x = x;
+ last_y = y;
+ }
+ }
+ if ((xadjust != 0) || (yadjust != 0))
+ printf("Xadjust: %d, Yadjust: %d\n",xadjust, yadjust);
+ return(0);
+}
+
+#define WFNT_FILTER 200
+
+char *TsiHelp[] = {
+ "Touch screen interface",
+ "-[v] {cmd} [args...]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -v additive verbosity",
+ "",
+ "Commands:",
+ " scribble {width} {color} # draw on the frame buffer",
+ " wft [msec-timeout] # wait for touch",
+ " wfnt [msec-timeout] # wait for no touch",
+ "",
+ "Notes:",
+ " Shell variable 'TSI_X' and 'TSI_Y' are populated by 'wft'.",
+#endif
+ 0,
+};
+
+int
+TsiCmd(int argc,char *argv[])
+{
+ static int tsiInitialized;
+ int opt, verbose;
+ char *cmd, *arg1;
+ static struct elapsed_tmr tmr;
+
+ // Make sure the touch-screen interface is initialized...
+ if (!tsiInitialized) {
+ if (tsi_init() == -1) {
+ printf("Error intializing touch screen!\n");
+ return(CMD_FAILURE);
+ }
+ tsiInitialized = 1;
+ }
+ verbose = 0;
+ while((opt=getopt(argc,argv,"v")) != -1) {
+ switch(opt) {
+ case 'v':
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+ if (argc < optind + 1)
+ return(CMD_FAILURE);
+
+ cmd = argv[optind];
+ arg1 = argv[optind+1];
+
+ if (strcmp(cmd,"scribble") == 0) {
+ int width;
+ long color;
+
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+
+ width = strtol(arg1,0,0);
+ color = strtol(argv[optind+2],0,0);
+ tsi_scribble(width,color);
+ }
+ else if (strcmp(cmd,"wfnt") == 0) {
+ int x, y;
+ int filter, ftot;
+
+ if (argc == optind+2) {
+ int timeout = strtol(arg1,0,0);
+
+ startElapsedTimer(&tmr,timeout);
+ while(1) {
+ x = tsi_getx();
+ y = tsi_gety();
+ if (!tsi_active()) {
+ for(ftot=0,filter=0;filter<WFNT_FILTER;filter++)
+ ftot += tsi_active() ? 0 : 1;
+ if (ftot == WFNT_FILTER)
+ break;
+ }
+ if(msecElapsed(&tmr)) {
+ x = y = -1;
+ break;
+ }
+ }
+ }
+ else {
+ while(1) {
+ x = tsi_getx();
+ y = tsi_gety();
+ if (!tsi_active()) {
+ for(ftot=0,filter=0;filter<WFNT_FILTER;filter++)
+ ftot += tsi_active() ? 0 : 1;
+ if (ftot == WFNT_FILTER)
+ break;
+ }
+ }
+ }
+ shell_sprintf("TSI_X","%d",x);
+ shell_sprintf("TSI_Y","%d",y);
+ }
+ else if (strcmp(cmd,"wft") == 0) {
+ int x, y;
+
+ if (argc == optind+2) {
+ int timeout = strtol(arg1,0,0);
+
+ startElapsedTimer(&tmr,timeout);
+ while(1) {
+ if (tsi_active()) {
+ x = tsi_getx();
+ y = tsi_gety();
+ break;
+ }
+ if(msecElapsed(&tmr)) {
+ x = y = -1;
+ break;
+ }
+ }
+ }
+ else {
+ while(!tsi_active());
+ x = tsi_getx();
+ y = tsi_gety();
+ }
+ shell_sprintf("TSI_X","%d",x);
+ shell_sprintf("TSI_Y","%d",y);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+#endif
diff --git a/main/common/tsi.h b/main/common/tsi.h
new file mode 100644
index 0000000..4156415
--- /dev/null
+++ b/main/common/tsi.h
@@ -0,0 +1,35 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * tsi.h:
+ *
+ * Header file for the touch-screen-interface code.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+extern int tsi_init(void);
+extern int tsi_active(void);
+extern int tsi_getx(void);
+extern int tsi_gety(void);
+
+#ifndef PEN_MOVE_FILTER
+#define PEN_MOVE_FILTER 15
+#endif
diff --git a/main/common/umongpio.h b/main/common/umongpio.h
new file mode 100644
index 0000000..c58f1cb
--- /dev/null
+++ b/main/common/umongpio.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * gpio.h
+ * DESCRIPTION HERE
+ * A common way of looking at general purpose IO.
+ *
+ * This header is included by all code that uses uMon's general purpose
+ * GPIO interface mechanism. The idea is as follows:
+ * Each bit has two values associated with it:
+ *
+ * bit:
+ * The bit number within the register it is assigned (starting from 0).
+ *
+ * vbit:
+ * The bit number within a device which may have multiple registers of GPIO.
+ * For example, if a device has three 32-bit registers for GPIO, then there
+ * would be a total of 96 port numbers where 0-31 represent the bits of
+ * register 0, 32-63 represetnt the bits of register 1 and 64
+ *
+ * For each bit, the GPIO(vbit,bit) macro uses fields within a 32-bit value to
+ * define this information; hence, one 32-bit value contains both the register
+ * and device specific bit position.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _UMONGPIO_H_
+#define _UMONGPIO_H_
+
+#define GPIO_BITNUM_MASK 0x000000ff
+#define GPIO_VBITNUM_MASK 0xffff0000
+#define GPIO(vbit,bit) (((vbit << 16) & GPIO_VBITNUM_MASK) | \
+ (bit & GPIO_BITNUM_MASK))
+#define GPIOVBIT(val) ((val & GPIO_VBITNUM_MASK) >> 16)
+#define GPIOBIT(val) (1 << (val & GPIO_BITNUM_MASK))
+
+extern void GPIO_init(void);
+
+/* Each of these functions uses the "virtual" bit number...
+ */
+extern int GPIO_set(int vbit);
+extern int GPIO_clr(int vbit);
+extern int GPIO_tst(int vbit);
+extern int GPIO_in(int vbit);
+extern int GPIO_out(int vbit);
+
+#endif
diff --git a/main/common/version.h b/main/common/version.h
new file mode 100644
index 0000000..9eb1b9f
--- /dev/null
+++ b/main/common/version.h
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * version.h:
+ *
+ * MicroMonitor started using a version number as of December 2004.
+ * Since it has been around for quite some time, the initial version
+ * number is: 1.0.1.1
+ * The version number for MicroMonitor is 4 'dot' separated numbers.
+ * Each number can be as large as is needed.
+ *
+ * MAJOR_VERSION.MINOR_VERSION.BUILD_NUMBER.TARGET_VERSION
+
+ * MAJOR, MINOR & BUILD apply to the common code applicable to all targets.
+ * TARGET applies to the target-specific code.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _VERSION_H_
+#define _VERSION_H_
+
+/* MAJOR_VERSION:
+ * Incremented as a result of a major change or enhancement to the core
+ * monitor code or as a means of dropping the MINOR_VERSION back to zero;
+ * hence, simply identifying a significant set of MINOR changes or some
+ * big change.
+ */
+#define MAJOR_VERSION 1
+
+/* MINOR_VERSION:
+ * Incremented as a result of a new command or feature, or as a result
+ * of a bug fix to the core monitor code.
+ * When MAJOR_VERSION is incremented, MINOR_VERSION is reset to 0.
+ * 0->1:
+ * Formalize the uMon1.0 transition. Needed to do this because of the
+ * amount of churn in 1.0.
+ * 1->2:
+ * - New 'call -A' option
+ * - Work on flash internals to reduce the need for callers to know
+ * the flash bank pointer.
+ * - New tfs 'qclean' subcommand.
+ * - Bug fix: file in "tfs ramdev" space could not be marked stale.
+ * 2->3:
+ * - Bug fix: uMonInRam() re-write.
+ * - Bug fix: "tfs ramdev" device would be lost after mon_appexit().
+ * - Bug fix: "tfs ramdev" naming conflict could occur between device
+ * and file.
+ * 3->4:
+ * - The tfscheck() function accepts a NULL input TDEV pointer to signify
+ * a request to check all TFS devices (instead of just one named device).
+ * - The address used by xmodem -B for determining the last sector burned
+ * had to be decremented by 1.
+ * 4->5:
+ * - The "flash erase" command takes addresses as well as sector numbers.
+ * - The "flash info" and "tfs stat" populate shellvars with their info.
+ * - Bug fix: tftp get would turn on the server, now fixed so that if
+ * server was off, it stays off.
+ * - Bug fix: if destination file received by tftp server started with
+ * a $, but the shell variable didn't exist, the server would create
+ * a file with the $. This will now generate an error.
+ * 5->6:
+ * - Added more configurability so that uMon's footprint can be smaller.
+ * - Broke up memcmds.c into individually configurable commands using
+ * INCLUDE_DM, INCLUDE_PM, etc.
+ * - Added support to configure USRLVL, ICMP, and ICMPTIME in or out.
+ * - TFS now supports the option of being built without FLASH.
+ * - New read options: -p -n.
+ * - New pm options: -a -o -x.
+ * - New PRE_TFSAUTOBOOT_HOOK() macro.
+ * - Converted genlib.c to a library.
+ * - New api: mon_portcmd().
+ * 6->7:
+ * - New JFFS2 command.
+ * - New TFSERR_DSIMAX error checking in tfsmemuse() and tfsadd().
+ * - Eliminated the -x option in tfs command.
+ * - The tfs command now returns CMD_FAILURE if tfsadd fails.
+ * - Moncmd server will process a leading '.' as indication that the
+ * command is to be executed immediately rather than after the
+ * incoming packet queue is empty.
+ * 7->8:
+ * - New TFS_ALTDEVTBL_BASE code to support an alternat TFS device table
+ * that is outside uMon's text/data space.
+ * - Fixed bug in JFFS2 related to file truncation.
+ * 8->9:
+ * - New DOSFS/FATFS/CF facility (much help from Graham Henderson).
+ * - CodeWarrior-specific code cleanup (submitted by Arun Biyani).
+ * - Atmel NIOS port (submitted by Graham Henderson).
+ * 9->10:
+ * - New 'struct' command to hopefully eliminate 'lboot' and 'ldatags'.
+ * 10->11:
+ * - Fixed problems with packet transfer interface.
+ * - Updated the umon_apps/udp application.
+ * - New Microblaze port (as3dev).
+ * 11->12:
+ * - Added the 'to' side of the ARP request in ethernet verbosity.
+ * - Fixed bugs in tcpstuff.c that were only seen on little-endian CPUs.
+ * - Added the ability to load an elf file from raw memory space. This
+ * introduces the notion of a 'fake' tfs file header to tfs, using the
+ * first reserved entry in the header as a pointer to the data portion
+ * of the file.
+ * 12->14:
+ * - Added new DHCP shell variable ROOTPATH (reflects option 17).
+ * - New DHCP variable: DHCPDONTBOOT. Tells DHCP not to do anything with
+ * the incoming DHCP transaction (except store away the info in the
+ * shell variables); thus, allowing a script to do what it wants to do.
+ * - Change in TFTP server: if an out-of-sequence block number is received,
+ * it is now just ignored, the transaction doesn't terminate with an error.
+ * - Added inUmonBssSpace() check to the heap extension code.
+ * - Fixed bug in "tfs ramdev" command... If partition didn't exist and
+ * a size of zero was specified, TFS incorrectly attempted to create a
+ * zero-size ramdev partition.
+ * - Fixed bug in multiple-command-line-processing that occurs if a
+ * shell variable is expanded within one of the commands. See CVS
+ * log for docmd.c for more info.
+ * 14->15:
+ * - Fixed a bug in TFTP packet reception that was causing all incoming
+ * file downloads greater than 32Mg to fail because that is the point
+ * at which the block number will wrap.
+ * - Updates/cleanups made to keep the build warning-free with GCC 4.2
+ * from Microcross.
+ * 15->16:
+ * - Added lwip user application.
+ * - Added better exception handling to blackfin.
+ * - Added mon_timer() api.
+ * 16->17:
+ * - Lotta new stuff, refer to user manual for complete list...
+ * - Lwipapp: httpget, telnet client.
+ * - Tested support for nor-less system (booting from SPI flash).
+ * - TSI, FBI, mDNS, LLAD, etc...
+ * 17->18:
+ * - Refer to user manual for complete list...
+ * - SPI-SD support for BF537.
+ * - New FATFS
+ * - SPI-resident TFS support.
+ * - JFFS2 extended by B.Gatliff
+ * 18->19:
+ * - Refer to user manual for complete list...
+ * - TFS defrag bug fixes.
+ */
+#define MINOR_VERSION 19
+
+/* TARGET_VERSION:
+ * Incremented as a result of a bug fix or change made to the
+ * target-specific (i.e. port) portion of the code.
+ *
+ * To keep a "cvs-like" log of the changes made to a port that is
+ * not under CVS, it is recommended that the target_version.h file be
+ * used as the log to keep track of changes in one place.
+ */
+#include "target_version.h"
+
+#endif
diff --git a/main/common/warmstart.h b/main/common/warmstart.h
new file mode 100644
index 0000000..50300eb
--- /dev/null
+++ b/main/common/warmstart.h
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * warmstart.h:
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#ifndef _WARMSTART_H_
+
+/* Standard restart (warmstart) definitions used by monitor... */
+#define EXCEPTION (1<<4)
+#define INITIALIZE (3<<4)
+#define APPLICATION (5<<4)
+#define APP_EXIT (9<<4)
+
+#endif
diff --git a/main/common/xmodem.c b/main/common/xmodem.c
new file mode 100644
index 0000000..38ba48b
--- /dev/null
+++ b/main/common/xmodem.c
@@ -0,0 +1,855 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * xmodem.c:
+ *
+ * Command to upload or download via XMODEM protocol. Xmodem is quite
+ * limited, but adequate for simple file up/down load.
+ * This also supports XMODEM-1K and YMODEM. YMODEM is an extension to XMODEM
+ * that uses a 1K packet size, CRC and the first packet (seqno=0) contains
+ * information about the file being downloaded (in partiuclar, the name).
+ * YMODEM also supports BATCH downloads (multiple files downloaded in one
+ * transaction). This code supports incoming BATCH downloads (not tested
+ * because I can't find any terminal emulators that do it), but not for
+ * uploads.
+
+ * Minicom notes:
+ * Minicom is the terminal emulation program that comes with Linux.
+ * For some reason I had to make some adjustments to the xmodem.c
+ * to accommodate Minicom...
+ * - Minicom sends an initial 0x1a (EOF). Not sure why, so I just absorb
+ * that now.
+ * - Minicom doesn't like a fast nak-resend rate, so each additional
+ * 'd' option on the xmodem command line now causes the delay
+ * between outgoing NAKs (used to start up the protocol in Xdown())
+ * to double. As a result, when running with minicom, a file download
+ * may need "xmodem -ddd". Not exactly sure why this is necessary but
+ * here's my hunch...
+ * To do an xmodem transfer to the target running uMon, the "xmodem -d"
+ * command is issued on the uMon command line. This causes uMon to start
+ * generating periodic NAKs (part of the xmodem startup handshake).
+ * Then via CTRL-A Z, the minicom side of the transaction starts up.
+ * Apparently, minicom doesn't flush the input buffer when the xmodem
+ * transfer is started on its side. As a result there may be several
+ * NAKs buffered up on the TTY. The end result is that if too many
+ * NAKs have been queued up in the TTY's buffer, Minicom chokes on
+ * them at startup.
+ * Adding the ability to slow down the NAK send rate keeps uMon from
+ * sending too many NAKs prior to Minicom actually starting up its
+ * side of the protocol; hence, Minicom doesn't choke and the transfer
+ * works ok.
+ *
+ * By default, this code will disable the ethernet interface
+ * during the xmodem transaction. This is done because in most
+ * cases the monitor runs with no flow control; and getchar polls
+ * the ethernet interface. If the poll results in an incoming
+ * packet, then it may cause the serial port to lose characters.
+ * If this is not desireable (or if the uart has a large input fifo),
+ * then this can be changed with the DONT_DISABLE_ENET_IN_XMODEM
+ * #define set up in config.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "flash.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+#include "ether.h"
+#include "timer.h"
+
+#if INCLUDE_XMODEM
+
+#define PUTCHAR putchar
+
+
+/* struct xinfo:
+ * Used to contain information pertaining to the current transaction.
+ * The structure is built by the command Xmodem, then passed to the other
+ * support functions (Xup, Xdown, etc..) for reference and update.
+ */
+struct xinfo {
+ uchar sno; /* Sequence number. */
+ uchar pad; /* Unused, padding. */
+ int xfertot; /* Running total of transfer. */
+ int pktlen; /* Length of packet (128 or 1024). */
+ int pktcnt; /* Running tally of number of packets processed. */
+ int filcnt; /* Number of files transferred by ymodem. */
+ long size; /* Size of upload. */
+ ulong flags; /* Storage for various runtime flags. */
+ ulong base; /* Starting address for data transfer. */
+ ulong dataddr; /* Running address for data transfer. */
+ int errcnt; /* Keep track of errors (used in verify mode). */
+ int nakresend; /* Time between each NAK sent at Xdown startup. */
+ char *firsterrat; /* Pointer to location of error detected when */
+ /* transfer is in verify mode. */
+ char fname[TFSNAMESIZE];
+};
+
+/* Runtime flags: */
+#define USECRC (1<<0)
+#define VERIFY (1<<1)
+#define YMODEM (1<<2)
+
+/* Current xmodem operation: */
+#define XNULL 0
+#define XUP 1
+#define XDOWN 2
+
+/* X/Ymodem protocol: */
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define NAK 0x15
+#define CAN 0x18
+#define EOF 0x1a
+#define ESC 0x1b
+
+#define PKTLEN_128 128
+#define PKTLEN_1K 1024
+
+#define BYTE_TIMEOUT 1000
+
+static int Xup(struct xinfo *);
+static int Xdown(struct xinfo *);
+static int getPacket(uchar *,struct xinfo *);
+static int putPacket(uchar *,struct xinfo *);
+
+char *XmodemHelp[] = {
+ "Xmodem file transfer",
+ "-[a:BcdF:f:i:ks:uvy]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -a{##} address (overrides default of APPRAMBASE)",
+#if INCLUDE_FLASH
+ " -B boot sector reload",
+#endif
+ " -c use crc (default = checksum)",
+ " -d download",
+#if INCLUDE_TFS
+ " -F{name} filename",
+ " -f{flags} file flags (see tfs)",
+ " -i{info} file info (see tfs)",
+#endif
+ " -k force packet length to 1K",
+ " -s{##} size (overrides computed size)",
+ " -u upload",
+ " -v verify only",
+#if INCLUDE_TFS
+ " -y use Ymodem extensions",
+#endif
+ "Notes:",
+ " * Either -d or -u must be specified (-B implies -d).",
+ " * Each additional 'd' option cuts the nak-resend rate in half.",
+ " * XMODEM forces a 128-byte modulo on file size. The -s option",
+ " can be used to override this when transferring a file to TFS.",
+ " * File upload requires no address or size (size will be mod 128).",
+ " * When using -B, it should be the ONLY command line option,",
+ " it's purpose is to reprogram the boot sector, so be careful!",
+#endif
+ (char *)0,
+};
+
+int
+Xmodem(int argc,char *argv[])
+{
+ int opt, xop;
+ struct xinfo xi;
+ char *info, *flags;
+#if INCLUDE_TFS
+ TFILE *tfp;
+#endif
+#if INCLUDE_FLASH
+ int newboot = 0;
+#endif
+#if INCLUDE_ETHERNET
+ int eon;
+#endif
+
+ xop = XNULL;
+ info = (char *)0;
+ flags = (char *)0;
+ xi.fname[0] = 0;
+ xi.size = 0;
+ xi.flags = 0;
+ xi.filcnt = 0;
+ xi.nakresend = 2;
+ xi.pktlen = PKTLEN_128;
+ xi.base = xi.dataddr = getAppRamStart();
+ while ((opt=getopt(argc,argv,"a:BcdF:f:i:ks:uvy")) != -1) {
+ switch(opt) {
+ case 'a':
+ xi.dataddr = xi.base = strtoul(optarg,(char **)0,0);
+ break;
+ case 'B':
+ xop = XDOWN;
+#if INCLUDE_FLASH
+ newboot = 1;
+#endif
+ break;
+ case 'c':
+ xi.flags |= USECRC;
+ break;
+ case 'd':
+ xi.nakresend *= 2; /* -ddd increases Xdown() resend delay */
+ xop = XDOWN;
+ break;
+#if INCLUDE_TFS
+ case 'F':
+ strncpy(xi.fname,optarg,TFSNAMESIZE);
+ break;
+ case 'f':
+ flags = optarg;
+ break;
+ case 'i':
+ info = optarg;
+ break;
+#endif
+ case 'k':
+ xi.pktlen = PKTLEN_1K;
+ break;
+ case 's':
+ xi.size = strtol(optarg,(char **)0,0);
+ break;
+ case 'u':
+ xop = XUP;
+ break;
+ case 'v':
+ xi.flags |= VERIFY;
+ break;
+#if INCLUDE_TFS
+ case 'y':
+ xi.flags |= (YMODEM | USECRC);
+ xi.pktlen = PKTLEN_1K;
+ break;
+#endif
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ /* There should be no arguments after the option list. */
+ if (argc != optind)
+ return(CMD_PARAM_ERROR);
+
+ if (xop == XUP) {
+ if ((xi.flags & YMODEM) && !(xi.fname[0]))
+ printf("Ymodem upload needs filename\n");
+ else {
+ if (xi.fname[0]) { /* Causes -a and -s options to be ignored. */
+#if INCLUDE_TFS
+ tfp = tfsstat(xi.fname);
+ if (!tfp) {
+ printf("%s: file not found\n",xi.fname);
+ return(CMD_FAILURE);
+ }
+ xi.base = xi.dataddr = (ulong)TFS_BASE(tfp);
+ xi.size = TFS_SIZE(tfp);
+#endif
+ }
+#ifdef DONT_DISABLE_ENET_IN_XMODEM /* See note at top of file */
+ Xup(&xi);
+#else
+#if INCLUDE_ETHERNET
+ eon = DisableEthernet();
+#endif
+ Xup(&xi);
+#if INCLUDE_ETHERNET
+ if (eon)
+ EthernetStartup(0,0);
+#endif
+#endif
+ }
+ }
+ else if (xop == XDOWN) {
+ long tmpsize;
+
+ if ((xi.flags & YMODEM) && (xi.fname[0]))
+ printf("Ymodem download gets name from protocol, '%s' ignored\n",
+ xi.fname);
+
+#ifdef DONT_DISABLE_ENET_IN_XMODEM /* See note at top of file */
+ tmpsize = (long)Xdown(&xi);
+#else
+#if INCLUDE_ETHERNET
+ eon = DisableEthernet();
+#endif
+ tmpsize = (long)Xdown(&xi);
+#if INCLUDE_ETHERNET
+ if (eon)
+ EthernetStartup(0,0);
+#endif
+#endif
+ if (tmpsize == -1)
+ return(CMD_FAILURE);
+ if ((!xi.size) || (tmpsize < 0))
+ xi.size = tmpsize;
+
+#if INCLUDE_TFS
+ if ((xi.fname[0]) && (xi.size > 0)) {
+ int err;
+
+ printf("Writing to file '%s'...\n",xi.fname);
+ err = tfsadd(xi.fname,info,flags,(uchar *)xi.base,xi.size);
+ if (err != TFS_OKAY) {
+ printf("%s: %s\n",xi.fname,(char *)tfsctrl(TFS_ERRMSG,err,0));
+ return(CMD_FAILURE);
+ }
+ }
+#if INCLUDE_FLASH
+ else
+#endif
+#endif
+#if INCLUDE_FLASH
+ if ((newboot) && (xi.size > 0)) {
+ extern int FlashProtectWindow;
+ int rc;
+ char *bb;
+ ulong bootbase;
+
+ bb = getenv("BOOTROMBASE");
+ if (bb)
+ bootbase = strtoul(bb,0,0);
+ else
+ bootbase = BOOTROM_BASE;
+#ifdef TO_FLASH_ADDR
+ /* The address the program is linked to is not necessarily the
+ * physical address where flash operations can be performed on.
+ * A typical use could be that the program is linked to run in
+ * a cacheable region but writing to the flash can only be done
+ * in an uncached region.
+ * "config.h" is a good place to define the TO_FLASH_ADDR macro.
+ */
+ bootbase = (ulong)TO_FLASH_ADDR(bootbase);
+#endif
+ printf("Reprogramming boot @ 0x%lx from 0x%lx, %ld bytes.\n",
+ bootbase,xi.base,xi.size);
+ if (askuser("OK?")) {
+ int first, last;
+
+ /* If sector(s) need to be unlocked, do that now...
+ */
+ if (addrtosector((uchar *)bootbase,&first,0,0) == -1)
+ return(CMD_FAILURE);
+
+ if (addrtosector((uchar *)bootbase+xi.size-1,&last,0,0) == -1)
+ return(CMD_FAILURE);
+
+ if (flashlock(first,FLASH_LOCKABLE) != -1) {
+ FlashProtectWindow = 1;
+ while(first < last)
+ flashlock(first++,FLASH_UNLOCK);
+ }
+
+ FlashProtectWindow = 1;
+ rc = flashewrite((uchar *)bootbase,(uchar *)xi.base,xi.size);
+ if (rc == -1) {
+ printf("failed\n");
+ return(CMD_FAILURE);
+ }
+ }
+ }
+#endif
+ }
+ else
+ return(CMD_PARAM_ERROR);
+ shell_sprintf("XMODEMGET","%ld",xi.size);
+ return(CMD_SUCCESS);
+}
+
+/* xgetchar():
+ * Wrap getchar with a timer, so that after 5 seconds of waiting
+ * we giveup...
+ */
+int
+xgetchar(char *cp, int lno)
+{
+ struct elapsed_tmr tmr;
+
+ startElapsedTimer(&tmr,5000);
+ while(!msecElapsed(&tmr) && !gotachar());
+ if (!gotachar()) {
+ Mtrace("Xgetchar tmt %d",lno);
+ return(-1);
+ }
+ *cp = getchar();
+ return(0);
+}
+
+/* putPacket():
+ * Used by Xup to send packets.
+ */
+static int
+putPacket(uchar *tmppkt, struct xinfo *xip)
+{
+ char c;
+ int i;
+ ushort chksm;
+
+ chksm = 0;
+
+ if (xip->pktlen == PKTLEN_128)
+ PUTCHAR(SOH);
+ else
+ PUTCHAR(STX);
+
+ PUTCHAR((char)(xip->sno));
+ PUTCHAR((char)~(xip->sno));
+
+ if (xip->flags & USECRC) {
+ for(i=0;i<xip->pktlen;i++) {
+ PUTCHAR((char)*tmppkt);
+ chksm = (chksm<<8)^xcrc16tab[(chksm>>8)^*tmppkt++];
+ }
+ /* An "endian independent way to extract the CRC bytes. */
+ PUTCHAR((char)(chksm >> 8));
+ PUTCHAR((char)chksm);
+ }
+ else {
+ for(i=0;i<xip->pktlen;i++) {
+ PUTCHAR((char)*tmppkt);
+ chksm = ((chksm+*tmppkt++)&0xff);
+ }
+ PUTCHAR((char)(chksm&0x00ff));
+ }
+
+ if (xgetchar(&c,__LINE__) == -1) /* Wait for ack */
+ return(-1);
+
+ /* If pktcnt == -1, then this is the first packet sent by
+ * YMODEM (filename) and we must wait for one additional
+ * character in the response.
+ */
+ if (xip->pktcnt == -1) {
+ if (xgetchar(&c,__LINE__) == -1)
+ return(-1);
+ }
+ return((int)c);
+}
+
+/* getPacket():
+ * Used by Xdown to retrieve packets.
+ */
+static int
+getPacket(uchar *tmppkt, struct xinfo *xip)
+{
+ char *pkt;
+ int i,rcvd;
+ uchar seq[2];
+
+ if ((rcvd = getbytes_t((char *)seq,2,BYTE_TIMEOUT)) != 2) {
+ PUTCHAR(NAK);
+ Mtrace("RCVD %d != 2",rcvd);
+ return(0);
+ }
+
+ if (xip->flags & VERIFY) {
+ rcvd = getbytes_t((char *)tmppkt,xip->pktlen,BYTE_TIMEOUT);
+ if (rcvd != xip->pktlen) {
+ PUTCHAR(NAK);
+ Mtrace("RCVD %d != %d",rcvd,xip->pktlen);
+ return(0);
+ }
+ for(i=0;i<xip->pktlen;i++) {
+ if (tmppkt[i] != ((char *)xip->dataddr)[i]) {
+ if (xip->errcnt++ == 0)
+ xip->firsterrat = (char *)(xip->dataddr+i);
+ }
+ }
+ pkt = (char *)tmppkt;
+ }
+ else {
+ rcvd = getbytes_t((char *)xip->dataddr,xip->pktlen,BYTE_TIMEOUT);
+ if (rcvd != xip->pktlen) {
+ PUTCHAR(NAK);
+ Mtrace("RCVD %d != %d",rcvd,xip->pktlen);
+ return(0);
+ }
+ pkt = (char *)xip->dataddr;
+ }
+
+ if (xip->flags & USECRC) {
+ char c;
+ ushort crc, xcrc;
+
+ /* An "endian independent way to combine the CRC bytes. */
+ if (xgetchar(&c,__LINE__) == -1)
+ return(0);
+ crc = (ushort)c;
+ crc <<= 8;
+ if (xgetchar(&c,__LINE__) == -1)
+ return(0);
+ crc += (ushort)c;
+ xcrc = xcrc16((uchar *)pkt,(ulong)(xip->pktlen));
+ if (crc != xcrc) {
+ PUTCHAR(NAK);
+ Mtrace("CRC %04x != %04x",crc,xcrc);
+ return(0);
+ }
+ }
+ else {
+ uchar csum, xcsum;
+
+ if (xgetchar((char *)&xcsum,__LINE__) == -1)
+ return(0);
+ csum = 0;
+ for(i=0;i<xip->pktlen;i++)
+ csum += *pkt++;
+ if (csum != xcsum) {
+ PUTCHAR(NAK);
+ Mtrace("CSUM %02x != %02x (%d)",csum,xcsum,xip->pktlen);
+ return(0);
+ }
+ Mtrace("CSUM %02x (%d)",csum,xip->pktlen);
+ }
+
+ /* Test the sequence number compliment...
+ */
+ if ((uchar)seq[0] != (uchar)~seq[1]) {
+ PUTCHAR(NAK);
+ Mtrace("SNOCMP %02x != %02x",(uchar)seq[0],(uchar)~(seq[1]));
+ return(0);
+ }
+
+ /* Verify that the incoming sequence number is the expected value...
+ */
+ if ((uchar)seq[0] != xip->sno) {
+ /* If the incoming sequence number is one less than the expected
+ * sequence number, then we assume that the sender did not recieve
+ * our previous ACK, and they are resending the previously received
+ * packet. In that case, we send ACK and don't process the
+ * incoming packet...
+ */
+ if ((uchar)seq[0] == xip->sno-1) {
+ Mtrace("R_ACK");
+ PUTCHAR(ACK);
+ return(0);
+ }
+
+ /* Otherwise, something's messed up...
+ */
+ PUTCHAR(CAN);
+ Mtrace("SNO: %02x != %02x",seq[0],xip->sno);
+ return(-1);
+ }
+
+ /* First packet of YMODEM contains information about the transfer:
+ * FILENAME SP FILESIZE SP MOD_DATE SP FILEMODE SP FILE_SNO
+ * Only the FILENAME is required and if others are present, then none
+ * can be skipped.
+ */
+ if ((xip->flags & YMODEM) && (xip->pktcnt == 0)) {
+ char *slash, *space, *fname;
+
+ slash = strrchr((char *)(xip->dataddr),'/');
+ space = strchr((char *)(xip->dataddr),' ');
+ if (slash)
+ fname = slash+1;
+ else
+ fname = (char *)(xip->dataddr);
+ Mtrace("<fname=%s>",fname);
+ if (space) {
+ *space = 0;
+ xip->size = atoi(space+1);
+ }
+ strcpy(xip->fname,fname);
+ if (fname[0])
+ xip->filcnt++;
+ }
+ else
+ xip->dataddr += xip->pktlen;
+ xip->sno++;
+ xip->pktcnt++;
+ xip->xfertot += xip->pktlen;
+ Mtrace("ACK");
+ PUTCHAR(ACK);
+ if (xip->flags & YMODEM) {
+ if (xip->fname[0] == 0) {
+ printf("\nRcvd %d file%c\n",
+ xip->filcnt,xip->filcnt > 1 ? 's' : ' ');
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/* Xup():
+ * Called when a transfer from target to host is being made (considered
+ * an upload).
+ */
+static int
+Xup(struct xinfo *xip)
+{
+ uchar c, buf[PKTLEN_128];
+ int tmp, done, pktlen;
+
+ Mtrace("Xup starting");
+
+ if (xip->size & 0x7f) {
+ xip->size += 128;
+ xip->size &= 0xffffff80L;
+ }
+
+ printf("Upload %ld bytes from 0x%lx\n",xip->size,(ulong)xip->base);
+
+ /* Startup synchronization... */
+ /* Wait to receive a NAK or 'C' from receiver. */
+ done = 0;
+ while(!done) {
+ if (xgetchar((char *)&c,__LINE__) == -1)
+ return(0);
+ switch(c) {
+ case NAK:
+ done = 1;
+ Mtrace("CSM");
+ break;
+ case 'C':
+ xip->flags |= USECRC;
+ done = 1;
+ Mtrace("CRC");
+ break;
+ case 'q': /* ELS addition, not part of XMODEM spec. */
+ return(0);
+ default:
+ break;
+ }
+ }
+
+ rawon();
+
+ if (xip->flags & YMODEM) {
+ Mtrace("SNO_0");
+ xip->sno = 0;
+ xip->pktcnt = -1;
+ memset((char *)buf,0,PKTLEN_128);
+ sprintf((char *)buf,"%s",xip->fname);
+ pktlen = xip->pktlen;
+ xip->pktlen = PKTLEN_128;
+ if (putPacket(buf,xip) == -1)
+ return(0);
+ xip->pktlen = pktlen;
+ }
+
+ done = 0;
+ xip->sno = 1;
+ xip->pktcnt = 0;
+ while(!done) {
+ if ((tmp = putPacket((uchar *)(xip->dataddr),xip)) == -1)
+ return(0);
+ c = (uchar)tmp;
+ switch(c) {
+ case ACK:
+ xip->sno++;
+ xip->pktcnt++;
+ xip->size -= xip->pktlen;
+ xip->dataddr += xip->pktlen;
+ Mtrace("A");
+ break;
+ case NAK:
+ Mtrace("N");
+ break;
+ case CAN:
+ done = -1;
+ Mtrace("C");
+ break;
+ case EOT:
+ done = -1;
+ Mtrace("E");
+ break;
+ default:
+ done = -1;
+ Mtrace("<%02x>",c);
+ break;
+ }
+ if (xip->size <= 0) {
+ char tmp;
+
+ PUTCHAR(EOT);
+ if (xgetchar(&tmp,__LINE__) == -1) /* Flush the ACK */
+ return(0);
+ break;
+ }
+ Mtrace("!");
+ }
+
+ Mtrace("Xup_almost");
+ if ((done != -1) && (xip->flags & YMODEM)) {
+ xip->sno = 0;
+ memset((char *)buf,0,PKTLEN_128);
+ pktlen = xip->pktlen;
+ xip->pktlen = PKTLEN_128;
+ if (putPacket(buf,xip) == -1)
+ return(0);
+ xip->pktlen = pktlen;
+ }
+ Mtrace("Xup_done.");
+ rawoff();
+ return(0);
+}
+
+
+/* Xdown():
+ * Called when a transfer from host to target is being made (considered
+ * an download).
+ * Note that if we don't have INCLUDE_MALLOC set (in config.h), then
+ * we allocate a 128-byte static buffer and only support the 128-byte
+ * packet size here.
+ */
+
+static int
+Xdown(struct xinfo *xip)
+{
+ struct elapsed_tmr tmr;
+ char c, *tmppkt;
+ int i, done;
+#if !INCLUDE_MALLOC
+ static char pkt[PKTLEN_128];
+
+ tmppkt = pkt;
+#else
+ tmppkt = malloc(PKTLEN_1K);
+ if (!tmppkt) {
+ Mtrace("malloc failed");
+ return(-1);
+ }
+#endif
+
+ rawon();
+
+nextfile:
+ if (xip->flags & YMODEM)
+ xip->sno = 0x00;
+ else
+ xip->sno = 0x01;
+ xip->pktcnt = 0;
+ xip->errcnt = 0;
+ xip->xfertot = 0;
+ xip->firsterrat = 0;
+
+ /* Startup synchronization... */
+ /* Continuously send NAK or 'C' until sender responds. */
+restart:
+ Mtrace("Xdown");
+ for(i=0;i<32;i++) {
+ if (xip->flags & USECRC)
+ PUTCHAR('C');
+ else
+ PUTCHAR(NAK);
+
+ startElapsedTimer(&tmr,xip->nakresend * 1000);
+ while(!msecElapsed(&tmr) && !gotachar());
+ if (gotachar())
+ break;
+ }
+ if (i == 32) {
+ Mtrace("Giveup @ %d",__LINE__);
+ return(-1);
+ }
+
+ done = 0;
+ Mtrace("Got response");
+ while(done == 0) {
+ if (xgetchar(&c,__LINE__) == -1)
+ return(-1);
+ switch(c) {
+ case SOH: /* 128-byte incoming packet */
+ Mtrace("O");
+ xip->pktlen = 128;
+ done = getPacket((uchar *)tmppkt,xip);
+ if (done < 0)
+ Mtrace("GP_%d",done);
+ if (!done && (xip->pktcnt == 1) && (xip->flags & YMODEM))
+ goto restart;
+ break;
+#if INCLUDE_MALLOC
+ case STX: /* 1024-byte incoming packet */
+ Mtrace("T");
+ xip->pktlen = 1024;
+ done = getPacket((uchar *)tmppkt,xip);
+ if (done < 0)
+ Mtrace("GP_%d",done);
+ if (!done && (xip->pktcnt == 1) && (xip->flags & YMODEM))
+ goto restart;
+ break;
+#endif
+ case CAN:
+ Mtrace("C");
+ done = -1;
+ break;
+ case EOT:
+ Mtrace("E");
+ PUTCHAR(ACK);
+ if (xip->flags & YMODEM) {
+#if INCLUDE_TFS
+ if (!xip->size)
+ xip->size = xip->pktcnt * xip->pktlen;
+ if (xip->fname[0])
+ tfsadd(xip->fname,0,0,(uchar *)xip->base,xip->size);
+ xip->dataddr = xip->base;
+#endif
+ goto nextfile;
+ }
+ else {
+ done = xip->xfertot;
+ rawoff();
+ printf("\nRcvd %d pkt%c (%d bytes)\n",xip->pktcnt,
+ xip->pktcnt > 1 ? 's' : ' ',xip->xfertot);
+
+ /* If the transfer is complete and no file add is to
+ * be done, then we flush d-cache and invalidate
+ * i-cache across the memory space that was just
+ * copied to. This is necessary in case the
+ * binary data that was just transferred is code.
+ */
+ flushDcache((char *)xip->base,xip->xfertot);
+ invalidateIcache((char *)xip->base,xip->xfertot);
+ }
+ break;
+ case ESC: /* User-invoked abort */
+ Mtrace("X");
+ done = -1;
+ break;
+ case EOF: /* 0x1a sent by MiniCom, just ignore it. */
+ break;
+ default:
+ Mtrace("<%02x>",c);
+ done = -1;
+ break;
+ }
+ Mtrace("!");
+ }
+ rawoff();
+ if (xip->flags & VERIFY) {
+ if (xip->errcnt)
+ printf("%d errors, first at 0x%lx\n",
+ xip->errcnt,(ulong)(xip->firsterrat));
+ else
+ printf("verification passed\n");
+ }
+ free(tmppkt);
+ return(done);
+}
+
+
+#endif
diff --git a/main/cpu/arm/arm.h b/main/cpu/arm/arm.h
new file mode 100644
index 0000000..8c9c53e
--- /dev/null
+++ b/main/cpu/arm/arm.h
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * arm.h
+ *
+ * PSR Bits
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#define PSR_THUMB_STATE 0x00000020
+#define PSR_IMASK_IRQ 0x00000080
+#define PSR_IMASK_FRQ 0x00000040
+#define PSR_CONDITION_NEGATIVE 0x80000000
+#define PSR_CONDITION_ZERO 0x40000000
+#define PSR_CONDITION_CARRY 0x20000000
+#define PSR_CONDITION_OVERFLOW 0x10000000
+#define PSR_MODE_MASK 0x0000001f
+
+/* Mode bits within PSR:
+ */
+#define ABORT_MODE 0x00000017
+#define FASTINTRQST_MODE 0x00000011
+#define INTRQST_MODE 0x00000012
+#define SUPERVISOR_MODE 0x00000013
+#define SYSTEM_MODE 0x0000001f
+#define UNDEFINED_MODE 0x0000001b
+#define USER_MODE 0x00000010
+
+/* Exception types:
+ */
+#define EXCTYPE_UNDEF 1
+#define EXCTYPE_ABORTP 2
+#define EXCTYPE_ABORTD 3
+#define EXCTYPE_IRQ 4
+#define EXCTYPE_FIRQ 5
+#define EXCTYPE_SWI 6
+#define EXCTYPE_NOTASSGN 7
+
+/* Link register adjustments for each exception:
+ * These adjustments are used by the exception handler to establish the
+ * address at which the exception occurred.
+ */
+#define LRADJ_UNDEF 4
+#define LRADJ_ABORTP 4
+#define LRADJ_ABORTD 8
+#define LRADJ_IRQ 4
+#define LRADJ_FIRQ 4
+#define LRADJ_SWI 4
+
+/* Vector numbers used by assign_handler and the mon_assignhandler()
+ * API function...
+ */
+#define VEC_RST 0
+#define VEC_UND 1
+#define VEC_SWI 2
+#define VEC_ABP 3
+#define VEC_ABD 4
+#define VEC_IRQ 5
+#define VEC_RESERVED 6
+#define VEC_FIQ 7
diff --git a/main/cpu/arm/cache_arm.c b/main/cpu/arm/cache_arm.c
new file mode 100644
index 0000000..cc471da
--- /dev/null
+++ b/main/cpu/arm/cache_arm.c
@@ -0,0 +1,124 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * cache_arm.c
+ *
+ * ARM's definition of "flush" and "clean" (as taken from the
+ * "ARM System Developer's Guide") ...
+ *
+ * To "flush a cache" is to clear it of any stored data. Flushing clears
+ * the valid bit in the affected cache line... The term "invalidate"
+ * is sometimes used in place of the term "flush".
+ *
+ * To "clean a cache" is to force a write of the dirty cache lines
+ * from the cache out to main memory and clear the dirty bits in the
+ * cache line.
+ *
+ * This conflicts with uMon's general use of the terms "flush" and
+ * "invalidate". For uMon, "flush" refers to what ARM calls "clean"
+ * and "invalidate" refers to what ARM calls "flush". ARRGGHH!!
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "cache.h"
+
+int
+arm_cleanDcache(char *base, int size)
+{
+ return(0);
+}
+
+int
+arm_flushIcache(char *base, int size)
+{
+ /* Flush (i.e. "invlidate in uMon terminology) entire instruction
+ * cache (ignore incoming args).
+ */
+ asm(" MOV r0, #0");
+ asm(" MCR p15, 0, r0, c7, c5, 0");
+ return(0);
+}
+
+/* cacheInitForTarget():
+ Enable instruction cache only...
+*/
+void
+cacheInitForTarget()
+{
+ asm(" MRC p15, 0, r0, c1, c0, 0");
+ asm(" ORR r0, r0, #0x1000"); /* bit 12 is ICACHE enable*/
+ asm(" MCR p15, 0, r0, c1, c0, 0");
+
+ /* Flush instruction cache */
+ arm_flushIcache(0,0);
+
+ dcacheFlush = arm_cleanDcache;
+ icacheInvalidate = arm_flushIcache;
+}
+
+/* MRC/MCR assembler syntax (for ARM general):
+ *
+ * <MCR|MRC>{cond} p#,<expression1>,Rd,cn,cm{,<expression2>}
+ *
+ * Where:
+ * - MRC move from coprocessor to ARM register (L=1)
+ * - MCR move from ARM register to coprocessor (L=0)
+ * - {cond} two character condition mnemonic (see list below)
+ * - p# the unique number of the required coprocessor
+ * - <expression1> evaluated to a constant and placed in the CP Opc field
+ * - Rd is an expression evaluating to a valid ARM processor register
+ * number
+ * - cn and cm are expressions evaluating to the valid coprocessor register
+ * numbers CRn and CRm respectively
+ * - <expression2> where present is evaluated to a constant and placed in
+ * the CP field
+ *
+ * Examples
+ * - MRC 2,5,R3,c5,c6 ;request coproc 2 to perform operation 5
+ * ;on c5 and c6, and transfer the (single
+ * ;32-bit word) result back to R3
+ * - MCR 6,0,R4,c6 ;request coproc 6 to perform operation 0
+ * ;on R4 and place the result in c6
+ * - MRCEQ 3,9,R3,c5,c6,2 ;conditionally request coproc 2 to
+ * ;perform
+ * ;operation 9 (type 2) on c5 and c6, and
+ * ;transfer the result back to R3
+ *
+ * Condition codes:
+ * EQ (equal) - Z set
+ * NE (not equal) - Z clear
+ * CS (unsigned higher or same) - C set
+ * CC (unsigned lower) - C clear
+ * MI (negative) - N set
+ * PL (positive or zero) - N clear
+ * VS (overflow) - V set
+ * VC (no overflow) - V clear
+ * HI (unsigned higher) - C set and Z clear
+ * LS (unsigned lower or same) - C clear or Z set
+ * GE (greater or equal) - N set and V set, or N clear and V clear
+ * LT (less than) - N set and V clear, or N clear and V set
+ * GT (greater than) - Z clear, and either N set and Vset,
+ * or N clear and V clear
+ * LE (less than or equal) - Z set, or N set and V clear,
+ * or N clear and V set
+ * AL - always
+ * NV - never
+ */
diff --git a/main/cpu/arm/except_arm.c b/main/cpu/arm/except_arm.c
new file mode 100644
index 0000000..f9e4f30
--- /dev/null
+++ b/main/cpu/arm/except_arm.c
@@ -0,0 +1,94 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * FILENAME_HERE
+ *
+ * DESCRIPTION_HERE
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "config.h"
+#include "arm.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "warmstart.h"
+
+ulong ExceptionAddr;
+int ExceptionType;
+
+/***********************************************************************
+ *
+ * umon_exception()
+ * Default exception handler used by the low level code in vectors_arm.S.
+ */
+void
+umon_exception(ulong addr, ulong type)
+{
+ ExceptionAddr = addr;
+ ExceptionType = type;
+ monrestart(EXCEPTION);
+}
+
+/***********************************************************************
+ *
+ * ExceptionType2String():
+ * This function simply returns a string that verbosely describes
+ * the incoming exception type (vector number).
+ */
+char *
+ExceptionType2String(int type)
+{
+ char *string;
+
+ switch(type) {
+ case EXCTYPE_UNDEF:
+ string = "Undefined instruction";
+ break;
+ case EXCTYPE_ABORTP:
+ string = "Abort prefetch";
+ break;
+ case EXCTYPE_ABORTD:
+ string = "Abort data";
+ break;
+ case EXCTYPE_IRQ:
+ string = "IRQ";
+ break;
+ case EXCTYPE_FIRQ:
+ string = "Fast IRQ";
+ break;
+ case EXCTYPE_NOTASSGN:
+ string = "Not assigned";
+ break;
+ case EXCTYPE_SWI:
+ string = "Software Interrupt";
+ break;
+ default:
+ string = "???";
+ break;
+ }
+ return(string);
+}
+
+void
+vinit(void)
+{
+}
diff --git a/main/cpu/arm/gdbregs_arm.c b/main/cpu/arm/gdbregs_arm.c
new file mode 100644
index 0000000..11953a9
--- /dev/null
+++ b/main/cpu/arm/gdbregs_arm.c
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * gdbregs_arm.c
+ *
+ * List of the register names for the ARM in the order they
+ * are expected by the GDB 'g' command (read all registers).
+ * R13=SP, R14=LR
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#define CPU_PC_REG "PC"
+
+static char *gdb_regtbl[] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "R13", "R14", "PC",
+ "R0", "CPSR",
+};
diff --git a/main/cpu/arm/ldatags.c b/main/cpu/arm/ldatags.c
new file mode 100644
index 0000000..f647f2d
--- /dev/null
+++ b/main/cpu/arm/ldatags.c
@@ -0,0 +1,441 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * ldatags:
+ *
+ * Load (install) ARM Tags for booting Linux.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "ether.h"
+#include "cli.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+
+#define __PACKED__ __attribute__ ((packed))
+#define TAG_SIZE(a) ((sizeof(a) + sizeof(struct tag_hdr))/4)
+#define STR_LEN(string) (sizeof(string) - 1)
+
+#define MEM32_SIZE "mem32_size="
+#define MEM32_START "mem32_start="
+#define CORE_FLAGS "core_flags="
+#define CORE_PGSIZE "core_pgsize="
+#define CORE_ROOTDEV "core_rootdev="
+#define INITRD_SIZE "initrd_size="
+#define INITRD_START "initrd_start="
+#define RAMDISK_FLAGS "ramdisk_flags="
+#define RAMDISK_SIZE "ramdisk_size="
+#define RAMDISK_START "ramdisk_start="
+#define SERIAL_HI "serial_hi="
+#define SERIAL_LO "serial_lo="
+#define CMDLINE "cmdline="
+#define CMDLINE_APP "cmdline_append="
+#define REVISION "revision="
+
+void sno_mac_warning(int);
+void initrd_file_warning(int);
+
+#ifdef ATAG_SPACE_DEFINED
+extern int atag_space, end_atag_space;
+#endif
+
+#define CLISIZE 1024
+
+/* Tag specification defaults:
+ */
+#define RAMDISK_MAJOR 1
+#define PAGE_SIZE 4096
+#define PHYS_OFFSET 0x20000000
+#define MEM_SIZE 0x01e00000
+
+/* Tag identifiers:
+ */
+#define ATAG_NONE 0x00000000
+#define ATAG_CORE 0x54410001
+#define ATAG_MEM 0x54410002
+#define ATAG_VIDEOTEXT 0x54410003
+#define ATAG_RAMDISK 0x54410004
+#define ATAG_INITRD 0x54410005
+#define ATAG_INITRD2 0x54420005
+#define ATAG_SERIAL 0x54410006
+#define ATAG_REVISION 0x54410007
+#define ATAG_VIDEOLFB 0x54410008
+#define ATAG_CMDLINE 0x54410009
+#define ATAG_ACORN 0x41000101
+#define ATAG_MEMCLK 0x41000402
+#define ATAG_SNOMAC ATAG_SERIAL
+
+/* Tag structures:
+ */
+struct tag_hdr {
+ ulong size;
+ ulong tag;
+}__PACKED__;
+
+struct tag_core {
+ ulong flags;
+ ulong pgsize;
+ ulong rootdev;
+}__PACKED__;
+
+struct tag_mem32 {
+ ulong size;
+ ulong start;
+}__PACKED__;
+
+union tag_snomac {
+ struct tag_serial {
+ ulong hi;
+ ulong lo;
+ } serial;
+ struct tag_mac {
+ char mac[8]; /* only use first 6 bytes */
+ } mac;
+}__PACKED__;
+
+struct tag_initrd {
+ ulong start;
+ ulong size;
+}__PACKED__;
+
+struct tag_ramdisk {
+ ulong flags;
+ ulong size;
+ ulong start;
+}__PACKED__;
+
+struct tag_cmdline {
+ char cmdline[CLISIZE];
+}__PACKED__;
+
+struct tag_revno {
+ ulong rev;
+}__PACKED__;
+
+struct init_tags {
+ struct tag_hdr hdr1;
+ struct tag_core core;
+ struct tag_hdr hdr2;
+ struct tag_mem32 mem;
+ struct tag_hdr hdr3;
+ union tag_snomac snomac;
+ struct tag_hdr hdr4;
+ struct tag_ramdisk ramdisk;
+ struct tag_hdr hdr5;
+ struct tag_initrd initrd;
+ struct tag_hdr hdr6;
+ struct tag_cmdline cmdline;
+ struct tag_hdr hdr7;
+ struct tag_revno revno;
+ struct tag_hdr hdr_last;
+}__PACKED__;
+
+/* This is the default tag list. All entries in this list can
+ * be overridden by sub-commands within the ldatags command.
+ */
+static struct init_tags inittag = {
+ { TAG_SIZE(struct tag_core), ATAG_CORE },
+ { 1, PAGE_SIZE, 0xff },
+
+ { TAG_SIZE(struct tag_mem32), ATAG_MEM },
+ { MEM_SIZE, PHYS_OFFSET },
+
+ { TAG_SIZE(union tag_snomac), ATAG_SNOMAC },
+ { {0xffffffff, 0xffffffff} },
+
+ { TAG_SIZE(struct tag_ramdisk), ATAG_RAMDISK },
+ { 0, 0, 0 },
+
+ { TAG_SIZE(struct tag_initrd), ATAG_INITRD2 },
+ { 0, 0 },
+
+ { TAG_SIZE(struct tag_cmdline), ATAG_CMDLINE },
+ { {0} },
+
+ { TAG_SIZE(struct tag_revno), ATAG_REVISION },
+ { 0 },
+
+ { 0, ATAG_NONE },
+};
+
+
+char *ldatagsHelp[] = {
+ "Install ARM tags for Linux startup.",
+ "[-a:cf:imv] [sub-cmd1 sub-cmd2 ...]",
+ "Options:",
+ " -a {addr} tag list address",
+ " -c clear tag list memory",
+ " -f {fname} initrd filename",
+ " -i init default tag list",
+ " -m load MAC address into serial_no tag",
+ " -v enable verbosity",
+ "Sub-commands:",
+ " " CORE_FLAGS "{value}",
+ " " CORE_PGSIZE "{value}",
+ " " CORE_ROOTDEV "{value}",
+ " " MEM32_SIZE "{value}",
+ " " MEM32_START "{value}",
+ " " SERIAL_LO "{value} (serial hi/lo overrides -m)",
+ " " SERIAL_HI "{value}",
+ " " INITRD_SIZE "{value} (initrd size/start overrides -f)",
+ " " INITRD_START "{value}",
+ " " RAMDISK_FLAGS "{value}",
+ " " RAMDISK_SIZE "{value}",
+ " " RAMDISK_START "{value}",
+ " " REVISION "{value}",
+ " " CMDLINE "{string}",
+ " " CMDLINE_APP "{string}",
+ 0
+};
+
+
+int
+ldatags(int argc,char *argv[])
+{
+ TFILE *tfp;
+ char *eadd, *initrd_fname;
+ struct init_tags *tagaddr;
+ int opt, verbose, arg, clear, init, mac, len;
+ int sno_mac_warned, initrd_file_warned;
+
+ initrd_fname = 0;
+ sno_mac_warned = initrd_file_warned = 0;
+ mac = init = verbose = clear = 0;
+#ifdef ATAG_SPACE_DEFINED
+ tagaddr = (struct init_tags *)&atag_space;
+#else
+ tagaddr = (struct init_tags *)getAppRamStart();
+#endif
+ while((opt=getopt(argc,argv,"a:cf:imv")) != -1) {
+ switch(opt) {
+ case 'a': /* Override default tag list address. */
+ tagaddr = (struct init_tags *)strtoul(optarg,0,0);
+ break;
+ case 'c': /* Clear the tag list space. */
+ clear++;
+ break;
+ case 'f': /* Initrd filename. */
+ initrd_fname = optarg;
+ break;
+ case 'i': /* Initialize tag list with defaults. */
+ init++;
+ break;
+ case 'm': /* Load MAC address into list. */
+ mac++;
+ break;
+ case 'v': /* Enable verbosity. */
+ verbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+#ifdef ATAG_SPACE_DEFINED
+ /* If the ATAG space is allocated externally (usually in rom.lnk file),
+ * then if at this point the tag address still points to that space,
+ * we must start by verifying that the allocated space is large enough
+ * to hold the init_tags structure...
+ */
+ if (tagaddr == (struct init_tags *)&atag_space) {
+ if (((int)&end_atag_space - (int)&atag_space) < sizeof(struct init_tags)) {
+ printf("Error: the size of struct init_tags (%d) is larger than\n",
+ sizeof(struct init_tags));
+ printf(" the size of the allocated atag space (%d bytes).\n",
+ ((int)&end_atag_space - (int)&atag_space));
+ return(CMD_FAILURE);
+ }
+ }
+#endif
+
+ if (clear) {
+ memset((char *)tagaddr,0,sizeof(struct init_tags));
+ if (verbose)
+ printf("Tagspace at 0x%lx cleared\n",(long)tagaddr);
+ return(CMD_SUCCESS);
+ }
+
+ /* If -i specified, then load default tag list for starters...
+ */
+ if (init)
+ memcpy((char *)tagaddr,(char *)&inittag,sizeof(struct init_tags));
+
+ /* Insert this board's MAC address:
+ */
+ if (mac) {
+ memset(tagaddr->snomac.mac.mac,0,8);
+ eadd = getenv("ETHERADD");
+ if (eadd) {
+ if (EtherToBin(eadd,(uchar *)tagaddr->snomac.mac.mac) < 0)
+ return(CMD_FAILURE);
+ }
+ else {
+ printf("ETHERADD shell var not set.\n");
+ return(CMD_FAILURE);
+ }
+ }
+
+ if (initrd_fname) {
+ tfp = tfsstat(initrd_fname);
+ if (!tfp) {
+ printf("No such file: %s\n",initrd_fname);
+ return(CMD_FAILURE);
+ }
+ tagaddr->initrd.size = (ulong)TFS_SIZE(tfp);
+ tagaddr->initrd.start = (ulong)TFS_BASE(tfp);
+ }
+
+ /* Process the command line arguments:
+ */
+ for(arg=optind;arg<argc;arg++) {
+ if (strncmp(argv[arg],CORE_FLAGS,STR_LEN(CORE_FLAGS)) == 0) {
+ tagaddr->core.flags =
+ strtoul(argv[arg]+STR_LEN(CORE_FLAGS),0,0);
+ }
+ else if (strncmp(argv[arg],CORE_PGSIZE,STR_LEN(CORE_PGSIZE)) == 0) {
+ tagaddr->core.pgsize =
+ strtoul(argv[arg]+STR_LEN(CORE_PGSIZE),0,0);
+ }
+ else if (strncmp(argv[arg],CORE_ROOTDEV,STR_LEN(CORE_ROOTDEV)) == 0) {
+ tagaddr->core.rootdev =
+ strtoul(argv[arg]+STR_LEN(CORE_ROOTDEV),0,0);
+ }
+ else if (strncmp(argv[arg],MEM32_SIZE,STR_LEN(MEM32_SIZE)) == 0) {
+ tagaddr->mem.size =
+ strtoul(argv[arg]+STR_LEN(MEM32_SIZE),0,0);
+ }
+ else if (strncmp(argv[arg],MEM32_START,STR_LEN(MEM32_START)) == 0) {
+ tagaddr->mem.start =
+ strtoul(argv[arg]+STR_LEN(MEM32_START),0,0);
+ }
+ else if (strncmp(argv[arg],INITRD_SIZE,STR_LEN(INITRD_SIZE)) == 0) {
+ if (initrd_fname)
+ initrd_file_warning(initrd_file_warned++);
+ tagaddr->initrd.size =
+ strtoul(argv[arg]+STR_LEN(INITRD_SIZE),0,0);
+ }
+ else if (strncmp(argv[arg],INITRD_START,STR_LEN(INITRD_START)) == 0) {
+ if (initrd_fname)
+ initrd_file_warning(initrd_file_warned++);
+ tagaddr->initrd.start =
+ strtoul(argv[arg]+STR_LEN(INITRD_START),0,0);
+ }
+ else if (strncmp(argv[arg],RAMDISK_FLAGS,STR_LEN(RAMDISK_FLAGS)) == 0) {
+ tagaddr->ramdisk.flags =
+ strtoul(argv[arg]+STR_LEN(RAMDISK_FLAGS),0,0);
+ }
+ else if (strncmp(argv[arg],RAMDISK_SIZE,STR_LEN(RAMDISK_SIZE)) == 0) {
+ tagaddr->ramdisk.size =
+ strtoul(argv[arg]+STR_LEN(RAMDISK_SIZE),0,0);
+ }
+ else if (strncmp(argv[arg],RAMDISK_START,STR_LEN(RAMDISK_START)) == 0) {
+ tagaddr->ramdisk.start =
+ strtoul(argv[arg]+STR_LEN(RAMDISK_START),0,0);
+ }
+ else if (strncmp(argv[arg],SERIAL_HI,STR_LEN(SERIAL_HI)) == 0) {
+ if (mac)
+ sno_mac_warning(sno_mac_warned++);
+ mac = 0;
+ tagaddr->snomac.serial.hi =
+ strtoul(argv[arg]+STR_LEN(SERIAL_HI),0,0);
+ }
+ else if (strncmp(argv[arg],SERIAL_LO,STR_LEN(SERIAL_LO)) == 0) {
+ if (mac)
+ sno_mac_warning(sno_mac_warned++);
+ mac = 0;
+ tagaddr->snomac.serial.lo =
+ strtoul(argv[arg]+STR_LEN(SERIAL_LO),0,0);
+ }
+ else if (strncmp(argv[arg],CMDLINE,STR_LEN(CMDLINE)) == 0) {
+ len = strlen(argv[arg]+STR_LEN(CMDLINE));
+ if (len > CLISIZE-1)
+ printf("Kernel cli too big (%d>%d)\n",len,CLISIZE);
+ else
+ strcpy(tagaddr->cmdline.cmdline,argv[arg]+STR_LEN(CMDLINE));
+ }
+ else if (strncmp(argv[arg],CMDLINE_APP,STR_LEN(CMDLINE_APP)) == 0) {
+ len = strlen(argv[arg]+STR_LEN(CMDLINE_APP));
+ len += strlen(tagaddr->cmdline.cmdline);
+ if (len > CLISIZE-1)
+ printf("Kernel cli too big (%d>%d)\n",len,CLISIZE);
+ else
+ strcat(tagaddr->cmdline.cmdline,argv[arg]+STR_LEN(CMDLINE_APP));
+ }
+ else if (strncmp(argv[arg],REVISION,STR_LEN(REVISION)) == 0) {
+ tagaddr->revno.rev =
+ strtoul(argv[arg]+STR_LEN(REVISION),0,0);
+ }
+ else {
+ printf("Unrecognized sub-command: %s\n",argv[arg]);
+ return(CMD_FAILURE);
+ }
+ }
+
+ if (verbose) {
+ printf("ATAGS (%d bytes) at 0x%lx...\n",
+ sizeof(struct init_tags),(long)tagaddr);
+ printf(" Core (flags/pgsize/rootdev) = 0x%lx/0x%0lx/0x%lx\n",
+ tagaddr->core.flags,tagaddr->core.pgsize,tagaddr->core.rootdev);
+ printf(" Mem32 (size/offset) = 0x%08lx/0x%08lx\n",
+ tagaddr->mem.size,tagaddr->mem.start);
+ if (mac) {
+ printf(" Mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ tagaddr->snomac.mac.mac[0], tagaddr->snomac.mac.mac[1],
+ tagaddr->snomac.mac.mac[2], tagaddr->snomac.mac.mac[3],
+ tagaddr->snomac.mac.mac[4], tagaddr->snomac.mac.mac[5]);
+ }
+ else {
+ printf(" Serial (hi/lo) = 0x%08lx/0x%08lx\n",
+ tagaddr->snomac.serial.hi, tagaddr->snomac.serial.lo);
+ }
+ printf(" Ramdisk (flags/size/start) = 0x%lx/0x%lx/0x%lx\n",
+ tagaddr->ramdisk.flags, tagaddr->ramdisk.size,
+ tagaddr->ramdisk.start);
+
+ printf(" Initrd (size/start) = 0x%lx/0x%lx\n",
+ tagaddr->initrd.size, tagaddr->initrd.start);
+
+ printf(" Cmdline = <%s>\n",tagaddr->cmdline.cmdline);
+ }
+
+ return(CMD_SUCCESS);
+}
+
+void
+sno_mac_warning(int already_warned)
+{
+ if (already_warned)
+ return;
+
+ printf("Warning: serialno command overrides -m option.\n");
+}
+
+void
+initrd_file_warning(int already_warned)
+{
+ if (already_warned)
+ return;
+
+ printf("Warning: initrd command overrides -f option.\n");
+}
diff --git a/main/cpu/arm/misc_arm.c b/main/cpu/arm/misc_arm.c
new file mode 100644
index 0000000..355245c
--- /dev/null
+++ b/main/cpu/arm/misc_arm.c
@@ -0,0 +1,64 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * misc_arm.c
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+/*
+ * Set the Current Program Status Register.
+ * old way assumed argument was in R0:
+ * asm(" msr CPSR_c, r0");
+ */
+void
+putpsr(unsigned long psr)
+{
+ volatile unsigned register reg;
+
+ reg = psr;
+ asm volatile ("msr CPSR_c, %0" : "=r" (reg));
+}
+
+/*
+ * Return the Current Program Status Register.
+ * old way assumed return in R0:
+ * asm(" mrs r0, CPSR");
+ */
+unsigned long
+getpsr(void)
+{
+ volatile unsigned register reg;
+ asm volatile ("mrs %0, CPSR" : "=r" (reg));
+ return(reg);
+}
+
+/* getsp():
+ * Return the current stack pointer.
+ * oldway: asm(" mov r0, r13");
+ */
+unsigned long
+getsp(void)
+{
+ volatile unsigned register reg;
+ asm volatile ("mov %0, r13" : "=r" (reg));
+ return(reg);
+}
diff --git a/main/cpu/arm/misc_arm.h b/main/cpu/arm/misc_arm.h
new file mode 100644
index 0000000..add61d3
--- /dev/null
+++ b/main/cpu/arm/misc_arm.h
@@ -0,0 +1,28 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * misc_arm.h
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+extern void putpsr(unsigned long psr);
+extern unsigned long getpsr(void);
+extern unsigned long getsp(void);
diff --git a/main/cpu/arm/regs_arm.c b/main/cpu/arm/regs_arm.c
new file mode 100644
index 0000000..13180f0
--- /dev/null
+++ b/main/cpu/arm/regs_arm.c
@@ -0,0 +1,32 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * FILENAME_HERE
+ *
+ * DESCRIPTION_HERE
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+static char *regnames[] = {
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
+ "R8", "R9", "R10", "R11", "R12", "SP", "LR",
+ "PC", "CPSR"
+};
diff --git a/main/cpu/arm/strace_arm.c b/main/cpu/arm/strace_arm.c
new file mode 100644
index 0000000..8dd7456
--- /dev/null
+++ b/main/cpu/arm/strace_arm.c
@@ -0,0 +1,156 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * strace.c:
+ *
+ * Note that this stack trace can be used to trace REAL exceptions or
+ * user-induced exceptions. If one is user-induced, then the user is
+ * typically just replacing an instruction at the point at which the break
+ * is to occur with a SC (syscall) instruction. The point at which this
+ * insertion is made must be after the function sets up its stack frame
+ * otherwise it is likely that the trace will be bogus.
+ *
+ * BTW... the SC instruction is 0x44000002.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_STRACE
+#include "tfs.h"
+#include "tfsprivate.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+char *StraceHelp[] = {
+ "Stack trace",
+ "-[d:rs:v]",
+ " -d # max depth count (def=20)",
+ " -r dump regs",
+ " -s {func} stop at function 'func'",
+ " -v verbose",
+ 0,
+};
+
+int
+Strace(int argc,char *argv[])
+{
+ TFILE *tfp;
+ char *symfile, *stopat, fname[64];
+ ulong *framepointer, pc, fp, offset;
+ int tfd, opt, maxdepth, pass, verbose;
+
+ tfd = fp = 0;
+ maxdepth = 20;
+ verbose = 0;
+ stopat = 0;
+ pc = ExceptionAddr;
+ while ((opt=getopt(argc,argv,"d:rs:v")) != -1) {
+ switch(opt) {
+ case 'd':
+ maxdepth = atoi(optarg);
+ break;
+ case 'r':
+ showregs();
+ break;
+ case 's':
+ stopat = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ if (!fp)
+ getreg("R11", &fp);
+
+ framepointer = (ulong *)fp;
+
+ /* Start by detecting the presence of a symbol table file... */
+ symfile = getenv("SYMFILE");
+ if (!symfile)
+ symfile = SYMFILE;
+
+ tfp = tfsstat(symfile);
+ if (tfp) {
+ tfd = tfsopen(symfile,TFS_RDONLY,0);
+ if (tfd < 0)
+ tfp = (TFILE *)0;
+ }
+
+ /* Show current position: */
+ printf(" 0x%08lx",pc);
+ if (tfp) {
+ AddrToSym(tfd,pc,fname,&offset);
+ printf(": %s()",fname);
+ if (offset)
+ printf(" + 0x%lx",offset);
+ }
+ putchar('\n');
+
+ /* Now step through the stack frame... */
+ pass = 0;
+ while(maxdepth) {
+ if (pass != 0)
+ framepointer = (ulong *)*(framepointer - 3);
+
+ pc = *(framepointer - 1);
+
+ if (verbose) {
+ printf("fp=0x%lx,*fp=0x%lx,pc=%lx\n", (ulong)framepointer,
+ (ulong)*framepointer,pc);
+ }
+
+ if (((ulong)framepointer & 3) || (!framepointer) ||
+ (!*framepointer) || (!pc)) {
+ break;
+ }
+
+ printf(" 0x%08lx",pc);
+ if (tfp) {
+ int match;
+
+ match = AddrToSym(tfd,pc,fname,&offset);
+ printf(": %s()",fname);
+ if (offset)
+ printf(" + 0x%lx",offset);
+ if ((!match) || ((stopat != 0) && (strcmp(fname,stopat) == 0))) {
+ putchar('\n');
+ break;
+ }
+ }
+ putchar('\n');
+ maxdepth--;
+ pass++;
+ }
+
+ if (!maxdepth)
+ printf("Max depth termination\n");
+
+ if (tfp) {
+ tfsclose(tfd,0);
+ }
+ return(0);
+}
+#endif
diff --git a/main/cpu/arm/vectors_arm.S b/main/cpu/arm/vectors_arm.S
new file mode 100644
index 0000000..c4389ed
--- /dev/null
+++ b/main/cpu/arm/vectors_arm.S
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * vectors_arm.S
+ *
+ * Minimalist exception handlers...
+ * Catch the exception, call generic handler with exception-specific id.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+#include "arm.h"
+
+ .global undefined_instruction
+undefined_instruction:
+ mov r1, #EXCTYPE_UNDEF
+ b umon_exception
+
+ .global software_interrupt
+software_interrupt:
+ mov r1, #EXCTYPE_SWI
+ b umon_exception
+
+ .global abort_prefetch
+abort_prefetch:
+ mov r1, #EXCTYPE_ABORTP
+ b umon_exception
+
+ .global abort_data
+abort_data:
+ mov r1, #EXCTYPE_ABORTD
+ b umon_exception
+
+ .global not_assigned
+not_assigned:
+ mov r1, #EXCTYPE_NOTASSGN
+ b umon_exception
+
+ .global interrupt_request
+interrupt_request:
+ mov r1, #EXCTYPE_IRQ
+ b umon_exception
+
+ .global fast_interrupt_request
+fast_interrupt_request:
+ mov r1, #EXCTYPE_FIRQ
+ b umon_exception
diff --git a/main/cpu/template/except_template.c b/main/cpu/template/except_template.c
new file mode 100644
index 0000000..1623d5c
--- /dev/null
+++ b/main/cpu/template/except_template.c
@@ -0,0 +1,87 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * except_template.c:
+ *
+ * Template for cpu-specific code that handles exceptions that are caught
+ * by the exception vectors that have been installed by the monitor through
+ * vinit().
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "cpu.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "warmstart.h"
+
+ulong ExceptionAddr;
+int ExceptionType;
+
+/* exception():
+ * This is the first 'C' function called out of a monitor-installed
+ * exception handler.
+ */
+void
+exception(void)
+{
+ /* ADD_CODE_HERE */
+
+ /* Populating these two values is target specific.
+ * Refer to other target-specific examples for details.
+ * In some cases, these values are extracted from registers
+ * already put into the register cache by the lower-level
+ * portion of the exception handler in vectors_template.s
+ */
+ ExceptionAddr = 0;
+ ExceptionType = 0;
+
+ /* Allow the console uart fifo to empty...
+ */
+ flushconsole();
+ monrestart(EXCEPTION);
+}
+
+/* vinit():
+ * This function is called by init1() at startup of the monitor to
+ * install the monitor-based vector table. The actual functions are
+ * in vectors.s.
+ */
+void
+vinit()
+{
+ /* ADD_CODE_HERE */
+}
+
+/* ExceptionType2String():
+ * This function simply returns a string that verbosely describes
+ * the incoming exception type (vector number).
+ */
+char *
+ExceptionType2String(int type)
+{
+ char *string;
+
+ /* ADD_CODE_HERE */
+ return(string);
+}
+
diff --git a/main/cpu/template/strace_template.c b/main/cpu/template/strace_template.c
new file mode 100644
index 0000000..559f5b8
--- /dev/null
+++ b/main/cpu/template/strace_template.c
@@ -0,0 +1,124 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * strace_template.c:
+ *
+ * Template for creating cpu-specific stack-trace command.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_STRACE
+#include "tfs.h"
+#include "tfsprivate.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+#include "cpu.h"
+
+char *StraceHelp[] = {
+ "Stack trace",
+ "-[d:F:P:rs:v]",
+ " -d # max depth count (def=20)",
+ " -F # specify frame-pointer (don't use content of A6)",
+ " -P # specify PC (don't use content of PC)",
+ " -r dump regs",
+ " -v verbose",
+ 0,
+};
+
+int
+Strace(int argc,char *argv[])
+{
+ char *symfile, fname[64];
+ TFILE *tfp;
+ ulong *framepointer, pc, fp, offset;
+ int tfd, opt, maxdepth, pass, verbose, bullseye;
+
+ tfd = fp = 0;
+ maxdepth = 20;
+ verbose = 0;
+ pc = ExceptionAddr;
+ while ((opt=getopt(argc,argv,"d:F:P:rs:v")) != -1) {
+ switch(opt) {
+ case 'd':
+ maxdepth = atoi(optarg);
+ break;
+ case 'F':
+ fp = strtoul(optarg,0,0);
+ break;
+ case 'P':
+ pc = strtoul(optarg,0,0);
+ break;
+ case 'r':
+ showregs();
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ if (!fp)
+ getreg("A6", (ulong *)&framepointer);
+ else
+ framepointer = (ulong *)fp;
+
+ /* Start by detecting the presence of a symbol table file... */
+ symfile = getenv("SYMFILE");
+ if (!symfile)
+ symfile = SYMFILE;
+
+ tfp = tfsstat(symfile);
+ if (tfp) {
+ tfd = tfsopen(symfile,TFS_RDONLY,0);
+ if (tfd < 0)
+ tfp = (TFILE *)0;
+ }
+
+ /* Show current position: */
+ printf(" 0x%08lx",pc);
+ if (tfp) {
+ AddrToSym(tfd,pc,fname,&offset);
+ printf(": %s()",fname);
+ if (offset)
+ printf(" + 0x%lx",offset);
+ }
+ putchar('\n');
+
+ /* Now step through the stack frame... */
+ bullseye = pass = 0;
+ while(maxdepth) {
+ /* ADD_CODE_HERE */
+ }
+
+ if (!maxdepth)
+ printf("Max depth termination\n");
+
+ if (tfp) {
+ tfsclose(tfd,0);
+ }
+ return(0);
+}
+
+#endif
diff --git a/main/dev/bp b/main/dev/bp
new file mode 100644
index 0000000..c472414
--- /dev/null
+++ b/main/dev/bp
@@ -0,0 +1,27 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * FILENAME_HERE
+ *
+ * DESCRIPTION_HERE
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
diff --git a/main/dev/fb_draw.c b/main/dev/fb_draw.c
new file mode 100644
index 0000000..a0f9391
--- /dev/null
+++ b/main/dev/fb_draw.c
@@ -0,0 +1,261 @@
+//==========================================================================
+//
+// fb_draw.c
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 10/18/03
+// Description: generic frame buffer drawing routines - based on
+// lcd.c (c) 1999 Cirrus Logic.
+//
+// These routines all end up calling fb_set_pixel(). That routine must
+// be provided in the target specific code.
+//
+//==========================================================================
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "fb_fonts.h"
+#include "vga_lookup.h"
+
+#if INCLUDE_LCD
+extern uchar bcolor;
+extern void fb_set_pixel(int X, int Y, uchar color);
+
+void fb_draw_line2(int x0, int y0, int x1, int y1, uchar color)
+ {
+ int i;
+ int steep = 1;
+ int sx, sy; /* step positive or negative (1 or -1) */
+ int dx, dy; /* delta (difference in X and Y between points) */
+ int e;
+
+ /*
+ * optimize for vertical and horizontal lines here
+ */
+
+ dx = (x1 > x0) ? (x1 - x0) : x0 - x1;
+ sx = ((x1 - x0) > 0) ? 1 : -1;
+ dy = (y1 > y0) ? (y1 - y0) : y0 - y1;
+ sy = ((y1 - y0) > 0) ? 1 : -1;
+ e = (dy << 1) - dx;
+ for (i = 0; i < dx; i++) {
+ if (steep) {
+ fb_set_pixel(x0,y0,color);
+ } else {
+ fb_set_pixel(y0,x0,color);
+ }
+ while (e >= 0) {
+ y0 += sy;
+ e -= (dx << 1);
+ }
+ x0 += sx;
+ e += (dy << 1);
+ }
+ }
+
+// ------------------------------------------------------------------
+// fb_draw_circle draws a circle at the specified location based on
+// bresenham's circle drawing algorithm
+void fb_draw_circle(ulong x, ulong y, ulong radius, uchar color)
+{
+ ulong xpos, ypos, d;
+
+ xpos = x;
+ ypos = radius;
+
+ d = 3 - (2 * ypos);
+
+ while(ypos >= xpos)
+ {
+ fb_set_pixel(x + xpos, y + ypos, color); // point in octant 1
+ fb_set_pixel(x - xpos, y + ypos, color); // point in octant 4
+ fb_set_pixel(x - xpos, y - ypos, color); // point in octant 5
+ fb_set_pixel(x + xpos, y - ypos, color); // point in octant 8
+ fb_set_pixel(x + ypos, y + xpos, color); // point in octant 2
+ fb_set_pixel(x - ypos, y + xpos, color); // point in octant 3
+ fb_set_pixel(x - ypos, y - xpos, color); // point in octant 6
+ fb_set_pixel(x + ypos, y - xpos, color); // point in octant 7
+
+ if (d < 0)
+ {
+ d = (d + (4 * xpos)) + 6;
+ }
+ else
+ {
+ d = (d + (4 * (xpos - ypos))) + 10;
+ ypos = ypos - 1;
+ }
+
+ xpos++;
+ }
+}
+
+void fb_draw_circle2(ulong xpos, ulong ypos, ulong radius, uchar color)
+{
+ int x;
+ int y = radius;
+ int d = -radius;
+ for(x = 1; x < (radius/1.414); x++)
+ { d += (2 * x) - 1;
+ if (d >= 0)
+ { y--;
+ d -= (2 * y); /* Must do this AFTER y-- */
+ }
+ // fb_set_pixel(x + xpos, y + ypos, color);
+ fb_set_pixel(xpos + x, ypos + y, color); // point in octant 1
+ fb_set_pixel(xpos - x, ypos + y, color); // point in octant 4
+ fb_set_pixel(xpos - x, ypos - y, color); // point in octant 5
+ fb_set_pixel(xpos + x, ypos - y, color); // point in octant 8
+ fb_set_pixel(xpos + y, ypos + x, color); // point in octant 2
+ fb_set_pixel(xpos - y, ypos + x, color); // point in octant 3
+ fb_set_pixel(xpos - y, ypos - x, color); // point in octant 6
+ fb_set_pixel(xpos + y, ypos - x, color); // point in octant 7
+ }
+}
+
+// ------------------------------------------------------------------
+// fb_draw_circle draws a filled circle at the specified location based on
+// bresenham's circle drawing algorithm
+//
+void fb_fill_circle(ulong x, ulong y, ulong radius, uchar color)
+{
+ ulong xpos, ypos, d;
+
+ xpos = x;
+ ypos = radius;
+
+ d = 3 - (2 * ypos);
+
+ while(ypos >= xpos)
+ {
+ fb_draw_line2(x - xpos, y + ypos, x + xpos, y + ypos, color);
+ fb_draw_line2(x - ypos, y + xpos, x + ypos, y + xpos, color);
+ fb_draw_line2(x - xpos, y - ypos, x + xpos, y - ypos, color);
+ fb_draw_line2(x - ypos, y - xpos, x + ypos, y - xpos, color);
+
+ if(d < 0)
+ {
+ d += (4 * xpos) + 6;
+ }
+ else
+ {
+ d += 10 + (4 * (xpos - ypos));
+ ypos--;
+ }
+
+ xpos++;
+ }
+}
+
+// ------------------------------------------------------------------
+// fb_print_char prints a character at the specified location.
+//
+void fb_print_char(uchar cchar, ulong x, ulong y, uchar color)
+{
+ ulong idx1, idx2;
+ uchar font_line, fcolor;
+
+ // printable characters only
+ if ((cchar < FIRST_CHAR) || (cchar > LAST_CHAR))
+ return;
+
+ // loop through each row of the font.
+ for(idx1 = 0; idx1 < FONT_HEIGHT; idx1++)
+ {
+ // read the byte which describes this row of the font.
+ font_line = fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1];
+
+ // loop through each column of this row.
+ for(idx2 = 0; idx2 < 8; idx2++)
+ {
+ // set the pixel based on the value of this bit of the font,
+ // using the requested or the backround color.
+ fcolor = font_line & 1 << ((FONT_WIDTH - 1) - idx2) ? color : bcolor;
+
+ fb_set_pixel(x + idx2, y + idx1, fcolor);
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+// fb_print_string prints a string at the specified location.
+//
+void
+fb_print_string(uchar *pcbuffer, ulong x, ulong y, uchar color)
+{
+ // loop through each character in the string.
+ while(*pcbuffer)
+ {
+ // print this character.
+ fb_print_char(*pcbuffer++, x, y, color);
+
+ // advance horizontaly past this character.
+ x += FONT_WIDTH;
+ }
+}
+
+// ------------------------------------------------------------------
+// fb_print_charx2 prints a double-sized character at the specified location.
+//
+void fb_print_charx2(char cchar, ulong x, ulong y, uchar color)
+{
+ ulong idx1, idx2;
+ ushort font_line;
+ uchar fcolor;
+
+ // printable characters only
+ if (((unsigned char)cchar < FIRST_CHAR) ||
+ ((unsigned char)cchar > LAST_CHAR))
+ return;
+
+ // loop through each row of the font.
+ for(idx1 = 0; idx1 < FONT_HEIGHT; idx1++)
+ {
+ // read the byte which describes this row of the font.
+ font_line = (fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1]) << 8;
+ if (FONT_WIDTH > 8) // get the second byte if present
+ {
+ font_line = fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1 + 1];
+ }
+
+ // loop through each column of this row.
+ for(idx2 = 0; idx2 < FONT_WIDTH; idx2++)
+ {
+ // determine the color of this pixel block.
+ fcolor = font_line & (1 << ((FONT_WIDTH - 1) - idx2)) ? color : bcolor;
+
+ // set the pixel block (2x2) based on the value of this bit of
+ // the font, using the requested or the backround color.
+ fb_set_pixel(x + (idx2 << 1), y + (idx1 << 1), fcolor);
+ fb_set_pixel(x + (idx2 << 1) + 1, y + (idx1 << 1), fcolor);
+ fb_set_pixel(x + (idx2 << 1), y + (idx1 << 1) + 1, fcolor);
+ fb_set_pixel(x + (idx2 << 1) + 1, y + (idx1 << 1) + 1, fcolor);
+ }
+ }
+}
+
+// ------------------------------------------------------------------
+// fb_print_stringx2 prints a string of double-sized characters at the
+// specified location.
+//
+void fb_print_stringx2(char *pcbuffer, ulong x, ulong y, uchar color)
+{
+ //
+ // loop through each character in the string.
+ //
+ while(*pcbuffer)
+ {
+ //
+ // print this character.
+ //
+ fb_print_charx2(*pcbuffer++, x, y, color);
+
+ //
+ // advance horizontaly past this character.
+ //
+ x += 16;
+ }
+}
+#endif
+
diff --git a/main/dev/fb_draw.h b/main/dev/fb_draw.h
new file mode 100644
index 0000000..4c5de0a
--- /dev/null
+++ b/main/dev/fb_draw.h
@@ -0,0 +1,8 @@
+extern void fb_draw_line2(int x0, int y0, int x1, int y1, uchar color);
+extern void fb_draw_circle(ulong x, ulong y, ulong radius, uchar color);
+extern void fb_draw_circle2(int xpos, int ypos, int radius, uchar color);
+extern void fb_fill_circle(ulong x, ulong y, ulong radius, uchar color);
+extern void fb_print_char(uchar cchar, ulong x, ulong y, uchar color);
+extern void fb_print_string(uchar *pcbuffer, ulong x, ulong y, uchar color);
+extern void fb_print_charx2(char cchar, ulong x, ulong y, uchar color);
+extern void fb_print_stringx2(char *pcbuffer, ulong x, ulong y, uchar color);
diff --git a/main/dev/fb_fonts.h b/main/dev/fb_fonts.h
new file mode 100644
index 0000000..9a96782
--- /dev/null
+++ b/main/dev/fb_fonts.h
@@ -0,0 +1,237 @@
+//------------------------------------------------------------------------
+// fb_fonts.h
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 10/18/03
+// Description: basic fonts for different screen sizes. 8x16
+// is good for VGA and above, 8x8 is good for QVGA
+// landscape (320 x 240), while 5x7 gives the most
+// characters on QVGA portrait mode (240 x 320).
+//
+// Note that 8x8 and 5x7 use one byte per font row,
+// but 5x7 uses only the upper 5 bits.
+//
+// To lookoup, subtract FIRST_CHAR from the character,
+// multiply x FONT_HEIGHT and get the next FONT_WIDTH
+// bytes. Thes efonts only support printable ascii
+// characters 0x20 to 0x7f
+//
+
+#define FIRST_CHAR 0x20
+#define LAST_CHAR 0x7F
+#define CURSOR_ON 0x7F
+#define CURSOR_OFF 0x20
+
+#ifdef USE_FONT8X8
+#define FONT_HEIGHT 8
+#define FONT_WIDTH 8
+#define FONT_STEP 8 // font rows are 8 bytes apart
+
+static uchar fb_font_data[LAST_CHAR-FIRST_CHAR+1][FONT_STEP] =
+{
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x20
+ { 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, }, // 0x21 !
+ { 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x22 "
+ { 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, }, // 0x23 #
+ { 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, }, // 0x24 $
+ { 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, }, // 0x25 %
+ { 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, }, // 0x26 &
+ { 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x27 '
+ { 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, }, // 0x28 (
+ { 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, }, // 0x29 )
+ { 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, }, // 0x2a *
+ { 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, }, // 0x2b +
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, }, // 0x2c ,
+ { 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, }, // 0x2d -
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, }, // 0x2e .
+ { 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, }, // 0x2f /
+ { 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, }, // 0x30 0
+ { 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, }, // 0x31 1
+ { 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, }, // 0x32 2
+ { 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, }, // 0x33 3
+ { 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, }, // 0x34 4
+ { 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, }, // 0x35 5
+ { 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, }, // 0x36 6
+ { 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, }, // 0x37 7
+ { 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, }, // 0x38 8
+ { 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, }, // 0x39 9
+ { 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, }, // 0x3a :
+ { 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, }, // 0x3b ;
+ { 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, }, // 0x3c <
+ { 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, }, // 0x3d =
+ { 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, }, // 0x3e >
+ { 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, }, // 0x3f ?
+ { 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, }, // 0x40 @
+ { 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, }, // 0x41 A
+ { 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, }, // 0x42 B
+ { 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, }, // 0x43 C
+ { 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, }, // 0x44 D
+ { 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, }, // 0x45 E
+ { 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, }, // 0x46 F
+ { 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, }, // 0x47 G
+ { 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, }, // 0x48 H
+ { 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x49 I
+ { 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, }, // 0x4a J
+ { 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, }, // 0x4b K
+ { 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, }, // 0x4c L
+ { 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, }, // 0x4d M
+ { 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, }, // 0x4e N
+ { 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, }, // 0x4f O
+ { 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, }, // 0x50 P
+ { 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, }, // 0x51 Q
+ { 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, }, // 0x52 R
+ { 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, }, // 0x53 S
+ { 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x54 T
+ { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, }, // 0x55 U
+ { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, }, // 0x56 V
+ { 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, }, // 0x57 W
+ { 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, }, // 0x58 X
+ { 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, }, // 0x59 Y
+ { 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, }, // 0x5a Z
+ { 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, }, // 0x5b [
+ { 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, }, // 0x5c '\'
+ { 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, }, // 0x5d ]
+ { 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, }, // 0x5e ^
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, }, // 0x5f _
+ { 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x60 `
+ { 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, }, // 0x61 a
+ { 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, }, // 0x62 b
+ { 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, }, // 0x63 c
+ { 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, }, // 0x64 d
+ { 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, }, // 0x65 e
+ { 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, }, // 0x66 f
+ { 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, }, // 0x67 g
+ { 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, }, // 0x68 h
+ { 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x69 i
+ { 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, }, // 0x6a j
+ { 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, }, // 0x6b k
+ { 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x6c l
+ { 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, }, // 0x6d m
+ { 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, }, // 0x6e n
+ { 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, }, // 0x6f o
+ { 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, }, // 0x70 p
+ { 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, }, // 0x71 q
+ { 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, }, // 0x72 r
+ { 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, }, // 0x73 s
+ { 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, }, // 0x74 t
+ { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, }, // 0x75 u
+ { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, }, // 0x76 v
+ { 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, }, // 0x77 w
+ { 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, }, // 0x78 x
+ { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, }, // 0x79 y
+ { 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, }, // 0x7a z
+ { 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, }, // 0x7b {
+ { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, }, // 0x7c |
+ { 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, }, // 0x7d }
+ { 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x7e ~
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, // block cursor
+};
+
+#endif
+
+#ifdef USE_FONT8X16
+#define FONT_WIDTH 8
+#define FONT_HEIGHT 16
+#define FONT_STEP 16 // font rows are 16 bytes apart
+
+const uchar fb_font_data[LAST_CHAR-FIRST_CHAR+1][FONT_STEP] = {
+// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x20
+{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, }, // 0x21 !
+{ 0x00, 0x00, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x22 "
+{ 0x00, 0x00, 0x00, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x23 #
+{ 0x00, 0x10, 0x10, 0x7c, 0x92, 0x90, 0x90, 0x7c, 0x12, 0x12, 0x92, 0x7c, 0x10, 0x10, 0x00, 0x00, }, // 0x24 $
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x94, 0x68, 0x10, 0x2c, 0x52, 0x8c, 0x00, 0x00, 0x00, 0x00, }, // 0x25 %
+{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x56, 0x8c, 0x88, 0x8c, 0x76, 0x00, 0x00, 0x00, 0x00, }, // 0x26 &
+{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x27 '
+{ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x28 (
+{ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, }, // 0x29 )
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0xfe, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2a *
+{ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2b +
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, }, // 0x2c ,
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2d -
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, }, // 0x2e .
+{ 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2f /
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x30 0
+{ 0x00, 0x00, 0x00, 0x08, 0x18, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x31 1
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x32 2
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x33 3
+{ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x34 4
+{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x35 5
+{ 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x36 6
+{ 0x00, 0x00, 0x00, 0x7e, 0x42, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x37 7
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x38 8
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, }, // 0x39 9
+{ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x3a :
+{ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, }, // 0x3b ;
+{ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x3c <
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x3d =
+{ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x3e >
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x3f ?
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x4e, 0x52, 0x52, 0x4e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x40 @
+{ 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x41 A
+{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, }, // 0x42 B
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x43 C
+{ 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, }, // 0x44 D
+{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x45 E
+{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x46 F
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, }, // 0x47 G
+{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x48 H
+{ 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x49 I
+{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x4a J
+{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x4b K
+{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x4c L
+{ 0x00, 0x00, 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, }, // 0x4d M
+{ 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x4e N
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x4f O
+{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x50 P
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x4a, 0x3c, 0x04, 0x06, 0x00, 0x00, }, // 0x51 Q
+{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x52 R
+{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x20, 0x18, 0x04, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x53 S
+{ 0x00, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x54 T
+{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x55 U
+{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, }, // 0x56 V
+{ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x57 W
+{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x58 X
+{ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x44, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x59 Y
+{ 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x5a Z
+{ 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x5b [
+{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x5c '\'
+{ 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x5d ]
+{ 0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x5e ^
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, }, // 0x5f _
+{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x60 `
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, }, // 0x61 a
+{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, }, // 0x62 b
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x63 c
+{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, }, // 0x64 d
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x65 e
+{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, }, // 0x66 f
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x42, 0x3c, 0x00, 0x00, }, // 0x67 g
+{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x68 h
+{ 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x69 i
+{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1c, 0x00, 0x00, }, // 0x6a j
+{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x42, 0x44, 0x78, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x6b k
+{ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x6c l
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xee, 0x92, 0x92, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00, }, // 0x6d m
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x6e n
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x6f o
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x00, }, // 0x70 p
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x03, 0x00, 0x00, }, // 0x71 q
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x72 r
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x38, 0x04, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x73 s
+{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, }, // 0x74 t
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, }, // 0x75 u
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x76 v
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x77 w
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x78 x
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x04, 0x78, 0x00, 0x00, }, // 0x79 y
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x7a z
+{ 0x00, 0x00, 0x00, 0x06, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, }, // 0x7b {
+{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x7c |
+{ 0x00, 0x00, 0x00, 0x60, 0x10, 0x10, 0x10, 0x0c, 0x10, 0x10, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, }, // 0x7d }
+{ 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x7e ~
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, // 0x7f block cursor
+};
+
+#endif
diff --git a/main/dev/smsc911x.c b/main/dev/smsc911x.c
new file mode 100644
index 0000000..bf4e7d0
--- /dev/null
+++ b/main/dev/smsc911x.c
@@ -0,0 +1,392 @@
+//==========================================================================
+//
+// smsc911x.c
+//
+//
+//
+// Author(s): Jay Monkman <jtm@lopingdog.com>
+// Contributors:
+// Date: 06-07-2007
+// Description: Driver for the SMSC 911x and 912x families of
+// ethernet controllers
+//
+//--------------------------------------------------------------------------
+
+#include "config.h"
+#if INCLUDE_ETHERNET
+#include "cpuio.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "ether.h"
+#include "smsc911x.h"
+
+
+//--------------------------------------------------------------------------
+// smsc911x_mac_read()
+//
+// Reads a register mapped through the MAC_CSR register
+//--------------------------------------------------------------------------
+static ulong smsc911x_mac_read(int reg)
+{
+ while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
+ continue;
+ }
+
+ MAC_CSR_CMD = MAC_RD_CMD(reg);
+
+ while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
+ continue;
+ }
+
+ return MAC_CSR_DATA;
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_mac_write()
+//
+// Writes a register mapped through the MAC_CSR register
+//--------------------------------------------------------------------------
+static void smsc911x_mac_write(int reg, ulong val)
+{
+ while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
+ continue;
+ }
+
+ MAC_CSR_DATA = val;
+ MAC_CSR_CMD = MAC_WR_CMD(reg);
+
+ while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
+ continue;
+ }
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_phy_read()
+//
+// Reads a PHY register
+//--------------------------------------------------------------------------
+#if 0
+static ulong smsc911x_phy_read(int reg)
+{
+ while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) {
+ continue;
+ }
+
+ smsc911x_mac_write(MII_ACC, MII_ACC_ADDR(1) | MII_ACC_REG(reg));
+
+ while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) {
+ continue;
+ }
+
+ return smsc911x_mac_read(MII_DATA);
+}
+#endif
+
+//--------------------------------------------------------------------------
+// smsc911x_phy_write()
+//
+// Writes a PHY register
+//--------------------------------------------------------------------------
+static void smsc911x_phy_write(int reg, ushort val)
+{
+ while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) {
+ continue;
+ }
+
+ smsc911x_mac_write(MII_DATA, val);
+
+ smsc911x_mac_write(MII_ACC, (MII_ACC_ADDR(1) |
+ MII_ACC_REG(reg) |
+ MII_ACC_WR));
+
+ while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) {
+ continue;
+ }
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_reset()
+//
+// This function performs a soft reset of the controller
+//--------------------------------------------------------------------------
+void smsc911x_reset(void)
+{
+
+ HW_CFG |= HW_CFG_SRST;
+
+ /* Wait for it */
+ while (HW_CFG & HW_CFG_SRST) {
+ continue;
+ }
+
+ PMT_CTRL |= PMT_CTRL_PHY_RST;
+
+ /* Wait for it */
+ while (PMT_CTRL & PMT_CTRL_PHY_RST) {
+ continue;
+ }
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_set_mac()
+//
+// This function puts the mac address from BinEnetAddr into the smsc911x.
+//--------------------------------------------------------------------------
+static void smsc911x_set_mac(void)
+{
+ ulong i;
+
+ i = ((BinEnetAddr[5] << 8) |
+ (BinEnetAddr[4] << 0));
+ smsc911x_mac_write(ADDRH, i);
+
+
+ i = ((BinEnetAddr[3] << 24) |
+ (BinEnetAddr[2] << 16) |
+ (BinEnetAddr[1] << 8) |
+ (BinEnetAddr[0] << 0));
+ smsc911x_mac_write(ADDRL, i);
+
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_init()
+//
+// This code initializes the ethernet controller.
+//--------------------------------------------------------------------------
+int smsc911x_init(void)
+{
+ ulong val;
+
+ /* Set the PHY clock config */
+ HW_CFG = (HW_CFG & ~HW_CFG_PHY_CLK_MASK) | HW_CFG_PHY_CLK_INT;
+
+ /* reset the controller, PHY */
+ smsc911x_reset();
+
+ switch(ID_REV) {
+ case ID_REV_CHIP_9118:
+ if (EtherVerbose & SHOW_DRIVER_DEBUG)
+ printf("Found SMSC9118\n");
+ break;
+ case ID_REV_CHIP_9211:
+ if (EtherVerbose & SHOW_DRIVER_DEBUG)
+ printf("Found SMSC9211\n");
+ break;
+ case ID_REV_CHIP_9215:
+ if (EtherVerbose & SHOW_DRIVER_DEBUG)
+ printf("Found SMSC9215\n");
+ break;
+ case ID_REV_CHIP_9218:
+ if (EtherVerbose & SHOW_DRIVER_DEBUG)
+ printf("Found SMSC9218\n");
+ break;
+ default:
+ printf("Unidentified Ethernet controller: 0x%x\n", ID_REV);
+ return -1;
+ }
+
+ // set the mac address
+ smsc911x_set_mac();
+
+ /* These came from SMSC's example driver */
+ HW_CFG = (HW_CFG & ~HW_CFG_TX_FIF_MASK) | HW_CFG_TX_FIF_SZ(5);
+
+ AFC_CFG = (AFC_CFG_AFC_HI(0x6e) |
+ AFC_CFG_AFC_LO(0x37) |
+ AFC_CFG_BACK_DUR(0x4));
+
+ /* Configure the GPIOs as LEDs */
+ GPIO_CFG = (GPIO_CFG_LED3_EN |
+ GPIO_CFG_LED2_EN |
+ GPIO_CFG_LED1_EN |
+ GPIO_CFG_GPIOBUF(2) |
+ GPIO_CFG_GPIOBUF(1) |
+ GPIO_CFG_GPIOBUF(0));
+
+ /* Configure PHY to advertise all speeds */
+ smsc911x_phy_write(PHY_ANAR, (PHY_ANAR_100TX_FD |
+ PHY_ANAR_100TX |
+ PHY_ANAR_10T_FD |
+ PHY_ANAR_10T |
+ PHY_ANAR_SF));
+
+ /* Enable auto negotiation */
+ smsc911x_phy_write(PHY_BCR, (PHY_BCR_ANE |
+ PHY_BCR_RAN));
+
+ /* Set the controller to buffer entire packets */
+ HW_CFG |= HW_CFG_SF;
+
+ /* Configure FIFO thresholds */
+ FIFO_INT = FIFO_INT_TDAL(0xff);
+
+ /* Enable the MAC */
+ val = smsc911x_mac_read(MAC_CR);
+ val |= (MAC_CR_TXEN | MAC_CR_RXEN);
+ smsc911x_mac_write(MAC_CR, val);
+
+ TX_CFG |= TX_CFG_TX_ON;
+
+ RX_CFG = 0;
+
+ return 0;
+}
+
+void
+smsc911x_enable_multicast_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val |= MAC_CR_MCPAS;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+void
+smsc911x_disable_multicast_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val &= ~MAC_CR_MCPAS;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+void
+smsc911x_enable_promiscuous_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val |= MAC_CR_PRMS;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+void
+smsc911x_disable_promiscuous_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val &= ~MAC_CR_PRMS;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+void
+smsc911x_enable_broadcast_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val |= MAC_CR_BCAST;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+void
+smsc911x_disable_broadcast_reception(void)
+{
+ ulong val;
+ val = smsc911x_mac_read(MAC_CR);
+ val &= ~MAC_CR_BCAST;
+ smsc911x_mac_write(MAC_CR, val);
+}
+
+
+//--------------------------------------------------------------------------
+// smsc911x_tx()
+//
+// This function transmits a packet
+//--------------------------------------------------------------------------
+int smsc911x_tx(uchar *txbuf, ulong len)
+{
+ int avail;
+ ulong cmda;
+ ulong cmdb;
+ int i;
+ ulong *p;
+ vulong tmp __attribute__((unused));
+
+ tmp = TX_STATUS_FIFO_PORT;
+
+ /* Wait until space is available for the packet */
+ do {
+ avail = TX_FIFO_INF & TX_FIFO_TDFREE_MASK;
+ } while (avail < len);
+
+ cmda = (TX_CMD_FS |
+ TX_CMD_LS |
+ TX_CMD_BS(len));
+
+ cmdb = TX_CMD_PKTLEN(len);
+
+ TX_FIFO_PORT = cmda;
+ TX_FIFO_PORT = cmdb;
+ p = (ulong*)txbuf;
+
+ for (i = 0; i < (len/4); i++) {
+ TX_FIFO_PORT = p[i];
+
+ }
+
+ if ((len & 0x3) != 0) {
+ int index = len & ~3;
+ int num = len & 3;
+ ulong last = 0;
+
+ for (i = 0; i < num; i++) {
+ last |= (txbuf[index + i] << (i * 8));
+ }
+
+ TX_FIFO_PORT = last;
+ }
+
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// smsc911x_rx()
+//
+// This function checks to see if the smsc911x has a receive buffer
+// ready. If so, it copies it into the buffer pointed to by pktbuf
+//--------------------------------------------------------------------------
+int smsc911x_rx(uchar *pktbuf)
+{
+ ulong status;
+ int i;
+ int size;
+ ulong inf = RX_FIFO_INF;
+ ulong *p = (ulong *)pktbuf;
+
+ if (((inf >> 16) & 0xffff) == 0) {
+ return 0;
+ }
+
+ status = RX_STATUS_FIFO_PORT;
+ size = (status & RX_STATUS_PL_MASK) >> RX_STATUS_PL_SHIFT;
+ if (size == 0) {
+ return 0;
+ }
+ if ((status & RX_STATUS_ES) == 0) {
+ for (i = 0; i < ((size + 3) / 4); i++) {
+ p[i] = RX_FIFO_PORT;
+ }
+
+ return size - 4;
+ } else {
+ /* Fast forward */
+ if (size >= 16) {
+ RX_DP_CTL = RX_DP_RX_FFWD;
+ while (RX_DP_CTL & RX_DP_RX_FFWD) {
+ continue;
+ }
+ } else {
+ ulong tmp;
+ for (i = 0; i < ((size + 3)/4); i++) {
+ tmp = RX_FIFO_PORT;
+ }
+ tmp = tmp; // eliminate 'set-but-not-unused' warning
+ }
+ return 0;
+ }
+}
+
+
+#endif // INCLUDE_ETHERNET
+
diff --git a/main/dev/smsc911x.h b/main/dev/smsc911x.h
new file mode 100644
index 0000000..64d5819
--- /dev/null
+++ b/main/dev/smsc911x.h
@@ -0,0 +1,304 @@
+//==========================================================================
+//
+// smsc911x.h
+//
+//
+// Author(s): Jay Monkman <jtm@lopingdog.com>
+// Contributors:
+// Date: 06-07-2007
+// Description: This file contains definitions for the SMSC 911x and 912x
+// families of ethernet controllers.
+//
+//--------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------
+// cpuio.h must provide SMSC911X_BASE_ADDRESS
+// defines
+#define SMSC_REG(_x_) *(vulong *)(SMSC911X_BASE_ADDRESS + _x_)
+
+// ------------------------------------------------------------------------
+// Directly visible registers.
+#define RX_FIFO_PORT SMSC_REG(0x00)
+#define TX_FIFO_PORT SMSC_REG(0x20)
+#define RX_FIFO_PORT_INC SMSC_REG(0x100)
+#define TX_FIFO_PORT_INC SMSC_REG(0x120)
+#define RX_STATUS_FIFO_PORT SMSC_REG(0x40)
+#define RX_STATUS_FIFO_PEEK SMSC_REG(0x44)
+#define RX_STATUS_FF (1 << 30)
+#define RX_STATUS_PL_MASK (0x3fff << 16)
+#define RX_STATUS_PL_SHIFT (16)
+#define RX_STATUS_ES (1 << 15)
+#define RX_STATUS_BF (1 << 13)
+#define RX_STATUS_LE (1 << 12)
+#define RX_STATUS_RF (1 << 11)
+#define RX_STATUS_MF (1 << 10)
+#define RX_STATUS_FTL (1 << 7)
+#define RX_STATUS_CS (1 << 6)
+#define RX_STATUS_FT (1 << 5)
+#define RX_STATUS_RWTO (1 << 4)
+#define RX_STATUS_ME (1 << 3)
+#define RX_STATUS_DB (1 << 2)
+#define RX_STATUS_CE (1 << 1)
+
+#define TX_STATUS_FIFO_PORT SMSC_REG(0x48)
+#define TX_STATUS_FIFO_PEEK SMSC_REG(0x4c)
+#define TX_STATUS_FIFO_ES (1 << 15)
+#define TX_STATUS_FIFO_LOC (1 << 11)
+#define TX_STATUS_FIFO_NC (1 << 10)
+#define TX_STATUS_FIFO_LC (1 << 9)
+#define TX_STATUS_FIFO_EC (1 << 8)
+#define TX_STATUS_FIFO_ED (1 << 2)
+#define TX_STATUS_FIFO_UE (1 << 1)
+#define TX_STATUS_FIFO_D (1 << 0)
+#define TX_STATUS_FIFO_TAG_MASK (0xffff << 16)
+
+#define ID_REV SMSC_REG(0x50)
+#define ID_REV_ID_MASK (0xffff << 16)
+#define ID_REV_CHIP_9118 (0x0115 << 16)
+#define ID_REV_CHIP_9211 (0x9211 << 16)
+#define ID_REV_CHIP_9215 (0x115A << 16)
+#define ID_REV_CHIP_9218 (0x118A << 16)
+#define ID_REV_REV_MASK (0xffff << 0)
+
+#define INT_STS SMSC_REG(0x58)
+#define INT_STS_SW_INT (1 << 21)
+#define INT_STS_TXSTOP_INT (1 << 25)
+#define INT_STS_RXSTOP_INT (1 << 24)
+#define INT_STS_RXDFH_INT (1 << 23)
+#define INT_STS_TIOC_INT (1 << 21)
+#define INT_STS_RXD_INT (1 << 20)
+#define INT_STS_GPT_INT (1 << 19)
+#define INT_STS_PHY_INT (1 << 18)
+#define INT_STS_PMT_INT (1 << 17)
+#define INT_STS_TXSO_INT (1 << 16)
+#define INT_STS_RWT_INT (1 << 15)
+#define INT_STS_RXE_INT (1 << 14)
+#define INT_STS_TXE_INT (1 << 13)
+#define INT_STS_TDFU_INT (1 << 11)
+#define INT_STS_TDFO_INT (1 << 10)
+#define INT_STS_TDFA_INT (1 << 9)
+#define INT_STS_TSFF_INT (1 << 8)
+#define INT_STS_TSFL_INT (1 << 7)
+#define INT_STS_RDXF_INT (1 << 6)
+#define INT_STS_RDFL_INT (1 << 5)
+#define INT_STS_RSFF_INT (1 << 4)
+#define INT_STS_RSFL_INT (1 << 3)
+#define INT_STS_GPIO2_INT (1 << 2)
+#define INT_STS_GPIO1_INT (1 << 1)
+#define INT_STS_GPIO0_INT (1 << 0)
+
+#define BYTE_TEST SMSC_REG(0x64)
+#define BYTE_TEST_VAL (0x87654321)
+
+#define FIFO_INT SMSC_REG(0x68)
+#define FIFO_INT_TDAL(x) (((x) & 0xff) << 24)
+#define FIFO_INT_TSL(x) (((x) & 0xff) << 16)
+#define FIFO_INT_RDAL(x) (((x) & 0xff) << 8)
+#define FIFO_INT_RSL(x) (((x) & 0xff) << 0)
+
+#define RX_CFG SMSC_REG(0x6c)
+#define RX_CFG_END_ALIGN4 (0 << 30)
+#define RX_CFG_END_ALIGN16 (1 << 30)
+#define RX_CFG_END_ALIGN32 (2 << 30)
+#define RX_CFG_FORCE_DISCARD (1 << 15)
+#define RX_CFG_RXDOFF(x) (((x) & 0x1f) << 8)
+
+#define TX_CFG SMSC_REG(0x70)
+#define TX_CFG_TXS_DUMP (1 << 15)
+#define TX_CFG_TXD_DUMP (1 << 14)
+#define TX_CFG_TXSAO (1 << 2)
+#define TX_CFG_TX_ON (1 << 1)
+#define TX_CFG_STOP_TX (1 << 0)
+
+#define HW_CFG SMSC_REG(0x74)
+#define HW_CFG_TTM (1 << 21)
+#define HW_CFG_SF (1 << 20)
+#define HW_CFG_TX_FIF_SZ(x) (((x) & 0xf) << 16)
+#define HW_CFG_TX_FIF_MASK (0xf << 16)
+#define HW_CFG_TR(x) (((x) & 0x3) << 12)
+#define HW_CFG_PHY_CLK_MASK (3 << 5)
+#define HW_CFG_PHY_CLK_INT (0 << 5)
+#define HW_CFG_PHY_CLK_EXT (1 << 5)
+#define HW_CFG_PHY_CLK_DIS (2 << 5)
+#define HW_CFG_SMI_SEL (1 << 3)
+#define HW_CFG_EXT_PHY_EN (1 << 2)
+#define HW_CFG_BITMD_32 (1 << 2)
+#define HW_CFG_SRST_TO (1 << 1)
+#define HW_CFG_SRST (1 << 0)
+
+#define RX_DP_CTL SMSC_REG(0x78)
+#define RX_DP_RX_FFWD (1 << 31)
+
+#define RX_FIFO_INF SMSC_REG(0x7c)
+#define TX_FIFO_RXSUSED_MASK (0x00ff << 16)
+#define TX_FIFO_RXDUSED_MASK (0xffff << 0)
+
+#define TX_FIFO_INF SMSC_REG(0x80)
+#define TX_FIFO_TXSUSED_MASK (0x00ff << 16)
+#define TX_FIFO_TDFREE_MASK (0xffff << 0)
+
+#define PMT_CTRL SMSC_REG(0x84)
+#define PMT_CTRL_PM_MODE_D0 (0 << 12)
+#define PMT_CTRL_PM_MODE_D1 (1 << 12)
+#define PMT_CTRL_PM_MODE_D2 (2 << 12)
+#define PMT_CTRL_PHY_RST (1 << 10)
+#define PMT_CTRL_WOL_EN (1 << 9)
+#define PMT_CTRL_ED_EN (1 << 8)
+#define PMT_CTRL_PME_TYPE (1 << 6)
+#define PMT_CTRL_WUPS_NONE (0 << 4)
+#define PMT_CTRL_WUPS_D2 (1 << 4)
+#define PMT_CTRL_WUPS_D1 (2 << 4)
+#define PMT_CTRL_WUPS_MULT (3 << 4)
+#define PMT_CTRL_PME_IND (1 << 3)
+#define PMT_CTRL_PME_POL (1 << 2)
+#define PMT_CTRL_PME_EN (1 << 1)
+#define PMT_CTRL_PME_READY (1 << 0)
+
+#define GPIO_CFG SMSC_REG(0x88)
+#define GPIO_CFG_LED3_EN (1 << 30)
+#define GPIO_CFG_LED2_EN (1 << 29)
+#define GPIO_CFG_LED1_EN (1 << 28)
+#define GPIO_CFG_GPIO_INT_POL(x) (1 << (((x) & 0x3) + 24))
+#define GPIO_CFG_EEPR_EEPROM (0 << 20)
+#define GPIO_CFG_GPIOBUF(x) (1 << (((x) & 0x3) + 16))
+#define GPIO_CFG_GPIODIR(x) (1 << (((x) & 0x3) + 8))
+
+#define GPT_CFG SMSC_REG(0x8c)
+#define GPT_CFG_TIMER_EN (1 << 29)
+#define GPT_CFG_GPT_LOAD(x) (((x) & 0xffff) << 0)
+
+#define GPT_CNT SMSC_REG(0x90)
+#define GPT_CNT_MASK (0xffff << 0)
+
+#define WORD_SWAP SMSC_REG(0x98)
+#define WORD_SWAP_BIG (0xFFFFFFFF)
+
+#define FREE_RUN SMSC_REG(0x9c)
+
+#define RX_DROP SMSC_REG(0xa0)
+
+#define MAC_CSR_CMD SMSC_REG(0xa4)
+#define MAC_CSR_CMD_CSR_BUSY (0x80000000)
+#define MAC_CSR_CMD_RNW (0x40000000)
+#define MAC_RD_CMD(x) (((x) & 0xff) | (MAC_CSR_CMD_CSR_BUSY |\
+ MAC_CSR_CMD_RNW))
+#define MAC_WR_CMD(x) (((x) & 0xff) | (MAC_CSR_CMD_CSR_BUSY))
+
+#define MAC_CSR_DATA SMSC_REG(0xa8)
+
+#define AFC_CFG SMSC_REG(0xac)
+#define AFC_CFG_AFC_HI(x) (((x) & 0xff) << 16)
+#define AFC_CFG_AFC_LO(x) (((x) & 0xff) << 8)
+#define AFC_CFG_BACK_DUR(x) (((x) & 0xf) << 4)
+#define AFC_CFG_FCMULT (1 << 3)
+#define AFC_CFG_FCBRD (1 << 2)
+#define AFC_CFG_FCADD (1 << 1)
+#define AFC_CFG_FCANY (1 << 0)
+
+#define E2P_CMD SMSC_REG(0xb0)
+#define E2P_DATA SMSC_REG(0xb4)
+
+// ----------------------------------------------------------
+// Registers available via MAC_CSR_CMD/MAC_CSR_DATA registers
+#define MAC_CR (0x1)
+#define MAC_CR_RXALL (1 << 31)
+#define MAC_CR_RCVOWN (1 << 23)
+#define MAC_CR_LOOPBK (1 << 21)
+#define MAC_CR_FDPX (1 << 20)
+#define MAC_CR_MCPAS (1 << 18)
+#define MAC_CR_PRMS (1 << 18)
+#define MAC_CR_INVFILT (1 << 17)
+#define MAC_CR_PASSBAD (1 << 16)
+#define MAC_CR_HO (1 << 15)
+#define MAC_CR_HPFILT (1 << 13)
+#define MAC_CR_LCOLL (1 << 12)
+#define MAC_CR_BCAST (1 << 11)
+#define MAC_CR_DISRTY (1 << 10)
+#define MAC_CR_PADSTR (1 << 8)
+#define MAC_CR_BOLMT10 (0 << 6)
+#define MAC_CR_BOLMT8 (1 << 6)
+#define MAC_CR_BOLMT4 (2 << 6)
+#define MAC_CR_BOLMT1 (3 << 6)
+#define MAC_CR_DFCHK (1 << 5)
+#define MAC_CR_TXEN (1 << 3)
+#define MAC_CR_RXEN (1 << 2)
+
+#define ADDRH (0x2)
+#define ADDRL (0x3)
+#define HASHH (0x4)
+#define HASHL (0x5)
+
+#define MII_ACC (0x6)
+#define MII_ACC_ADDR(x) (((x) & 0x1f) << 11)
+#define MII_ACC_REG(x) (((x) & 0x1f) << 6)
+#define MII_ACC_WR (1 << 1)
+#define MII_ACC_BUSY (1 << 0)
+
+#define MII_DATA (0x7)
+#define FLOW (0x8)
+#define VLAN1 (0x9)
+#define VLAN2 (0xa)
+#define WUFF (0xb)
+#define WUCSR (0xc)
+
+// ----------------------------------------------------------
+// PHY Registers
+#define PHY_BCR 0
+#define PHY_BCR_RESET (1 << 15)
+#define PHY_BCR_LOOP (1 << 14)
+#define PHY_BCR_SPEED (1 << 13)
+#define PHY_BCR_ANE (1 << 12)
+#define PHY_BCR_PD (1 << 11)
+#define PHY_BCR_RAN (1 << 9)
+#define PHY_BCR_FD (1 << 8)
+#define PHY_BCR_CT (1 << 7)
+
+#define PHY_BSR 1
+#define PHY_PHY1 2
+#define PHY_PHY2 3
+#define PHY_ANAR 4
+#define PHY_ANAR_NP (1 << 15)
+#define PHY_ANAR_RF (1 << 13)
+#define PHY_ANAR_PAUSE(x) (((x) & 0x3) << 10)
+#define PHY_ANAR_100T4 (1 << 9)
+#define PHY_ANAR_100TX_FD (1 << 8)
+#define PHY_ANAR_100TX (1 << 7)
+#define PHY_ANAR_10T_FD (1 << 6)
+#define PHY_ANAR_10T (1 << 5)
+#define PHY_ANAR_SF (0x01)
+
+
+#define PHY_ANLPAR 5
+#define PHY_ANER 6
+#define PHY_MCSR 17
+#define PHY_SMR 18
+#define PHY_SCSI 27
+#define PHY_ISR 29
+#define PHY_IMR 30
+#define PHY_PSCSR 31
+
+
+// ----------------------------------------------------------
+// TX and RX command definitions
+#define TX_CMD_IC (1 << 31)
+#define TX_CMD_BEA(x) (((x) & 0x3) << 24)
+#define TX_CMD_DS(x) (((x) & 0x1f) << 16)
+#define TX_CMD_FS (1 << 13)
+#define TX_CMD_LS (1 << 12)
+#define TX_CMD_BS(x) (((x) & 0x7ff) << 0)
+#define TX_CMD_TAG(x) (((x) & 0xffff) << 16)
+#define TX_CMD_CRCDIS (1 << 13)
+#define TX_CMD_PKTLEN(x) (((x) & 0x7ff) << 0)
+
+
+
+void smsc911x_reset(void);
+int smsc911x_rx(uchar *);
+int smsc911x_tx(uchar *, ulong);
+int smsc911x_init(void);
+void smsc911x_enable_promiscuous_reception(void);
+void smsc911x_disable_promiscuous_reception(void);
+void smsc911x_enable_multicast_reception(void);
+void smsc911x_disable_multicast_reception(void);
+void smsc911x_enable_broadcast_reception(void);
+void smsc911x_disable_broadcast_reception(void);
diff --git a/main/dev/uart16550.c b/main/dev/uart16550.c
new file mode 100644
index 0000000..0326d7a
--- /dev/null
+++ b/main/dev/uart16550.c
@@ -0,0 +1,195 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * FILENAME_HERE
+ *
+ * Generic (hopefully) 16550 uart code for use as a MicroMonitor
+ * console serial port driver.
+ *
+ * The baud-rate divisor can be derived in one of two ways:
+ * If BRD_115200 is defined, then this code assumes that the full
+ * set of BRD_XXX definitions are defined (in config.h) and they
+ * are used. If BRD_115200 is not defined, then this driver assumes
+ * the getUartDivisor() function is externally provided by the
+ * port-specific code.
+ *
+ * The base address of the UART used as the console port must be
+ * defined as CONSOLE_UART_BASE (also in config.h).
+ *
+ * Also, if the uart is configured in the memory map such that the
+ * gap between registers is not 1, then set SIO_STEP (see uart16550.h)
+ * to 2 or 4 appropriately.
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#include "uart16550.h"
+
+
+#define CONSOLE(offset) *(volatile unsigned char *)(CONSOLE_UART_BASE+offset)
+
+#ifdef MORE_GOTACHAR
+extern void MORE_GOTACHAR();
+#endif
+#ifdef MORE_GETCHAR
+extern void MORE_GETCHAR();
+#endif
+#ifdef MORE_PUTCHAR
+extern void MORE_PUTCHAR();
+#endif
+
+/* Establish default initialization values that can be overridden
+ * in config.h:
+ */
+#ifndef MCTL_DEFAULT
+#define MCTL_DEFAULT (SIO_MCTL_DTR | SIO_MCTL_RTS)
+#endif
+#ifndef FCTL_DEFAULT
+#define FCTL_DEFAULT (SIO_FCTL_FEN | SIO_FCTL_RXDC | SIO_FCTL_TXDC)
+#endif
+#ifndef SPR_DEFAULT
+#define SPR_DEFAULT 0x00 // Clear scratchpad
+#endif
+#ifndef IEN_DEFAULT
+#define IEN_DEFAULT 0x00 // Ints used
+#endif
+#ifndef LCTL_DEFAULT
+#define LCTL_DEFAULT SIO_LCTL_W8
+#endif
+
+/* getDlLsb():
+ * Populate hi & lo, default to 9600...
+ */
+#ifdef BRD_115200
+int
+getUartDivisor(int baud, unsigned char *hi, unsigned char *lo)
+{
+ switch(baud) {
+ case 115200:
+ *lo = BRD_115200;
+ break;
+ case 57600:
+ *lo = BRD_57600;
+ break;
+ case 38400:
+ *lo = BRD_38400;
+ break;
+ case 19200:
+ *lo = BRD_19200;
+ break;
+ case 9600:
+ *lo = BRD_9600;
+ break;
+ default:
+ return(-1);
+ }
+ *hi = 0;
+ return(0);
+}
+#endif
+
+int
+ConsoleBaudSet(int baud)
+{
+ unsigned char tmp, hi, lo;
+
+ /* If either getDivisor returns -1 or both hi & lo are zero we
+ * return failure to indicate that the requested baud rate could
+ * not be established.
+ */
+ if (getUartDivisor(baud,&hi,&lo) == -1)
+ return(-1);
+ if ((hi == 0) && (lo == 0))
+ return(-1);
+
+ tmp = CONSOLE(SIO_LCTL); /* Save linectl reg */
+ CONSOLE(SIO_LCTL) = SIO_LCTL_DLAB;
+ CONSOLE(SIO_BAUDLO) = lo; /* Set baud */
+ CONSOLE(SIO_BAUDHI) = hi;
+ CONSOLE(SIO_LCTL) = tmp; /* Restore linectl reg */
+ return(0);
+}
+
+
+void
+InitUART(int baud)
+{
+ unsigned char tmp, hi, lo;
+
+ getUartDivisor(baud,&hi,&lo);
+
+ CONSOLE(SIO_LCTL) = SIO_LCTL_DLAB;
+ CONSOLE(SIO_BAUDLO) = lo; /* Set baud */
+ CONSOLE(SIO_BAUDHI) = hi;
+ CONSOLE(SIO_LCTL) = LCTL_DEFAULT; /* 8-bits, no parity */
+ CONSOLE(SIO_MCTL) = MCTL_DEFAULT;
+ tmp = CONSOLE(SIO_LSTAT); /* clear line stat */
+ tmp = CONSOLE(SIO_RXD); /* read receive buffer */
+ tmp = tmp; /* eliminate unused warning */
+ CONSOLE(SIO_IEN) = IEN_DEFAULT;
+ CONSOLE(SIO_FCTL) = FCTL_DEFAULT;
+ CONSOLE(SIO_SPR) = SPR_DEFAULT;
+}
+
+int
+target_console_empty(void)
+{
+ if (CONSOLE(SIO_LSTAT) & SIO_LSTAT_TRDY)
+ return(0);
+ return(1);
+}
+
+int
+target_putchar(char c)
+{
+ while(!(CONSOLE(SIO_LSTAT) & SIO_LSTAT_TRDY));
+ CONSOLE(SIO_TXD) = c;
+#ifdef MORE_PUTCHAR
+ MORE_PUTCHAR(c);
+#endif
+ return((int)c);
+}
+
+int
+target_getchar(void)
+{
+ char c;
+
+#ifdef MORE_GETCHAR
+ if (MORE_GOTACHAR())
+ c = MORE_GETCHAR();
+ else
+#endif
+ c = CONSOLE(SIO_RXD);
+ return((int)c);
+}
+
+int
+target_gotachar(void)
+{
+ if (CONSOLE(SIO_LSTAT) & SIO_LSTAT_RRDY)
+ return(1);
+#ifdef MORE_GOTACHAR
+ if (MORE_GOTACHAR())
+ return(1);
+#endif
+ return(0);
+}
diff --git a/main/dev/uart16550.h b/main/dev/uart16550.h
new file mode 100644
index 0000000..3700445
--- /dev/null
+++ b/main/dev/uart16550.h
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * uart16550.h
+ *
+ * Defines for standard Dual Uart
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+
+// If other than 1, SIO_STEP must be defined in config.h
+#ifndef SIO_STEP
+#define SIO_STEP 1
+#endif
+
+// register defines
+#define SIO_RXD (0 * SIO_STEP) // receive data, read, dlab = 0
+#define SIO_TXD (0 * SIO_STEP) // transmit data, write, dlab = 0
+#define SIO_BAUDLO (0 * SIO_STEP) // baud divisor 0-7, read/write, dlab = 1
+#define SIO_IEN (1 * SIO_STEP) // interrupt enable, read/write, dlab = 0
+#define SIO_BAUDHI (1 * SIO_STEP) // baud divisor 8-15, read/write, dlab = 1
+#define SIO_ISTAT (2 * SIO_STEP) // interrupt status, read, dlab = 0
+#define SIO_FCTL (2 * SIO_STEP) // fifo control, write, dlab = 0
+#define SIO_AFR (2 * SIO_STEP) // alt function reg, read/write, dlab = 1
+#define SIO_LCTL (3 * SIO_STEP) // line control, read/write
+#define SIO_MCTL (4 * SIO_STEP) // modem control read/write
+#define SIO_LSTAT (5 * SIO_STEP) // line status read
+#define SIO_MSTAT (6 * SIO_STEP) // modem status read
+#define SIO_SPR (7 * SIO_STEP) // scratch pad register
+
+// interrupt enable register bit defines
+#define SIO_IEN_RXD 0x01 // enable int on rcv holding reg full
+#define SIO_IEN_TXD 0x02 // enable int on xmt holding reg empty
+#define SIO_IEN_LSTAT 0x04 // enable int on line status reg state change
+#define SIO_IEN_MSTAT 0x08 // enable int on modem status reg state change
+
+// interrupt status register bit defines
+#define SIO_ISTAT_PEND 0x01 // 0 = interrupt pending
+#define SIO_ISTAT_MASK 0x0e // mask for interrupt ID bits
+#define SIO_ISTAT_INT 0x0F // bits 0-3 describe current highest priority
+ // interrupt pending. They can be used to
+ // vector to the correct routine.
+ // The codes are as follows:
+#define SIO_ISTAT_MI 0x00 // Modem Status Register interrupt
+#define SIO_ISTAT_TI 0x02 // Transmit Holding Register Empty interrupt
+#define SIO_ISTAT_RI 0x04 // Receive Holding Register Ready interrupt
+#define SIO_ISTAT_LI 0x06 // Line Status Register interrupt
+#define SIO_ISTAT_FI 0x0C // Rcv Holding Register Fifo Timeout interrupt
+
+// fifo control register bit defines
+#define SIO_FCTL_FEN 0x01 // 1 = fifo operation enabled
+#define SIO_FCTL_RXDC 0x02 // 1 = clear rxd fifo and reset counter,
+ // returns to 0 automatically
+#define SIO_FCTL_TXDC 0x04 // 1 = clear txd fifo and reset counter,
+ // returns to 0 automatically
+#define SIO_FCTL_MODE 0x08 // set txrdy and rxrdy modes, unused
+
+ // Bits 6 and 7 set the desired fifo trigger
+ // level as follows:
+#define SIO_FCTL_T1 0x00 // 00 = trigger when 1 character in fifo
+#define SIO_FCTL_T4 0x40 // 01 = trigger when 4 characters in fifo
+#define SIO_FCTL_T8 0x80 // 10 = trigger when 8 characters in fifo
+#define SIO_FCTL_T14 0xC0 // 11 = trigger when 14 characters in fifo
+
+// line control register bit defines
+ // bits 0 and 1 set the word length as follows:
+#define SIO_LCTL_W5 0x00 // 00 = 5
+#define SIO_LCTL_W6 0x01 // 01 = 6
+#define SIO_LCTL_W7 0x02 // 10 = 7
+#define SIO_LCTL_W8 0x03 // 11 = 8
+
+#define SIO_LCTL_STOP 0x04 // 0 = 1 stop bit, 1 = 1.5 stop bits if
+ // word length is 5, 2 otherwise
+#define SIO_LCTL_PAR 0x08 // 0 = no parity enabled, 1 = parity enabled
+#define SIO_LCTL_EVEN 0x10 // 0 = odd parity, 1 = even parity,
+ // if parity is enabled
+#define SIO_LCTL_FRC 0x20 // 0 = force parity bit to 1,
+ // 1 = force to 0, if parity is enabled
+#define SIO_LCTL_BRK 0x40 // 1 = send continuous break
+#define SIO_LCTL_DLAB 0x80 // 1 = select baud and alt function registers
+
+// modem control register bit defines
+#define SIO_MCTL_DTR 0x01 // 0 = set DTR output = 0,
+ // 1 = set DTR = 1, unused
+#define SIO_MCTL_RTS 0x02 // 0 = set RTS output = 0,
+ // 1 = set RTS = 1, channel A only
+#define SIO_MCTL_OP2 0x08 // 0 = set OP2 output = 0,
+ // 1 = set OP2 = 1, unused
+#define SIO_MCTL_LB 0x10 // 0 = normal operation,
+ // 1 = loopback mode
+
+// line status register bit defines
+#define SIO_LSTAT_RRDY 0x01 // 1 = receive register ready
+#define SIO_LSTAT_OVER 0x02 // 1 = receive overrun error
+#define SIO_LSTAT_PERR 0x04 // 1 = receive parity error
+#define SIO_LSTAT_FRAM 0x08 // 1 = receive framing error
+#define SIO_LSTAT_BRK 0x10 // 1 = receive break
+#define SIO_LSTAT_TRDY 0x20 // 1 = transmit hold register empty
+#define SIO_LSTAT_TEMTY 0x40 // 1 = transmit register empty
+#define SIO_LSTAT_ERR 0x80 // 1 = any error condition
+
+// modem status register bit defines
+#define SIO_MSTAT_CTS 0x01 // 1 = CTS state has changed, channel A only
+#define SIO_MSTAT_DSR 0x02 // 1 = DSR state has changed, unused
+#define SIO_MSTAT_RI 0x04 // 1 = RI state has changed, unused
+#define SIO_MSTAT_CD 0x08 // 1 = CD state has changed, unused
+#define SIO_MSTAT_RTS 0x10 // reflects RTS bit during loopback, chA only
+#define SIO_MSTAT_DTR 0x20 // reflects DTR bit during loopback, unused
+#define SIO_MSTAT_OP1 0x40 // reflects OP1 bit during loopback, unused
+#define SIO_MSTAT_OP2 0x80 // reflects OP2 bit during loopback, unused
+
+extern void InitUART(int baud);
+extern int ConsoleBaudSet(int baud);
+extern int target_getchar(void);
+extern int target_gotachar(void);
+extern int target_putchar(char c);
+extern int target_console_empty(void);
+extern int getUartDivisor(int baud,unsigned char *hi, unsigned char *lo);
+
diff --git a/main/dev/vga_lookup.h b/main/dev/vga_lookup.h
new file mode 100644
index 0000000..6c280b2
--- /dev/null
+++ b/main/dev/vga_lookup.h
@@ -0,0 +1,51 @@
+//==========================================================================
+//
+// vga_lookup.h
+//
+// Author(s): Michael Kelly, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 03/06/2005
+// Description: This file contains vga color lookup
+
+// 16-bit pixels are RGB 565 - LSB of RED and BLUE are tied low at the
+// LCD Interface, while the LSB of GREEN is loaded as 0
+#define RED_SUBPIXEL(n) (n & 0x1f) << 11
+#define GREEN_SUBPIXEL(n) (n & 0x1f) << 6
+#define BLUE_SUBPIXEL(n) (n & 0x1f) << 0
+
+// define a simple VGA style 16-color pallette
+#define LU_BLACK RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+#define LU_BLUE RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+#define LU_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00)
+#define LU_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f)
+#define LU_RED RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+#define LU_VIOLET RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f)
+#define LU_YELLOW RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00)
+#define LU_GREY RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f)
+#define LU_WHITE RED_SUBPIXEL(0x17) | GREEN_SUBPIXEL(0x17) | BLUE_SUBPIXEL(0x17)
+#define LU_BRT_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f)
+#define LU_BRT_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x00)
+#define LU_BRT_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+#define LU_BRT_RED RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+#define LU_BRT_VIOLET RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f)
+#define LU_BRT_YELLOW RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+#define LU_BRT_WHITE RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+
+const static unsigned short vga_lookup[] = {
+LU_BLACK,
+LU_BLUE,
+LU_GREEN,
+LU_CYAN,
+LU_RED,
+LU_VIOLET,
+LU_YELLOW,
+LU_GREY,
+LU_WHITE,
+LU_BRT_BLUE,
+LU_BRT_GREEN,
+LU_BRT_CYAN,
+LU_BRT_RED,
+LU_BRT_VIOLET,
+LU_BRT_YELLOW,
+LU_BRT_WHITE
+};
diff --git a/main/flash/README b/main/flash/README
new file mode 100644
index 0000000..f870647
--- /dev/null
+++ b/main/flash/README
@@ -0,0 +1,16 @@
+devices:
+ Each .c file represents one configuration of one particular flash
+ device. These files can be used standalone or mixed, depending on
+ the configuration of the board. Refer to devices/README for full
+ details.
+ Not all driver files have been updated to conform with uMon1.0.
+ The easiest way to determine if the driver has been updated to
+ uMon1.0 is to look at the relocatable xxx_lock() function. If
+ it supports the FLASH_LOCKABLE operation properly, then it has
+ been updated to be uMon1.0 compatible.
+
+Note that several of these drivers may need updating.
+Especially notable is the need for the WATCHDOG_MACRO to be inserted
+in strategic points within the driver. Obviously this will only be
+needed if the hardware runs with a watchdog.
+
diff --git a/main/flash/devices/s29gl512n_16x1.c b/main/flash/devices/s29gl512n_16x1.c
new file mode 100644
index 0000000..cbe28c4
--- /dev/null
+++ b/main/flash/devices/s29gl512n_16x1.c
@@ -0,0 +1,763 @@
+/* s29gl512n_16x1.c
+ * Device interface for Spansion S29GL512N flash device configured for
+ * x16 mode with 1 device in parallel.
+ * The device contains 512 128Kbyte sectors.
+ * There are four different memory configurations that this driver
+ * handles:
+ * 1. A single S29GL512N_16x1 device
+ * 2. Piggybacked S29GL512N_16x1 devices (2 devices).
+ * 3. 70GL01GN: 2 S29GL512N_16x1 devices in one package.
+ * 4. GL01GP: This is a single device with double the density of the
+ * S29GL512N_16x1 device.
+ */
+#include "config.h"
+
+#if INCLUDE_FLASH
+
+#define WRITE_BUFFER_SIZE 32
+#define WRITE_BUFFER_ADDR_MASK (~(WRITE_BUFFER_SIZE-1))
+
+#include "stddefs.h"
+#include "genlib.h"
+#include "cpu.h"
+#include "cpuio.h"
+#include "flash.h" /* Part of monitor common code */
+#include "s29gl512n_16x1.h"
+
+#define ftype volatile unsigned short
+#define Is_ff(add) (*(ftype *)add == 0xffff)
+#define Is_not_ff(add) (*(ftype *)add != 0xffff)
+#define Is_Equal(p1,p2) (*(ftype *)p1 == *(ftype *)p2)
+#define Is_Equal_d7(p1,p2) ((*(ftype *)p1&0x80) == (*(ftype *)p2&0x80))
+#define Is_Not_Equal(p1,p2) (*(ftype *)p1 != *(ftype *)p2)
+#define Is_Not_Equal_d7(p1,p2) ((*(ftype *)p1&0x80) != (*(ftype *)p2&0x80))
+#define Fwrite(to,frm) (*(ftype *)to = *(ftype *)frm)
+#define D5_Timeout(add) ((*(ftype *)(add) & 0x0020) == 0x0020)
+
+#define SECTOR_TOTAL (512*2)
+#define SECTOR_SIZE 0x20000
+#define SPANSION_29GL512N_ID 0x00012223
+#define SPANSION_29GL1024N_ID 0x00012228
+
+#define D6 0x0040
+#define D5 0x0020
+#define D3 0x0008
+
+#define SECTOR_ERASE(add) { \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \
+ *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x0080; \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \
+ *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \
+ *(ftype *)(add) = 0x0030; }
+
+
+#define FLASH_WRITE(dest,src) { \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \
+ *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00a0; \
+ Fwrite((ftype *)(dest),src); }
+
+#define AUTO_SELECT() { \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \
+ *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x0090; }
+
+#define READ_RESET() { \
+ ftype val; \
+ *(ftype *)(fdev->base) = 0x00f0; \
+ val = *(ftype *)(fdev->base); \
+ val = val; } // eliminate "variable unused warning"
+
+#define WHILE_D6_TOGGLES(a) \
+ while ((*(ftype *)(a) & D6) != (*(ftype *)(a) & D6))
+
+
+/* S29gl512n_16x1_erase():
+ * Based on the 'snum' value, erase the appropriate sector(s).
+ * Return 0 if success, else -1.
+ */
+int
+S29gl512n_16x1_erase(struct flashinfo *fdev,int snum)
+{
+ ulong add;
+ int ret;
+
+ ret = 0;
+ add = (ulong)(fdev->sectors[snum].begin);
+
+
+ SECTOR_ERASE(add);
+
+ /* Wait for sector erase to complete or timeout..
+ * DQ7 polling: wait for D7 to be 1.
+ * DQ6 toggling: wait for D6 to not toggle.
+ * DQ5 timeout: if DQ7 is 0, and DQ5 = 1, timeout.
+ */
+ while(1) {
+ WATCHDOG_MACRO;
+ if (*(ftype *)(add) == 0xffff) {
+ if (*(ftype *)(add) == 0xffff)
+ break;
+ }
+ if (D5_Timeout(add)) {
+ if (*(ftype *)(add) != 0xffff)
+ ret = -1;
+ break;
+ }
+ }
+
+ /* If the erase failed for some reason, then issue the read/reset
+ * command sequence prior to returning...
+ */
+ if (ret == -1)
+ READ_RESET();
+
+ return(ret);
+}
+
+/* EndS29gl512n_16x1_erase():
+ * Function place holder to determine the end of the above function.
+ */
+void
+EndS29gl512n_16x1_erase(void)
+{
+}
+
+#ifdef BUFFERED_WRITE
+
+/* S29gl512n_16x1_write():
+ * Copy specified number of bytes from source to destination. The destination
+ * address is assumed to be flash space.
+ */
+int
+S29gl512n_16x1_write(struct flashinfo *fdev,
+ uchar *dest,uchar *src,long bytecnt)
+{
+ ftype val;
+ int i, ret;
+ ulong cnt;
+ uchar *src1;
+
+ ret = 0;
+ src1 = (uchar *)&val;
+
+ /* Since we are working on a 2-byte wide device, every write to the
+ * device must be aligned on a 2-byte boundary. If our incoming
+ * destination address is odd, then decrement the destination by one
+ * and build a fake source using *dest-1 and src[0]...
+ */
+ if (((ulong)dest)&1) {
+ dest--;
+
+ src1[0] = *dest;
+ src1[1] = *src;
+
+ FLASH_WRITE(dest,src1);
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ if (Is_Equal_d7(dest,src1)) {
+ if (Is_Equal_d7(dest,src1))
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(dest)) {
+ if (Is_Not_Equal_d7(dest,src1)) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+
+ dest += 2;
+ src++;
+ bytecnt--;
+ }
+
+ /* Now determine how many whole words can be written to the destination.
+ * We try to take advantage of buffer writes.
+ */
+ for(cnt=bytecnt; cnt>1; ) {
+ ulong tmpLen;
+ uchar buf[WRITE_BUFFER_SIZE];
+ tmpLen=(((ulong)dest&WRITE_BUFFER_ADDR_MASK)+WRITE_BUFFER_SIZE)-
+ (ulong)dest;
+ if (tmpLen > cnt) {
+ tmpLen=cnt;
+ }
+ if (tmpLen&1) {
+ tmpLen--;
+ }
+ /* Because the source might be the flash itself, first copy the
+ * bytes to a RAM-based buffer just to be safe.
+ */
+ for(i=0; i<tmpLen; ++i) {
+ buf[i]=src[i];
+ }
+
+ /* Buffered write...
+ */
+ {
+ long b_cnt;
+ int i, rc;
+ uchar *b_src, *saddr, *eaddr;
+
+ rc = 0;
+ b_src = buf;
+ saddr = dest;
+ b_cnt = tmpLen;
+ eaddr = saddr + b_cnt - 1;
+
+ if (!b_cnt) return 0;
+
+ if (((ulong)eaddr&WRITE_BUFFER_ADDR_MASK) !=
+ ((ulong)saddr&WRITE_BUFFER_ADDR_MASK)) {
+ /* Overall buffer straddles a boundary */
+ return -1;
+ }
+
+ if (b_cnt&1) {
+ ret = -1;
+ goto done;
+ }
+
+ *(ftype *)(fdev->base+(0x555<<1)) = 0x00aa;
+ *(ftype *)(fdev->base+(0x2aa<<1)) = 0x0055;
+ *(ftype *)(saddr) = 0x0025;
+ *(ftype *)(saddr) = (b_cnt/2)-1;
+
+ for(i=0; i<b_cnt/2; i++) {
+ Fwrite(saddr,b_src);
+ saddr+=2;
+ b_src+=2;
+ }
+ /* We'll poll the last adress that was written */
+ saddr-=2;
+ b_src-=2;
+
+ *(ftype *)(saddr) = 0x0029;
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ if (Is_Equal_d7(saddr,b_src)) {
+ if (Is_Equal_d7(saddr,b_src))
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(saddr)) {
+ if (Is_Not_Equal_d7(saddr,b_src)) {
+ if (*(ftype *)saddr & 0x2) {
+ /* Reset the operation */
+ *(ftype *)(fdev->base+(0x555<<1)) = 0x00aa;
+ *(ftype *)(fdev->base+(0x2aa<<1)) = 0x0055;
+ *(ftype *)(fdev->base+(0x555<<1)) = 0x00F0;
+ }
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+
+ if (rc) {
+ READ_RESET();
+ }
+ //return rc;
+ }
+
+ dest+=tmpLen;
+ src+=tmpLen;
+ cnt-=tmpLen;
+ }
+
+ /* We still have to deal with the possibility that there might be a trailing
+ * byte that might have to be written
+ */
+ if (cnt) {
+ /* One additional byte left */
+ src1[0] = *src;
+ src1[1] = dest[1];
+
+ FLASH_WRITE(dest,src1);
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ if (Is_Equal_d7(dest,src1)) {
+ if (Is_Equal_d7(dest,src1))
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(dest)) {
+ if (Is_Not_Equal_d7(dest,src1)) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+ }
+
+done:
+ if (ret) {
+ READ_RESET();
+ }
+ return(ret);
+}
+
+#else
+
+/* S29gl512n_16x1_write():
+ * Copy specified number of bytes from source to destination. The destination
+ * address is assumed to be flash space.
+ */
+int
+S29gl512n_16x1_write(struct flashinfo *fdev,
+ uchar *dest,uchar *src,long bytecnt)
+{
+ ftype val;
+ int cnt, ret;
+ uchar *src1;
+
+ ret = 0;
+ cnt = bytecnt & ~1;
+ src1 = (uchar *)&val;
+
+ /* Since we are working on a 2-byte wide device, every write to the
+ * device must be aligned on a 2-byte boundary. If our incoming
+ * destination address is odd, then decrement the destination by one
+ * and build a fake source using *dest-1 and src[0]...
+ */
+ if (NotAligned16(dest)) {
+ dest--;
+
+ src1[0] = *dest;
+ src1[1] = *src;
+
+ FLASH_WRITE(dest,src1);
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ WATCHDOG_MACRO;
+
+ if (*(ftype *)(dest) == *(ushort *)src1) {
+ if (*(ftype *)(dest) == *(ushort *)src1)
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(dest)) {
+ if (*(ftype *)(dest) != *(ushort *)src1) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+
+ dest += 2;
+ src++;
+ bytecnt--;
+ }
+
+ /* Each pass through this loop writes 'fdev->width' bytes...
+ */
+
+ while (bytecnt >= fdev->width) {
+
+ /* Just in case src is not aligned... */
+ src1[0] = src[0];
+ src1[1] = src[1];
+
+
+ FLASH_WRITE(dest,src1);
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ WATCHDOG_MACRO;
+
+ if (*(ftype *)(dest) == *(ushort *)src1) {
+ if (*(ftype *)(dest) == *(ushort *)src1)
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(dest)) {
+ if (*(ftype *)(dest) != *(ushort *)src1) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+ dest += fdev->width;
+ src += fdev->width;
+ bytecnt -= 2;
+ }
+
+ /* Similar to the front end of this function, if the byte count is not
+ * even, then we have one byte left to write, so we need to write a
+ * 16-bit value by writing the last byte, plus whatever is already in
+ * the next flash location.
+ */
+ if (bytecnt) {
+ src1[0] = *src;
+ src1[1] = dest[1];
+
+
+ FLASH_WRITE(dest,src1);
+
+ /* Wait for write to complete or timeout. */
+ while(1) {
+ WATCHDOG_MACRO;
+ if (*(ftype *)(dest) == *(ushort *)src1) {
+ if (*(ftype *)(dest) == *(ushort *)src1)
+ break;
+ }
+ /* Check D5 for timeout... */
+ if (D5_Timeout(dest)) {
+ if (*(ftype *)(dest) != *(ushort *)src1) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ }
+ }
+ }
+
+done:
+ READ_RESET();
+
+ return(ret);
+}
+#endif
+
+/* EndS29gl512n_16x1_write():
+ * Function place holder to determine the end of the above function.
+ */
+void
+EndS29gl512n_16x1_write(void)
+{}
+
+/* S29gl512n_16x1_ewrite():
+ * Erase all sectors that are part of the address space to be written,
+ * then write the data to that address space.
+ * This function is optimized for speed by using the write buffer and
+ * erase delay timer. It assumes the incoming destination address is
+ * aligned on a 32-byte boundary and that the bytecount will be even.
+ */
+int
+S29gl512n_16x1_ewrite(struct flashinfo *fdev,
+ uchar *dest,uchar *src,long bytecnt)
+{
+ int i;
+ ulong add;
+
+ add = (ulong)(fdev->base);
+
+ /* For each sector, if it overlaps any of the destination space
+ * then erase that sector.
+ */
+ for (i=0;i<fdev->sectorcnt;i++) {
+ long size;
+ long *begin, *end;
+ struct sectorinfo *sip;
+
+ sip = &(fdev->sectors[i]);
+ begin = (long *)(sip->begin);
+ end = (long *)(sip->end);
+ size = sip->size;
+
+ /* If this sector is not overlapping the destination, then
+ * don't erase it...
+ */
+ if ((((uchar *)dest) > (uchar *)end) ||
+ (((uchar *)dest+bytecnt-1) < (uchar *)begin)) {
+ add += size;
+ continue;
+ }
+
+ /* If this sector is already erased, then don't erase it...
+ */
+ while(begin < end) {
+ if (*begin != 0xffffffff)
+ break;
+ begin++;
+ }
+ if (begin >= end) {
+ add += size;
+ continue;
+ }
+ SECTOR_ERASE(add);
+
+ WHILE_D6_TOGGLES(add);
+
+ add += size;
+ }
+
+ READ_RESET();
+
+ while(bytecnt > 0) {
+ int tot, tot1;
+ uchar *sa;
+
+ sa = dest;
+ *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa;
+ *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055;
+
+ *(ftype *)(sa) = 0x0025;
+ if (bytecnt >= 32)
+ tot = tot1 = 32;
+ else
+ tot = tot1 = bytecnt;
+ *(ftype *)(dest) = (tot/2 - 1);
+ while(tot > 0) {
+ Fwrite((ftype *)(dest),src);
+ dest+=2;
+ src+=2;
+ tot -= 2;
+ }
+ *(ftype *)(sa) = 0x0029;
+
+ WHILE_D6_TOGGLES(sa);
+
+ bytecnt -= tot1;
+ }
+
+ READ_RESET();
+
+ /* Now that the re-programming of flash is complete, reset: */
+ {
+#ifdef RESETMACRO
+ RESETMACRO();
+#else
+ void (*reset)();
+ reset = RESETFUNC();
+ reset();
+#endif
+ }
+
+ return(0); /* won't get here */
+}
+
+/* EndS29gl512n_16x1_ewrite():
+ * Function place holder to determine the end of the above function.
+ */
+void
+EndS29gl512n_16x1_ewrite(void)
+{}
+
+
+/* S29gl512n_16x1_type():
+ * Run the AUTOSELECT algorithm to retrieve the manufacturer and
+ * device id of the flash.
+ */
+int
+S29gl512n_16x1_type(struct flashinfo *fdev)
+{
+ ushort man, dev;
+ ulong id;
+
+
+ AUTO_SELECT();
+
+ man = *(ftype *)(fdev->base); /* manufacturer ID */
+ dev = *(ftype *)((fdev->base + 28)); /* device ID */
+ id = man;
+ id <<= 16;
+ id |= dev;
+
+ fdev->id = id;
+
+ READ_RESET();
+
+ return((int)(fdev->id));
+}
+
+/* EndS29gl512n_16x1_type():
+ * Function place holder to determine the end of the above function.
+ */
+void
+EndS29gl512n_16x1_type(void)
+{}
+
+/**************************************************************************
+ **************************************************************************
+ *
+ * The remainder of the code in this file should only included if the
+ * target configuration is such that this AM29F040 device is the only
+ * real flash device in the system that is to be visible to the monitor.
+ *
+ **************************************************************************
+ **************************************************************************
+ */
+#ifdef SINGLE_FLASH_DEVICE
+
+/* FlashXXXFbuf[]:
+ * If FLASH_COPY_TO_RAM is defined then these arrays will contain the
+ * flash operation functions above. To operate on most flash devices,
+ * you cannot be executing out of it (there are exceptions, but
+ * in general, we do not assume the flash supports this). The flash
+ * functions are copied here, then executed through the function
+ * pointers established in the flashinfo structure below.
+ * One obvious requirement... The size of each array must be at least
+ * as large as the function that it will contain.
+ */
+#ifdef FLASH_COPY_TO_RAM
+ulong FlashTypeFbuf[400];
+ulong FlashEraseFbuf[400];
+#ifdef BUFFERED_WRITE
+ulong FlashWriteFbuf[600];
+#else
+ulong FlashWriteFbuf[400];
+#endif
+ulong FlashEwriteFbuf[400];
+#endif
+
+/* FlashNamId[]:
+ * Used to correlate between the ID and a string representing the name
+ * of the flash device.
+ */
+struct flashdesc FlashNamId[] = {
+ { SPANSION_29GL512N_ID, "Spansion-29GL512N" },
+ { SPANSION_29GL1024N_ID, "Spansion-29GL1024N" },
+ { 0, (char *)0 },
+};
+
+
+struct sectorinfo sinfo_bank0[SECTOR_TOTAL];
+struct sectorinfo sinfo_bank1[SECTOR_TOTAL];
+
+int
+flashBankInit(int banknum, int snum, struct sectorinfo *sinfotbl)
+{
+ int i;
+ uchar *begin;
+ struct flashinfo *fbnk;
+
+ fbnk = &FlashBank[banknum];
+ if (banknum == 0)
+ fbnk->base = (unsigned char *)FLASH_BANK0_BASE_ADDR;
+ else
+ fbnk->base = (unsigned char *)FLASH_BANK0_BASE_ADDR+0x04000000;
+
+ fbnk->width = 2;
+
+#ifdef FLASH_COPY_TO_RAM
+ fbnk->fltype = (int(*)())FlashTypeFbuf;
+ fbnk->flerase = (int(*)())FlashEraseFbuf;
+ fbnk->flwrite = (int(*)())FlashWriteFbuf;
+ fbnk->flewrite = (int(*)())FlashEwriteFbuf;
+#else
+ fbnk->fltype = S29gl512n_16x1_type;
+ fbnk->flerase = S29gl512n_16x1_erase;
+ fbnk->flwrite = S29gl512n_16x1_write;
+ fbnk->flewrite = S29gl512n_16x1_ewrite;
+#endif
+
+ /* This device doesn't support flash lock, so set the pointer
+ * to the default FlashLockNotSupported() function...
+ */
+ fbnk->fllock = FlashLockNotSupported;
+
+ fbnk->sectors = sinfotbl;
+ fbnk->id = flashtype(fbnk);
+ switch(fbnk->id) {
+ case SPANSION_29GL512N_ID:
+ fbnk->end = fbnk->base + 0x04000000 - 1;
+ fbnk->sectorcnt = SECTOR_TOTAL/2;
+ break;
+ case SPANSION_29GL1024N_ID:
+ fbnk->end = fbnk->base + 0x08000000 - 1;
+ fbnk->sectorcnt = SECTOR_TOTAL;
+ break;
+ default:
+ /* The second bank may legitimately not be populated, so if it
+ * isn't found, indicate unavailable, don't claim an error...
+ */
+ printf("Flash bank %d: ",banknum);
+ if (banknum == 0)
+ printf("invalid id: 0x%lx.\n",fbnk->id);
+ else
+ printf("not available.\n");
+ return(-1);
+ }
+
+ begin = fbnk->base;
+ for(i=0;i<fbnk->sectorcnt;i++,snum++) {
+ fbnk->sectors[i].snum = snum;
+ fbnk->sectors[i].size = SECTOR_SIZE;
+ fbnk->sectors[i].begin = begin;
+ fbnk->sectors[i].end = fbnk->sectors[i].begin + SECTOR_SIZE - 1;
+ fbnk->sectors[i].protected = 0;
+ begin += SECTOR_SIZE;
+ }
+ return(snum);
+}
+
+/* FlashInit():
+ * Initialize data structures for each bank of flash...
+ */
+int
+FlashInit()
+{
+ int snum;
+
+ FlashCurrentBank = 0;
+
+ /* If code is in flash, then we must copy the flash ops to RAM.
+ * Note that this MUST be done when cache is disabled to assure
+ * that the RAM is occupied by the designated block of code.
+ */
+
+#ifdef FLASH_COPY_TO_RAM
+ if (flashopload((ulong *)S29gl512n_16x1_type,
+ (ulong *)EndS29gl512n_16x1_type,
+ FlashTypeFbuf,sizeof(FlashTypeFbuf)) < 0)
+ return(-1);
+
+ if (flashopload((ulong *)S29gl512n_16x1_erase,
+ (ulong *)EndS29gl512n_16x1_erase,
+ FlashEraseFbuf,sizeof(FlashEraseFbuf)) < 0)
+ return(-1);
+
+ if (flashopload((ulong *)S29gl512n_16x1_ewrite,
+ (ulong *)EndS29gl512n_16x1_ewrite,
+ FlashEwriteFbuf,sizeof(FlashEwriteFbuf)) < 0)
+ return(-1);
+
+ if (flashopload((ulong *)S29gl512n_16x1_write,
+ (ulong *)EndS29gl512n_16x1_write,
+ FlashWriteFbuf,sizeof(FlashWriteFbuf)) < 0)
+ return(-1);
+#endif
+
+#ifdef IS_MONOLITHIC_FLASH
+ ActiveFlashBanks = 1;
+ snum = flashBankInit(0,0,sinfo_bank0);
+
+ if (!IS_MONOLITHIC_FLASH()) {
+ if (flashBankInit(1,snum,sinfo_bank1) != -1)
+ ActiveFlashBanks++;
+ }
+#else
+ snum = flashBankInit(0,0,sinfo_bank0);
+#endif
+
+ if (snum < 0)
+ return(-1);
+
+#ifdef FLASH_PROTECT_RANGE
+ sectorProtect(FLASH_PROTECT_RANGE,1);
+#endif
+
+#if FLASHRAM_BASE
+ FlashRamInit(snum, FLASHRAM_SECTORCOUNT, &FlashBank[FLASHRAM_BANKNUM],
+ sinfoRAM, 0);
+#endif
+
+ return(0);
+}
+
+#endif /* SINGLE_FLASH_DEVICE */
+
+#endif /* INCLUDE_FLASH */
diff --git a/main/flash/devices/s29gl512n_16x1.h b/main/flash/devices/s29gl512n_16x1.h
new file mode 100644
index 0000000..f2b0a36
--- /dev/null
+++ b/main/flash/devices/s29gl512n_16x1.h
@@ -0,0 +1,12 @@
+extern int S29gl512n_16x1_erase(struct flashinfo *,int);
+extern void End_s29gl512n_16x1_erase(void);
+
+extern int S29gl512n_16x1_write(struct flashinfo *,unsigned char *,unsigned char *,long);
+extern void End_s29gl512n_16x1_write(void);
+
+extern int S29gl512n_16x1_ewrite(struct flashinfo *,unsigned char *,unsigned char *,long);
+extern void End_s29gl512n_16x1_ewrite(void);
+
+extern int S29gl512n_16x1_type(struct flashinfo *);
+extern void End_s29gl512n_16x1_type(void);
+
diff --git a/main/glib/abs.c b/main/glib/abs.c
new file mode 100644
index 0000000..8758947
--- /dev/null
+++ b/main/glib/abs.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)abs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+int
+abs(j)
+ int j;
+{
+ return(j < 0 ? -j : j);
+}
diff --git a/main/glib/asctime.c b/main/glib/asctime.c
new file mode 100644
index 0000000..7a042c3
--- /dev/null
+++ b/main/glib/asctime.c
@@ -0,0 +1,19 @@
+#include <time.h>
+#include "genlib.h"
+
+static const char *days[] =
+ {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+static const char *months[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+char *asctime_r(const struct tm *t, char *ret)
+{
+ sprintf(ret, "%s %s %2d, %4d %2d:%02d:%02d",
+ days[t->tm_wday], months[t->tm_mon],
+ t->tm_mday, t->tm_year + 1970,
+ t->tm_hour, t->tm_min, t->tm_sec);
+ return ret;
+}
+
diff --git a/main/glib/atoi.c b/main/glib/atoi.c
new file mode 100644
index 0000000..de76b27
--- /dev/null
+++ b/main/glib/atoi.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+int
+atoi(str)
+const char *str;
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
diff --git a/main/glib/crc16.c b/main/glib/crc16.c
new file mode 100644
index 0000000..19409fd
--- /dev/null
+++ b/main/glib/crc16.c
@@ -0,0 +1,59 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* CRC-CCITT crc16 used primarily by Xmodem...
+ */
+ushort xcrc16tab[] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+ushort
+xcrc16(uchar *buffer,ulong nbytes)
+{
+ ulong i;
+ ushort crc;
+
+ crc = 0;
+ for(i=0;i<nbytes;i++) {
+ crc = (ushort)((crc << 8) ^ xcrc16tab[(crc>>8) ^ buffer[i]]);
+#ifdef WATCHDOG_ENABLED
+ /* Every 256 bytes call the watchdog macro... */
+ if ((nbytes & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ }
+ return(crc);
+}
diff --git a/main/glib/crc32.c b/main/glib/crc32.c
new file mode 100644
index 0000000..5a5568c
--- /dev/null
+++ b/main/glib/crc32.c
@@ -0,0 +1,155 @@
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/*
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ *
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+const unsigned long crc32tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/* If the watchdog macro is enabled, then we break up the crc algorithm
+ * into CRC_CHUNK_SIZE blocks so that after each block we can run the
+ * watchdog macro...
+ */
+
+ulong
+crc32chunk(uchar *buffer,ulong nbytes, ulong crc_rslt)
+{
+ unsigned long temp;
+
+ while(nbytes) {
+ temp = (crc_rslt ^ *buffer++) & 0x000000FFL;
+ crc_rslt = ((crc_rslt >> 8) & 0x00FFFFFFL) ^ crc32tab[(int)temp];
+ nbytes--;
+ }
+ return(crc_rslt);
+}
+
+#ifdef WATCHDOG_ENABLED
+
+#define CRC_CHUNK_SIZE 0x4000
+
+ulong
+crc32(uchar *buffer, ulong nbytes)
+{
+ int size;
+ ulong crcval = 0xffffffff;
+
+ while(nbytes > 0) {
+ if (nbytes > CRC_CHUNK_SIZE)
+ size = CRC_CHUNK_SIZE;
+ else
+ size = nbytes;
+ nbytes -= size;
+
+ crcval = crc32chunk(buffer,size,crcval);
+ buffer += size;
+
+ WATCHDOG_MACRO;
+ }
+ return(~crcval);
+}
+
+#else
+
+ulong
+crc32(uchar *buffer,ulong nbytes)
+{
+ unsigned long temp, crc_rslt;
+
+ crc_rslt = 0xffffffff;
+ while(nbytes) {
+ temp = (crc_rslt ^ *buffer++) & 0x000000FFL;
+ crc_rslt = ((crc_rslt >> 8) & 0x00FFFFFFL) ^ crc32tab[(int)temp];
+ nbytes--;
+ }
+ return(~crc_rslt);
+}
+
+#endif
diff --git a/main/glib/div.c b/main/glib/div.c
new file mode 100644
index 0000000..7dfe553
--- /dev/null
+++ b/main/glib/div.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* div_t */
+
+div_t
+div(num, denom)
+ int num, denom;
+{
+ div_t r;
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ /*
+ * The ANSI standard says that |r.quot| <= |n/d|, where
+ * n/d is to be computed in infinite precision. In other
+ * words, we should always truncate the quotient towards
+ * 0, never -infinity.
+ *
+ * Machine division and remainer may work either way when
+ * one or both of n or d is negative. If only one is
+ * negative and r.quot has been truncated towards -inf,
+ * r.rem will have the same sign as denom and the opposite
+ * sign of num; if both are negative and r.quot has been
+ * truncated towards -inf, r.rem will be positive (will
+ * have the opposite sign of num). These are considered
+ * `wrong'.
+ *
+ * If both are num and denom are positive, r will always
+ * be positive.
+ *
+ * This all boils down to:
+ * if num >= 0, but r.rem < 0, we got the wrong answer.
+ * In that case, to get the right answer, add 1 to r.quot and
+ * subtract denom from r.rem.
+ */
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+ return (r);
+}
diff --git a/main/glib/getglib b/main/glib/getglib
new file mode 100755
index 0000000..4c963b2
--- /dev/null
+++ b/main/glib/getglib
@@ -0,0 +1,49 @@
+#
+# This is the original script I used to pull in files from the FreeBsd project:
+#
+export GLIBFILES="abs.c atoi.c crc16.c crc32.c ctypetbl.c div.c getopt.c gmtime.c inrange.c lceil.c ldiv.c little_print.c memccpy.c memchr.c memcmp.c memcpy.c memset.c pollconsole.c prascii.c printmem.c smemcpy.c smemset.c sprnfloat.c strcasecmp.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c strnlen.c strpbrk.c strrchr.c strspn.c strstr.c strtod.c strtok.c strtol.c strtoul.c strtolower.c strtoupper.c swap.c ticktock.c ulceil.c"
+
+export MYFILES="asctime.c inrange.c memcpy.c pollconsole.c prascii.c printmem.c smemcpy.c smemset.c swap.c ticktock.c"
+
+export BSDPATH=https://raw.githubusercontent.com/freebsd/freebsd/master
+
+export BSD_STRING_FILES="memccpy.c memchr.c memcmp.c memset.c strcasecmp.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c strnlen.c strpbrk.c strrchr.c strspn.c strstr.c strtok.c"
+
+export BSD_STDLIB_FILES="abs.c atoi.c div.c getopt.c ldiv.c strtol.c"
+
+rm -f *.c *.1 list
+
+for file in $MYFILES
+do
+ cp orig/$file .
+ echo "myfile: $file" >>list
+done
+
+for file in $BSD_STDLIB_FILES
+do
+ if ! [ -f $file ]
+ then
+ wget ${BSDPATH}/lib/libc/stdlib/$file
+ if [ $? == 0 ]
+ then
+ echo "stdlib: $file" >>list
+ fi
+ fi
+done
+
+for file in $BSD_STRING_FILES
+do
+ if ! [ -f $file ]
+ then
+ wget ${BSDPATH}/lib/libc/string/$file
+ if [ $? == 0 ]
+ then
+ echo "string: $file" >>list
+ fi
+ fi
+done
+
+wget ${BSDPATH}/contrib/tzcode/stdtime/asctime.c
+wget https://raw.githubusercontent.com/LADSoft/OrangeC/master/src/clibs/time/gmtime.c
+wget https://raw.githubusercontent.com/freebsd/freebsd-ports/master/converters/ta2as/files/strtolower.c
+wget https://raw.githubusercontent.com/freebsd/freebsd/master/sys/libkern/crc32.c
diff --git a/main/glib/getopt.c b/main/glib/getopt.c
new file mode 100644
index 0000000..cf43256
--- /dev/null
+++ b/main/glib/getopt.c
@@ -0,0 +1,139 @@
+/* $NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $ */
+#include <string.h>
+extern int printf(char *fmt,...);
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(int nargc, char * const nargv[], const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == 0)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == 0) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)printf(
+ "illegal option -- %c\n", optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = 0;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (oli[2] == ':')
+ /*
+ * GNU Extension, for optional arguments if the rest of
+ * the argument is empty, we return NULL
+ */
+ optarg = 0;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)printf(
+ "option requires an argument -- %c\n",
+ optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
+
+/* getoptinit():
+ * Since getopt() can be used by every command in the monitor
+ * it's variables must be reinitialized prior to each command
+ * executed through docommand()...
+ */
+void
+getoptinit(void)
+{
+ optind = 1;
+ opterr = 1;
+ optopt = 0;
+ optreset = 0;
+ optarg = (char *)0;
+}
diff --git a/main/glib/inrange.c b/main/glib/inrange.c
new file mode 100755
index 0000000..d687a8e
--- /dev/null
+++ b/main/glib/inrange.c
@@ -0,0 +1,71 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* inRange():
+ * This function is handed a range string and a value.
+ * If the value is within the range of the string specified, then
+ * return 1; else return 0.
+ * The incoming string can be a mix of ranges and values with each
+ * range and/or value separated by a comma and a range is specified
+ * by 2 numbers separated by a dash.
+ * Also, incoming ranges of "all" or "any" immediately return true
+ * and an incoming range of "none" or a null or empty pointer will
+ * return false.
+ */
+int
+inRange(char *range, int value)
+{
+ int lo, hi;
+ char rcopy[32], *rsp, *comma, *dash;
+
+ /* If incoming range is NULL, return zero.
+ */
+ if ((range == 0) || (*range == 0) || (strcmp(range,"none") == 0))
+ return(0);
+
+ /* If the range string is "all" or "any", then immediately return true...
+ */
+ if ((strcmp(range,"all") == 0) || (strcmp(range,"any") == 0))
+ return(1);
+
+ /* Scan the range string for valid characters:
+ */
+ rsp = range;
+ while(*rsp) {
+ if ((*rsp == ',') || (*rsp == '-') ||
+ (*rsp == 'x') || isxdigit(*rsp))
+ rsp++;
+ else
+ break;
+ }
+ if (*rsp)
+ return(0);
+
+ /* If incoming range string exceeds size of copy buffer, return 0.
+ */
+ if (strlen(range) > sizeof(rcopy)-1)
+ return(0);
+
+ strcpy(rcopy,range);
+ rsp = rcopy;
+ do {
+ comma = strchr(rsp,',');
+ if (comma)
+ *comma = 0;
+ dash = strchr(rsp,'-');
+ if (dash) {
+ lo = strtol(rsp,0,0);
+ hi = strtol(dash+1,0,0);
+ if ((value >= lo) && (value <= hi))
+ return(1);
+ }
+ else {
+ if (value == strtol(rsp,0,0))
+ return(1);
+ }
+ rsp = comma+1;
+ } while (comma);
+ return(0);
+}
diff --git a/main/glib/ldiv.c b/main/glib/ldiv.c
new file mode 100644
index 0000000..0ec98e6
--- /dev/null
+++ b/main/glib/ldiv.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* ldiv_t */
+
+ldiv_t
+ldiv(num, denom)
+ long num, denom;
+{
+ ldiv_t r;
+
+ /* see div.c for comments */
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+ return (r);
+}
diff --git a/main/glib/list b/main/glib/list
new file mode 100644
index 0000000..99ad5c5
--- /dev/null
+++ b/main/glib/list
@@ -0,0 +1,34 @@
+myfile: inrange.c
+myfile: pollconsole.c
+myfile: prascii.c
+myfile: printmem.c
+myfile: smemcpy.c
+myfile: smemset.c
+myfile: ticktock.c
+stdlib: abs.c
+stdlib: atoi.c
+stdlib: div.c
+stdlib: getopt.c
+stdlib: ldiv.c
+stdlib: strtol.c
+string: memccpy.c
+string: memchr.c
+string: memcmp.c
+string: memcpy.c
+string: memset.c
+string: strcasecmp.c
+string: strcat.c
+string: strchr.c
+string: strcmp.c
+string: strcpy.c
+string: strcspn.c
+string: strlen.c
+string: strncat.c
+string: strncmp.c
+string: strncpy.c
+string: strnlen.c
+string: strpbrk.c
+string: strrchr.c
+string: strspn.c
+string: strstr.c
+string: strtok.c
diff --git a/main/glib/memccpy.c b/main/glib/memccpy.c
new file mode 100644
index 0000000..a13bbf1
--- /dev/null
+++ b/main/glib/memccpy.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+void *
+memccpy(void *t, const void *f, int c, size_t n)
+{
+
+ if (n) {
+ unsigned char *tp = t;
+ const unsigned char *fp = f;
+ unsigned char uc = c;
+ do {
+ if ((*tp++ = *fp++) == uc)
+ return (tp);
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/main/glib/memchr.c b/main/glib/memchr.c
new file mode 100644
index 0000000..14b66c8
--- /dev/null
+++ b/main/glib/memchr.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+void *
+memchr(const void *s, int c, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *p = s;
+
+ do {
+ if (*p++ == (unsigned char)c)
+ return ((void *)(p - 1));
+ } while (--n != 0);
+ }
+ return (NULL);
+}
diff --git a/main/glib/memcmp.c b/main/glib/memcmp.c
new file mode 100644
index 0000000..baef47e
--- /dev/null
+++ b/main/glib/memcmp.c
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Compare memory regions.
+ */
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ do {
+ if (*p1++ != *p2++)
+ return (*--p1 - *--p2);
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/main/glib/memcpy.c b/main/glib/memcpy.c
new file mode 100644
index 0000000..3cfbfa3
--- /dev/null
+++ b/main/glib/memcpy.c
@@ -0,0 +1,108 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+#ifndef MEMCPY_CHUNK
+#define MEMCPY_CHUNK (256*1024)
+#endif
+
+/* memcpy():
+ * Copy n bytes from 'from' to 'to'; return 'to'.
+ * This version of memcpy() tries to take advantage of address alignment.
+ * The goal is to do as many of the copies on 4-byte aligned addresses,
+ * falling back to 2-byte alignment, and finally, if there is no other
+ * way, simple byte-by-byte copy.
+ * Note that there is some point where the amount of overhead may exceed
+ * the byte count; hence, this will take longer for small byte counts.
+ * The assumption here is that small byte count memcpy() calls don't really
+ * care.
+ */
+char *
+memcpy(char *to,char *from,int count)
+{
+ char *to_copy, *end;
+#if INCLUDE_QUICKMEMCPY
+ char *tend;
+#endif
+
+ to_copy = to;
+
+#if INCLUDE_QUICKMEMCPY
+ /* If count is greater than 8, get fancy, else just do byte-copy... */
+ if (count > 8) {
+ /* Attempt to optimize the transfer here... */
+ if (((int)to & 3) && ((int)from & 3)) {
+ /* If from and to pointers are both unaligned to the
+ * same degree then we can do a few char copies to get them
+ * 4-byte aligned and then do a lot of 4-byte aligned copies.
+ */
+ if (((int)to & 3) == ((int)from & 3)) {
+ while((int)to & 3) {
+ *to++ = *from++;
+ count--;
+ }
+ }
+ /* If from and to pointers are both odd, but different, then
+ * we can increment them both by 1 and do a bunch of 2-byte
+ * aligned copies...
+ */
+ else if (((int)to & 1) && ((int)from & 1)) {
+ *to++ = *from++;
+ count--;
+ }
+ }
+
+ /* If both pointers are now 4-byte aligned or 2-byte aligned,
+ * take advantage of that here...
+ */
+ if (!((int)to & 3) && !((int)from & 3)) {
+ tend = end = to + (count & ~3);
+ count = count & 3;
+#ifdef WATCHDOG_ENABLED
+ do {
+ tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK;
+#endif
+ while(to < tend) {
+ *(ulong *)to = *(ulong *)from;
+ from += 4;
+ to += 4;
+ }
+#ifdef WATCHDOG_ENABLED
+ WATCHDOG_MACRO;
+ } while (tend != end);
+#endif
+ }
+ else if (!((int)to & 1) && !((int)from & 1)) {
+ tend = end = to + (count & ~1);
+ count = count & 1;
+#ifdef WATCHDOG_ENABLED
+ do {
+ tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK;
+#endif
+ while(to < tend) {
+ *(ushort *)to = *(ushort *)from;
+ from += 2;
+ to += 2;
+ }
+#ifdef WATCHDOG_ENABLED
+ WATCHDOG_MACRO;
+ } while (tend != end);
+#endif
+ }
+ }
+#endif
+
+ if (count) {
+ end = to + count;
+ while(to < end)
+ *to++ = *from++;
+ }
+ return(to_copy);
+}
+
+void
+bcopy(char *from, char *to, int size)
+{
+ memcpy(to,from,size);
+}
diff --git a/main/glib/memset.c b/main/glib/memset.c
new file mode 100644
index 0000000..ad0d513
--- /dev/null
+++ b/main/glib/memset.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Hibler and Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <limits.h>
+
+#define wsize sizeof(u_int)
+#define wmask (wsize - 1)
+
+#ifdef BZERO
+#include <strings.h>
+
+#define RETURN return
+#define VAL 0
+#define WIDEVAL 0
+
+void
+bzero(void *dst0, size_t length)
+#else
+#include <string.h>
+
+#define RETURN return (dst0)
+#define VAL c0
+#define WIDEVAL c
+
+void *
+memset(void *dst0, int c0, size_t length)
+#endif
+{
+ size_t t;
+#ifndef BZERO
+ u_int c;
+#endif
+ u_char *dst;
+
+ dst = dst0;
+ /*
+ * If not enough words, just fill bytes. A length >= 2 words
+ * guarantees that at least one of them is `complete' after
+ * any necessary alignment. For instance:
+ *
+ * |-----------|-----------|-----------|
+ * |00|01|02|03|04|05|06|07|08|09|0A|00|
+ * ^---------------------^
+ * dst dst+length-1
+ *
+ * but we use a minimum of 3 here since the overhead of the code
+ * to do word writes is substantial.
+ */
+ if (length < 3 * wsize) {
+ while (length != 0) {
+ *dst++ = VAL;
+ --length;
+ }
+ RETURN;
+ }
+
+#ifndef BZERO
+ if ((c = (u_char)c0) != 0) { /* Fill the word. */
+ c = (c << 8) | c; /* u_int is 16 bits. */
+#if UINT_MAX > 0xffff
+ c = (c << 16) | c; /* u_int is 32 bits. */
+#endif
+#if UINT_MAX > 0xffffffff
+ c = (c << 32) | c; /* u_int is 64 bits. */
+#endif
+ }
+#endif
+ /* Align destination by filling in bytes. */
+ if ((t = (long)dst & wmask) != 0) {
+ t = wsize - t;
+ length -= t;
+ do {
+ *dst++ = VAL;
+ } while (--t != 0);
+ }
+
+ /* Fill words. Length was >= 2*words so we know t >= 1 here. */
+ t = length / wsize;
+ do {
+ *(u_int *)dst = WIDEVAL;
+ dst += wsize;
+ } while (--t != 0);
+
+ /* Mop up trailing bytes, if any. */
+ t = length & wmask;
+ if (t != 0)
+ do {
+ *dst++ = VAL;
+ } while (--t != 0);
+ RETURN;
+}
diff --git a/main/glib/pollconsole.c b/main/glib/pollconsole.c
new file mode 100755
index 0000000..62d05b2
--- /dev/null
+++ b/main/glib/pollconsole.c
@@ -0,0 +1,44 @@
+#include "config.h"
+#include <ctype.h>
+#include "ether.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "timer.h"
+
+/* pollConsole():
+ * Common function used to query the console port with a message.
+ * If after about a 2-second period (or the time specified by POLLTIMEOUT),
+ * there is no response from the console, then return 0; else return
+ * the character that was received.
+ */
+int
+pollConsole(char *msg)
+{
+ char *env;
+ int pollval, msec;
+ struct elapsed_tmr tmr;
+
+ env = getenv("POLLTIMEOUT");
+ if (env)
+ msec = strtol(env,0,0);
+ else
+ msec = 2000;
+
+ pollval = 0;
+ printf("%s",msg);
+ startElapsedTimer(&tmr,msec);
+ while(!msecElapsed(&tmr)) {
+ if (gotachar()) {
+ while(gotachar())
+ pollval = getchar();
+ break;
+ }
+ pollethernet();
+ }
+ putstr("\r\n");
+
+ if (ELAPSED_TIMEOUT(&tmr))
+ return(0);
+
+ return(pollval);
+}
diff --git a/main/glib/prascii.c b/main/glib/prascii.c
new file mode 100755
index 0000000..67a61d5
--- /dev/null
+++ b/main/glib/prascii.c
@@ -0,0 +1,22 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* prascii():
+ * Print the incoming data stream as ascii if printable, else just
+ * print a dot.
+ */
+void
+prascii(uchar *data,int cnt)
+{
+ int i;
+
+ for(i=0;i<cnt;i++) {
+ if ((*data > 0x1f) && (*data < 0x7f))
+ printf("%c",*data);
+ else
+ putchar('.');
+ data++;
+ }
+}
diff --git a/main/glib/printmem.c b/main/glib/printmem.c
new file mode 100755
index 0000000..5dfbea1
--- /dev/null
+++ b/main/glib/printmem.c
@@ -0,0 +1,40 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* printMem():
+ * Dump a block of memory.
+ */
+void
+printMem(uchar *base, int size, int showascii)
+{
+ int i, col;
+ uchar *cp, *cp1;
+
+ cp = cp1 = base;
+ printf(" ");
+ for(col=1,i=0;i<size;i++,col++) {
+ printf("%02x ",*cp++);
+ if ((col == 8) || (col == 16)) {
+ printf(" ");
+ if (col == 16) {
+ col = 0;
+ if (showascii)
+ prascii(cp1,16);
+ cp1 += 16;
+ printf("\n ");
+ }
+ }
+ }
+ if ((showascii) && (col > 1)) {
+ int space;
+
+ space = (3 * (17 - col)) + (col <= 8 ? 4 : 2);
+ while(space--)
+ putchar(' ');
+ prascii(cp1,col-1);
+ }
+ printf("\n");
+ return;
+}
diff --git a/main/glib/smemcpy.c b/main/glib/smemcpy.c
new file mode 100755
index 0000000..5b17470
--- /dev/null
+++ b/main/glib/smemcpy.c
@@ -0,0 +1,150 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* s_memcpy():
+ * Superset of memcpy(). Note, this used to be tfsmemcpy() in tfs.c;
+ * however, since it has no real TFS dependencies, and code outside of
+ * TFS uses it, it has been moved here and the name is changed.
+ *
+ * Includes verbose option plus verification after copy.
+ * Takes advantage of address alignment when possible.
+ *
+ * Note:
+ * If verbose is greater than one, then this function doesn't
+ * do any memory transfer, it simply displays the memory range
+ * that is to be transferred. This is used by TFS to dump a map without
+ * actually touching memory.
+ *
+ * Return:
+ * 0 if successful, else -1 indicating some part of the copy failed.
+ */
+int
+s_memcpy(char *_to,char *_from,int count, int verbose,int verifyonly)
+{
+ int err;
+ volatile register char *to, *from, *end;
+
+ to = _to;
+ from = _from;
+
+ if (verbose)
+ printf("%s %7d bytes from 0x%08lx to 0x%08lx",
+ verifyonly ? "vrfy" : "copy", count,(ulong)from,(ulong)to);
+
+ if (_to == _from) {
+ if (verbose)
+ printf("\n");
+ return(0);
+ }
+
+ if (count < 0)
+ return(-1);
+
+ if (verifyonly) {
+ while(count) {
+ if (*to != *from)
+ break;
+ to++;
+ from++;
+ count--;
+#ifdef WATCHDOG_ENABLED
+ if ((count & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ }
+ if (count) {
+ if (verbose) {
+ printf(" FAILED\n");
+ printf(" (0x%02x @ 0x%08lx should be 0x%02x)\n",
+ *to,(ulong)to,*from);
+ }
+ return(-1);
+ }
+ else
+ if (verbose)
+ printf(" OK\n");
+ return(0);
+ }
+
+ /* If verbose is greater than 1, then we don't even do a memcpy,
+ * we just let the user know what we would have done...
+ */
+ if ((count == 0) || (verbose > 1))
+ goto done;
+
+ if (to != from) {
+
+ err = 0;
+ if (!((int)to & 3) && !((int)from & 3) && !(count & 3)) {
+ volatile register ulong *lto, *lfrom, *lend;
+
+ count >>= 2;
+ lto = (ulong *)to;
+ lfrom = (ulong *)from;
+ lend = lto + count;
+ while(lto < lend) {
+ *lto = *lfrom;
+ if (*lto != *lfrom) {
+ err = 1;
+ break;
+ }
+ lto++;
+ lfrom++;
+#ifdef WATCHDOG_ENABLED
+ if (((int)lto & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ }
+ }
+ else if (!((int)to & 1) && !((int)from & 1) && !(count & 1)) {
+ volatile register ushort *sto, *sfrom, *send;
+
+ count >>= 1;
+ sto = (ushort *)to;
+ sfrom = (ushort *)from;
+ send = sto + count;
+ while(sto < send) {
+ *sto = *sfrom;
+ if (*sto != *sfrom) {
+ err = 1;
+ break;
+ }
+ sto++;
+ sfrom++;
+#ifdef WATCHDOG_ENABLED
+ if (((int)sto & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ }
+ }
+ else {
+ end = to + count;
+ while(to < end) {
+ *to = *from;
+ if (*to != *from) {
+ err = 1;
+ break;
+ }
+ to++;
+ from++;
+#ifdef WATCHDOG_ENABLED
+ if (((int)to & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ }
+ }
+ if (err) {
+ if (verbose)
+ printf(" failed\n");
+ return(-1);
+ }
+ }
+
+done:
+ if (verbose)
+ printf("\n");
+
+ return(0);
+}
diff --git a/main/glib/smemset.c b/main/glib/smemset.c
new file mode 100755
index 0000000..9216b50
--- /dev/null
+++ b/main/glib/smemset.c
@@ -0,0 +1,71 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* s_memset():
+ * Superset of memset() (used to be tfsmemset()).
+ * Includes verbose option, test to make sure the destination is not
+ * within MicroMonitor's own space, plus verification after set.
+ */
+int
+s_memset(uchar *to,uchar val,int count,int verbose,int verifyonly)
+{
+ int failed;
+ uchar *end;
+
+ failed = 0;
+
+#ifndef MONAPP
+ if (inUmonBssSpace((char *)to,(char *)to+count))
+ return(-1);
+#endif
+
+ if (verbose) {
+ printf("%s %7d bytes at 0x%08lx to 0x%02x",
+ verifyonly ? "vrfy" : "set ",count,(ulong)to,val);
+ }
+
+ if ((count == 0) || (verbose > 1))
+ goto done;
+
+ end = to+count;
+
+ if (verifyonly) {
+ while(to < end) {
+#ifdef WATCHDOG_ENABLED
+ if (((ulong)to & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ if (*to++ != val) {
+ failed = 1;
+ break;
+ }
+ }
+ }
+ else {
+ while(to < end) {
+#ifdef WATCHDOG_ENABLED
+ if (((ulong)to & 0xff) == 0)
+ WATCHDOG_MACRO;
+#endif
+ *to = val;
+ if (*to++ != val) {
+ failed = 1;
+ break;
+ }
+ }
+ }
+done:
+ if (verbose) {
+ if (failed)
+ printf(" failed");
+ else if (verifyonly)
+ printf(" OK");
+ printf("\n");
+ }
+ if (failed)
+ return(-1);
+ else
+ return(0);
+}
diff --git a/main/glib/strcasecmp.c b/main/glib/strcasecmp.c
new file mode 100644
index 0000000..12610f5
--- /dev/null
+++ b/main/glib/strcasecmp.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ const unsigned char
+ *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ while (tolower(*us1) == tolower(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower(*us1) - tolower(*--us2));
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char
+ *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ do {
+ if (tolower(*us1) != tolower(*us2++))
+ return (tolower(*us1) - tolower(*--us2));
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/main/glib/strcat.c b/main/glib/strcat.c
new file mode 100644
index 0000000..07a3c08
--- /dev/null
+++ b/main/glib/strcat.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+strcat(char * __restrict s, const char * __restrict append)
+{
+ char *save = s;
+
+ for (; *s; ++s);
+ while ((*s++ = *append++));
+ return(save);
+}
diff --git a/main/glib/strchr.c b/main/glib/strchr.c
new file mode 100644
index 0000000..ab83b39
--- /dev/null
+++ b/main/glib/strchr.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)index.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strchr(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c)
+ return ((char *)p);
+ if (*p == '\0')
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+__weak_reference(strchr, index);
diff --git a/main/glib/strcmp.c b/main/glib/strcmp.c
new file mode 100644
index 0000000..9daf624
--- /dev/null
+++ b/main/glib/strcmp.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+/*
+ * Compare strings.
+ */
+int
+strcmp(const char *s1, const char *s2)
+{
+ while (*s1 == *s2++)
+ if (*s1++ == '\0')
+ return (0);
+ return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
+}
diff --git a/main/glib/strcpy.c b/main/glib/strcpy.c
new file mode 100644
index 0000000..8a48d0d
--- /dev/null
+++ b/main/glib/strcpy.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+char *
+strcpy(char * __restrict to, const char * __restrict from)
+{
+ char *save = to;
+
+ for (; (*to = *from); ++from, ++to);
+ return(save);
+}
diff --git a/main/glib/strlen.c b/main/glib/strlen.c
new file mode 100644
index 0000000..6c665eb
--- /dev/null
+++ b/main/glib/strlen.c
@@ -0,0 +1,18 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* strlen():
+ * Returns the number of
+ * non-NULL bytes in string argument.
+ */
+int
+strlen(register char *s)
+{
+ register char *s0 = s + 1;
+
+ while (*s++ != '\0')
+ ;
+ return (s - s0);
+}
diff --git a/main/glib/strncat.c b/main/glib/strncat.c
new file mode 100644
index 0000000..9630ba3
--- /dev/null
+++ b/main/glib/strncat.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes
+ * are written at dst (at most n+1 bytes being appended). Return dst.
+ */
+char *
+strncat(char * __restrict dst, const char * __restrict src, size_t n)
+{
+ if (n != 0) {
+ char *d = dst;
+ const char *s = src;
+
+ while (*d != 0)
+ d++;
+ do {
+ if ((*d = *s++) == 0)
+ break;
+ d++;
+ } while (--n != 0);
+ *d = 0;
+ }
+ return (dst);
+}
diff --git a/main/glib/strncmp.c b/main/glib/strncmp.c
new file mode 100644
index 0000000..fba4854
--- /dev/null
+++ b/main/glib/strncmp.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+
+ if (n == 0)
+ return (0);
+ do {
+ if (*s1 != *s2++)
+ return (*(const unsigned char *)s1 -
+ *(const unsigned char *)(s2 - 1));
+ if (*s1++ == '\0')
+ break;
+ } while (--n != 0);
+ return (0);
+}
diff --git a/main/glib/strncpy.c b/main/glib/strncpy.c
new file mode 100644
index 0000000..740ac0d
--- /dev/null
+++ b/main/glib/strncpy.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Copy src to dst, truncating or null-padding to always copy n bytes.
+ * Return dst.
+ */
+char *
+strncpy(char * __restrict dst, const char * __restrict src, size_t n)
+{
+ if (n != 0) {
+ char *d = dst;
+ const char *s = src;
+
+ do {
+ if ((*d++ = *s++) == '\0') {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ *d++ = '\0';
+ break;
+ }
+ } while (--n != 0);
+ }
+ return (dst);
+}
diff --git a/main/glib/strnlen.c b/main/glib/strnlen.c
new file mode 100644
index 0000000..f44151f
--- /dev/null
+++ b/main/glib/strnlen.c
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+
+size_t
+strnlen(const char *s, size_t maxlen)
+{
+ size_t len;
+
+ for (len = 0; len < maxlen; len++, s++) {
+ if (!*s)
+ break;
+ }
+ return (len);
+}
diff --git a/main/glib/strpbrk.c b/main/glib/strpbrk.c
new file mode 100644
index 0000000..513f9ce
--- /dev/null
+++ b/main/glib/strpbrk.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Find the first occurrence in s1 of a character in s2 (excluding NUL).
+ */
+char *
+strpbrk(const char *s1, const char *s2)
+{
+ const char *scanp;
+ int c, sc;
+
+ while ((c = *s1++) != 0) {
+ for (scanp = s2; (sc = *scanp++) != '\0';)
+ if (sc == c)
+ return ((char *)(s1 - 1));
+ }
+ return (NULL);
+}
diff --git a/main/glib/strrchr.c b/main/glib/strrchr.c
new file mode 100644
index 0000000..f84ffb7
--- /dev/null
+++ b/main/glib/strrchr.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strrchr(const char *p, int ch)
+{
+ char *save;
+ char c;
+
+ c = ch;
+ for (save = NULL;; ++p) {
+ if (*p == c)
+ save = (char *)p;
+ if (*p == '\0')
+ return (save);
+ }
+ /* NOTREACHED */
+}
+
+__weak_reference(strrchr, rindex);
diff --git a/main/glib/strstr.c b/main/glib/strstr.c
new file mode 100644
index 0000000..22f4835
--- /dev/null
+++ b/main/glib/strstr.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Find the first occurrence of find in s.
+ */
+char *
+strstr(const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != '\0') {
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == '\0')
+ return (NULL);
+ } while (sc != c);
+ } while (strncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
diff --git a/main/glib/strtok.c b/main/glib/strtok.c
new file mode 100644
index 0000000..063a554
--- /dev/null
+++ b/main/glib/strtok.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 1998 Softweyr LLC. All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notices, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notices, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
+ * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#ifdef DEBUG_STRTOK
+#include <stdio.h>
+#endif
+#include <string.h>
+
+char *__strtok_r(char *, const char *, char **);
+
+__weak_reference(__strtok_r, strtok_r);
+
+char *
+__strtok_r(char *s, const char *delim, char **last)
+{
+ char *spanp, *tok;
+ int c, sc;
+
+ if (s == NULL && (s = *last) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *last = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = '\0';
+ *last = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+char *
+strtok(char *s, const char *delim)
+{
+ static char *last;
+
+ return (__strtok_r(s, delim, &last));
+}
+
+#ifdef DEBUG_STRTOK
+/*
+ * Test the tokenizer.
+ */
+int
+main(void)
+{
+ char blah[80], test[80];
+ char *brkb, *brkt, *phrase, *sep, *word;
+
+ sep = "\\/:;=-";
+ phrase = "foo";
+
+ printf("String tokenizer test:\n");
+ strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
+ for (word = strtok(test, sep); word; word = strtok(NULL, sep))
+ printf("Next word is \"%s\".\n", word);
+ strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
+
+ for (word = strtok_r(test, sep, &brkt); word;
+ word = strtok_r(NULL, sep, &brkt)) {
+ strcpy(blah, "blah:blat:blab:blag");
+
+ for (phrase = strtok_r(blah, sep, &brkb); phrase;
+ phrase = strtok_r(NULL, sep, &brkb))
+ printf("So far we're at %s:%s\n", word, phrase);
+ }
+
+ return (0);
+}
+
+#endif /* DEBUG_STRTOK */
diff --git a/main/glib/strtol.c b/main/glib/strtol.c
new file mode 100644
index 0000000..4c3571c
--- /dev/null
+++ b/main/glib/strtol.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ } else if (!any) {
+ } else if (neg)
+ acc = -acc;
+
+noconv:
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/main/glib/strtolower.c b/main/glib/strtolower.c
new file mode 100755
index 0000000..658ab7e
--- /dev/null
+++ b/main/glib/strtolower.c
@@ -0,0 +1,33 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+/* strtolower():
+ * In-place modification of a string to be all lower case.
+ */
+char *
+strtolower(char *string)
+{
+ char *cp;
+
+ cp = string;
+ while(*cp) {
+ *cp = tolower(*cp);
+ cp++;
+ }
+ return(string);
+}
+
+char *
+strtoupper(char *string)
+{
+ char *cp;
+
+ cp = string;
+ while(*cp) {
+ *cp = toupper(*cp);
+ cp++;
+ }
+ return(string);
+}
diff --git a/main/glib/strtoul.c b/main/glib/strtoul.c
new file mode 100644
index 0000000..9bc4a0b
--- /dev/null
+++ b/main/glib/strtoul.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ } else if (!any) {
+ } else if (neg)
+ acc = -acc;
+noconv:
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/main/glib/swap.c b/main/glib/swap.c
new file mode 100755
index 0000000..fa19cbf
--- /dev/null
+++ b/main/glib/swap.c
@@ -0,0 +1,18 @@
+#include "config.h"
+#include <ctype.h>
+#include "genlib.h"
+#include "stddefs.h"
+
+ushort
+swap2(ushort sval_in)
+{
+ return(((sval_in & 0x00ff) << 8) | ((sval_in & 0xff00) >> 8));
+}
+
+ulong
+swap4(ulong sval_in)
+{
+ return(((sval_in & 0x000000ff) << 24) | ((sval_in & 0x0000ff00) << 8) |
+ ((sval_in & 0x00ff0000) >> 8) | ((sval_in & 0xff000000) >> 24));
+}
+
diff --git a/main/glib/ticktock.c b/main/glib/ticktock.c
new file mode 100755
index 0000000..6a29eec
--- /dev/null
+++ b/main/glib/ticktock.c
@@ -0,0 +1,48 @@
+#include "config.h"
+#include <ctype.h>
+#include "ether.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+/* ticktock():
+ * Put out a ticker...
+ */
+void
+ticktock(void)
+{
+ static short tick;
+ char tock;
+
+#if INCLUDE_MONCMD
+ /* Don't do any ticker if the command was issued
+ * from UDP (i.e. moncmd)...
+ */
+ if (IPMonCmdActive)
+ return;
+#endif
+
+ switch(tick) {
+ case 1:
+ case 5:
+ tock = '|';
+ break;
+ case 2:
+ case 6:
+ tock = '/';
+ break;
+ case 3:
+ case 7:
+ tock = '-';
+ break;
+ case 4:
+ case 8:
+ tock = '\\';
+ break;
+ default:
+ tock = '|';
+ tick = 1;
+ break;
+ }
+ tick++;
+ printf("%c\b",tock);
+}
diff --git a/main/make/common.make b/main/make/common.make
new file mode 100755
index 0000000..161ae77
--- /dev/null
+++ b/main/make/common.make
@@ -0,0 +1,132 @@
+############################################################################
+#
+# common.make:
+# This file contains all the common stuff used by MicroMonitor port-specific
+# make files.
+
+############################################################################
+#
+# Various relative directories used to build the monitor:
+#
+BASE = $(TOPDIR)/target
+CPUDIR = $(BASE)/cpu/$(CPUTYPE)
+ZLIBDIR = $(BASE)/zlib
+GLIBDIR = $(BASE)/glib
+COMDIR = $(BASE)/common
+MAKEDIR = $(BASE)/make
+DEVDIR = $(BASE)/dev
+FSDIR = $(BASE)/fs
+FATFSDIR = $(FSDIR)/elmfatfs
+JFFS2DIR = $(BASE)/fs/jffs2
+
+ifeq ($(TOOLBIN),)
+TOOLBIN = $(TOPDIR)/host/bin
+endif
+
+############################################################################
+#
+# Generic tools used by all make files:
+# Names are derived from the TOOL_PREFIX variable
+# assumed to be established in the make file that
+# includes this.
+#
+
+ifeq ($(TOOL_PREFIX),)
+TOOL_PREFIX = $(CPUTYPE)-$(FILETYPE)
+endif
+NM = $(TOOL_PREFIX)-nm
+AR = $(TOOL_PREFIX)-ar
+LD = $(TOOL_PREFIX)-ld
+ASM = $(TOOL_PREFIX)-as
+CC = $(TOOL_PREFIX)-gcc
+STRIP = $(TOOL_PREFIX)-strip
+OBJCOPY = $(TOOL_PREFIX)-objcopy
+OBJDUMP = $(TOOL_PREFIX)-objdump
+
+LIBGCC = `$(CC) --print-libgcc-file-name`
+LIBDIR = $(LIBGCC:/libgcc.a=)
+NOF_LIBGCC = $(LIBDIR)/nof/libgcc.a
+
+# FLASHSUBDIR:
+# This is actually a portion of the PATH to the flash source files.
+# If not specified in the port-specific makefile, then assign the
+# default type of "devices". This then makes the assumption that
+# the files specified by the FLASHSRC variable in the port-specific
+# makefile are under $(BASE)/flash/devices (the new style flash
+# driver for uMon). For the older drivers, use the appropriate
+# directory found under "boards" in the umon_main tree.
+# The prefix $(BASE)/flash is assumed.
+#
+ifeq ($(FLASHSUBDIR),)
+FLASHSUBDIR = devices
+endif
+
+ifeq ($(FLASHDIR),)
+FLASHDIR = $(BASE)/flash/$(FLASHSUBDIR)
+endif
+
+# PORTDIR:
+# By default, PORTDIR is umon/umon_ports; however some ports are not part
+# of the CVS distribution; hence, umon/umon_ports sometimes needs to be
+# overridden...
+ifeq ($(PORTDIR),)
+PORTDIR = umon/umon_ports
+endif
+
+############################################################################
+#
+# Miscellaneous variables used by all targets:
+#
+DEPEND = depend
+DEPENDFILE = depends
+BUILDDIR = build_$(PLATFORM)
+
+COMMON_INCLUDE = -I. -I$(COMDIR) -I$(CPUDIR) -I$(FLASHDIR) -I$(DEVDIR) \
+ -I$(ZLIBDIR) $(PORT_INCLUDE)
+
+COMMON_CFLAGS = -g -c -Wall -DPLATFORM_$(PLATFORM)=1 \
+ -fno-builtin -fno-toplevel-reorder
+
+COMMON_AFLAGS = -xassembler-with-cpp -c -D PLATFORM_$(PLATFORM)=1 \
+ -D ASSEMBLY_ONLY
+
+CFLAGS = $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE)
+ASMFLAGS = $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE)
+
+
+MAKE_LDFILE = $(TOOLBIN)/vsub $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) \
+ $(PLATFORM)_$(@F:.$(FILETYPE)=.ld)
+MAKE_MONBUILT = $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) \
+ $(COMMON_INCLUDE) -omonbuilt.o $(COMDIR)/monbuilt.c
+MAKE_GNUSYMS = $(NM) --numeric-sort $@ > $(@:.$(FILETYPE)=.gsym)
+DUMP_MAP = $(OBJDUMP) -fh $@
+MAKE_BINARY = $(OBJCOPY) -O binary $@ $(@:.$(FILETYPE)=.bin)
+LINK = $(LD) -nostartfiles -o $@ \
+ -T $(PLATFORM)_$(@F:.$(FILETYPE)=.ld)
+DISASSEMBLE = $(OBJDUMP) --source --disassemble $@> \
+ $(@:.$(FILETYPE)=.dis)
+
+MAKE_CTAGS = ctags --file-tags=yes -n -L cscope.files
+MAKE_MONSYMS = $(TOOLBIN)/monsym -p0x -Pmm_ -Sx $(@:.$(FILETYPE)=.gsym) > \
+ $(@:.$(FILETYPE)=.usym)
+DUMP_MAP_ALT = $(TOOLBIN)/$(FILETYPE) -m $@
+MAKE_BINARY_ALT = $(TOOLBIN)/$(FILETYPE) -B $(@:.$(FILETYPE)=.bin) $@
+
+############################################################################
+#
+# Various source lists used to build libraries:
+#
+FATFSSRC = ff.c ffcmd.c cc932.c
+
+ZLIBSRC = adler32.c gzio.c infblock.c infcodes.c inffast.c inflate.c \
+ inftrees.c infutil.c trees.c uncompr.c zcrc32.c zutil.c
+
+GLIBSRC = abs.c asctime.c atoi.c crc16.c crc32.c div.c \
+ getopt.c inrange.c ldiv.c memccpy.c memchr.c \
+ memcmp.c memcpy.c memset.c pollconsole.c prascii.c printmem.c \
+ smemcpy.c smemset.c strcat.c strchr.c strcasecmp.c \
+ strcmp.c strcpy.c strlen.c strncat.c strncmp.c \
+ strncpy.c strpbrk.c strrchr.c strstr.c strtok.c \
+ strtol.c strtoul.c strtolower.c swap.c ticktock.c
diff --git a/main/make/defaults.make b/main/make/defaults.make
new file mode 100644
index 0000000..13ac240
--- /dev/null
+++ b/main/make/defaults.make
@@ -0,0 +1,23 @@
+############################################################################
+#
+# defaults.make:
+# Miscellaneous defaults that can be overridden in the makefile.
+#
+# LEDIT:
+# Line editor mode (vt100 or vi)...
+LEDIT = ledit_vt100.c
+
+# TFSCLEAN:
+# Powersafe defrag (tfsclean1) or non-powersafe defrag (tfsclean2)...
+TFSCLEAN = tfsclean1.c
+
+# FLASHDIR:
+# For systems that use the newer style flash driver, use
+# $(BASE)/flash/devices, or for the older drivers, refer
+# to the flash/boards directory.
+FLASHDIR = $(BASE)/flash/devices
+
+# DHCP:
+# For standard DHCP, use dhcp_00.c, else refer to other dhcp_XX.c file
+# for options.
+DHCP = dhcp_00.c
diff --git a/main/make/objects.make b/main/make/objects.make
new file mode 100644
index 0000000..ec3da67
--- /dev/null
+++ b/main/make/objects.make
@@ -0,0 +1,25 @@
+# Object lists built from the target-specific source lists:
+#
+# LOCSSRC: Assembly source code files in this directory.
+# CPUSSRC: Assembly source code files in the common/cpu directory.
+# LOCCSRC: C source code files in this directory.
+# COMCSRC: C source code files in the common/monitor directory.
+# CPUCSRC: C source code files in the common/cpu directory.
+#
+LOCSOBJ = $(LOCSSRC:%.S=%.o)
+LOCCOBJ = $(LOCCSRC:%.c=%.o)
+CPUSOBJ = $(CPUSSRC:%.S=%.o)
+CPUCOBJ = $(CPUCSRC:%.c=%.o)
+COMCOBJ = $(COMCSRC:%.c=%.o)
+
+# FATFSOBJ: C source code files used by elm-fatfs
+FATFSOBJ = $(FATFSSRC:%.c=%.o)
+
+# ZLIBOBJ: C source code files in the common/zlib directory.
+ZLIBOBJ = $(ZLIBSRC:%.c=%.o)
+
+# GLIBOBJ: C source code files in the common/glib directory.
+GLIBOBJ = $(GLIBSRC:%.c=%.o)
+
+FLASHOBJ = $(FLASHSRC:%.c=%.o)
+IODEVOBJ = $(IODEVSRC:%.c=%.o)
diff --git a/main/make/rules.make b/main/make/rules.make
new file mode 100644
index 0000000..1918fda
--- /dev/null
+++ b/main/make/rules.make
@@ -0,0 +1,461 @@
+###########################################################################
+#
+# targets.make:
+# Targets used by all target builds.
+#
+-include $(DEPENDFILE)
+
+$(LOCSOBJ):
+ $(CC) $(ASMFLAGS) -o ${@F} $(@:%.o=%.S)
+
+$(LOCCOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(@:%.o=%.c)
+
+$(CPUSOBJ):
+ $(CC) $(ASMFLAGS) -o ${@F} $(CPUDIR)/$(@:%.o=%.S)
+
+$(CPUCOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(CPUDIR)/$(@:%.o=%.c)
+
+$(COMCOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(COMDIR)/$(@:%.o=%.c)
+
+$(IODEVOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(DEVDIR)/$(@:%.o=%.c)
+
+$(FLASHOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(FLASHDIR)/$(@:%.o=%.c)
+
+$(ZLIBOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(ZLIBDIR)/$(@:%.o=%.c)
+
+$(GLIBOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(GLIBDIR)/$(@:%.o=%.c)
+
+$(FATFSOBJ):
+ $(CC) $(CFLAGS) -o ${@F} $(FATFSDIR)/$(@:%.o=%.c)
+
+libg.a: $(GLIBOBJ)
+ $(AR) rc libg.a $(GLIBOBJ)
+
+libz.a: $(ZLIBOBJ)
+ $(AR) rc libz.a $(ZLIBOBJ)
+
+libfatfs.a: $(FATFSOBJ)
+ $(AR) rc libfatfs.a $(FATFSOBJ)
+
+###########################################################################
+#
+# depend:
+# Build a file of dependencies to be included in the main makefile.
+#
+$(DEPEND):
+ @if [ ! -f $(DEPENDFILE) ] ; \
+ then \
+ for obj in $(LOCSSRC); do \
+ $(CC) $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(LOCCSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(CPUSSRC); do \
+ $(CC) $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(CPUDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(CPUCSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(CPUDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(COMCSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(COMDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(IODEVSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(DEVDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(FLASHSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(FLASHDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(ZLIBSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(ZLIBDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ for obj in $(GLIBSRC); do \
+ $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \
+ $(CUSTOM_INCLUDE) -MM $(GLIBDIR)/$$obj >>$(DEPENDFILE) ; \
+ echo $$obj dependencies... ; \
+ done; \
+ fi
+
+
+###########################################################################
+#
+# builddir:
+# All output files that are not just .o's or .a's are put in the
+# build directory, so make sure that directory exists...
+#
+$(BUILDDIR):
+ @if ! test -d $(BUILDDIR) ; then rm -f $(BUILDDIR); mkdir $(BUILDDIR); fi
+
+###########################################################################
+#
+# clobber:
+# Remove all files built by this makefile...
+#
+clobber:
+ rm -f *.o *.a *.ld
+ rm -rf $(BUILDDIR) tags cscope* *.gz *.ld depends
+
+###########################################################################
+#
+# clean:
+# Remove all the object files that were built by this makefile...
+#
+clean:
+ rm -f *.o *.a
+
+###########################################################################
+# Added on 6-6-05, to make boot and ramtst files with only one command
+# Top level target: all
+#
+all: boot ramtst
+
+###########################################################################
+#
+# ctags:
+# Build tags file for use by various editors.
+#
+ctags:
+ @if ! test -f cscope.files ; then make cscope; fi
+ $(MAKE_CTAGS)
+
+###########################################################################
+#
+# cscope:
+# Build 'cscope.files' file, which consists of all source files
+# that make up the build. It is used by the cscope tool.
+#
+cscope: cscope_local
+ for file in $(LOCSOBJ:%.o=%.S); do ls $$file \
+ >>cscope.files; done
+ for file in $(LOCCOBJ:%.o=%.c); do ls $$file \
+ >>cscope.files; done
+ for file in $(CPUSOBJ:%.o=%.S); do ls $(CPUDIR)/$$file \
+ >>cscope.files; done
+ for file in $(CPUCOBJ:%.o=%.c); do ls $(CPUDIR)/$$file \
+ >>cscope.files; done
+ for file in $(COMCOBJ:%.o=%.c); do ls $(COMDIR)/$$file \
+ >>cscope.files; done
+ for file in $(IODEVOBJ:%.o=%.c); do ls $(DEVDIR)/$$file \
+ >>cscope.files; done
+ for file in $(GLIBOBJ:%.o=%.c); do ls $(GLIBDIR)/$$file \
+ >>cscope.files; done
+ for file in $(ZLIBOBJ:%.o=%.c); do ls $(ZLIBDIR)/$$file \
+ >>cscope.files; done
+ ls $(COMDIR)/monbuilt.c >>cscope.files
+ ls *.h >>cscope.files
+ ls $(CPUDIR)/*.h >>cscope.files
+ ls $(COMDIR)/*.h >>cscope.files
+ ls $(ZLIBDIR)/*.h >>cscope.files
+
+###########################################################################
+#
+# libgcc:
+# Dump the current libgcc library
+#
+libgcc:
+ @$(CC) --print-libgcc-file-name
+
+
+###########################################################################
+#
+# buildcheck:
+# Check for the presence of the BUILD variable and $(BUILDDIR) directory.
+#
+buildcheck:
+ifeq ($(BUILD),)
+ @echo Must set BUILD variable.
+ @exit 1
+endif
+ @if ! test -d $(BUILDDIR) ; \
+ then \
+ echo Directory $(BUILDDIR) doesn\'t exist; \
+ exit 1; \
+ fi
+
+###########################################################################
+#
+# monsym:
+# Build the symbol table file used by the monitor
+#
+monsym: buildcheck
+ @if ! test -f $(BUILDDIR)/$(BUILD).gsym ; \
+ then \
+ echo File $(BUILDDIR)/$(BUILD).gsym doesn\'t exist; \
+ exit 1; \
+ fi
+ $(TOOLBIN)/monsym -Pmm_ -Sx $(BUILDDIR)/$(BUILD).gsym \
+ > $(BUILDDIR)/$(BUILD).usym
+
+###########################################################################
+#
+# strip:
+# Remove symbols from ramtst.elf image.
+#
+strip:
+ @if ! test -f $(BUILDDIR)/ramtst.elf ; \
+ then \
+ echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \
+ exit 1; \
+ fi
+ $(STRIP) $(BUILDDIR)/ramtst.elf
+
+###########################################################################
+#
+# map:
+# Dump a map of the specified build using objdump.
+#
+map: buildcheck
+ @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \
+ then \
+ echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \
+ exit 1; \
+ fi
+ $(OBJDUMP) -fh $(BUILDDIR)/$(BUILD).elf
+
+###########################################################################
+#
+# emap:
+# Dump a map of the specified build using the 'elf' tool.
+#
+emap: buildcheck
+ @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \
+ then \
+ echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \
+ exit 1; \
+ fi
+ $(TOOLBIN)/elf -m $(BUILDDIR)/$(BUILD).elf
+
+###########################################################################
+#
+# rebuild:
+# Rebuild entirely.
+#
+rebuild: clobber depend boot ramtst
+ @echo
+
+###########################################################################
+#
+# dis:
+# Generate a source/assembly file from the specified build.
+#
+dis: buildcheck
+ @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \
+ then \
+ echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \
+ exit 1; \
+ fi
+ $(OBJDUMP) --source --disassemble $(BUILDDIR)/$(BUILD).elf > \
+ $(BUILDDIR)/$(BUILD).dis
+
+###########################################################################
+#
+# newmon:
+# Use the newmon tool to overwrite a running monitor.
+# Allow the makefile to use "NEWMONBASE" as an override of the
+# default "BOOTROMBASE" for specifying the base address at which
+# newmon is to place the image.
+#
+newmon:
+ @if ! test -f $(BUILDDIR)/boot.bin ; \
+ then \
+ echo File $(BUILDDIR)/boot.bin doesn\'t exist; \
+ exit 1; \
+ fi
+ifndef TARGET_IP
+ @echo "Must specify TARGET_IP on command line (or environment)."
+ @exit 1
+endif
+ifdef NEWMONBASE
+ $(TOOLBIN)/newmon -u -B $(NEWMONBASE) $(TARGET_IP) $(BUILDDIR)/boot.bin
+else
+ifndef BOOTROMBASE
+ @echo "Must specify BOOTROMBASE or NEWMONBASE."
+ @exit 1
+endif
+ $(TOOLBIN)/newmon -u -B $(BOOTROMBASE) $(TARGET_IP) $(BUILDDIR)/boot.bin
+endif
+
+###########################################################################
+#
+# rundisable:
+# Build the tfs.c file with -D TFS_RUN_DISABLE defined so that the
+# image can be built with no ability to autoboot.
+#
+rundisable:
+ $(CC) $(COMMON_CFLAGS) -D TFS_RUN_DISABLE $(CUSTOM_CFLAGS) \
+ $(COMMON_INCLUDE) -o tfs.o $(COMDIR)/tfs.c
+
+###########################################################################
+#
+# tar:
+# Create a .tgz file that includes the current port & template source,
+# portions of umon_main applicable to the port and umon_apps/demo_app.
+# This assumes that umon_main and umon_ports are peer directories
+# that reside under the top-most directory level called "umon".
+#
+tar: clean
+ @rm -f *.tgz cscope.out tags
+ @/bin/sh -c "cd $(UMONTOP)/host; make clean"
+ @/bin/sh -c "cd $(UMONTOP)/../.. ; tar -cvzf umon_$(PLATFORM).tgz \
+ umon/README umon/umon_main/README \
+ umon/umon_main/host umon/umon_main/target/common \
+ umon/umon_main/target/cpu/$(CPUTYPE) \
+ umon/umon_main/target/dev umon/umon_main/target/make \
+ umon/umon_main/target/flash/$(FLASHSUBDIR) \
+ umon/umon_ports/template $(PORTDIR)/$(TGTDIR) \
+ umon/umon_main/target/fs umon/umon_main/target/glib \
+ umon/umon_main/target/zlib umon/umon_apps/demo \
+ umon/umon_apps/user_manual"
+ mv $(UMONTOP)/../../umon_$(PLATFORM).tgz .
+
+###########################################################################
+#
+# bdibuild:
+# Build all the stuff needed to create the images (boot.bin & ramtst.elf)
+# used for BDI2000 recovery.
+#
+bdibuild: clobber depend boot rundisable ramtst clean
+ echo The ramtst target is built with "TFS run" disabled.
+
+###########################################################################
+#
+# recovercopy:
+# Primarily used by esutter to copy the recovery file set to the
+# umon_recover directory. This is usually done after a "make bdibuild"
+# has done and tested.
+#
+recovercopy:
+ @if ! test -f $(BUILDDIR)/boot.bin ; \
+ then \
+ echo File $(BUILDDIR)/boot.bin doesn\'t exist; \
+ exit 1; \
+ fi
+ @if ! test -f $(BUILDDIR)/ramtst.elf ; \
+ then \
+ echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \
+ exit 1; \
+ fi
+ @if ! test -f bdi2000.cfg ; \
+ then \
+ echo File bdi2000.cfg doesn\'t exist; \
+ exit 1; \
+ fi
+ @if ! test -f bdi_hookup.jpg ; \
+ then \
+ echo File bdi_hookup.jpg doesn\'t exist; \
+ exit 1; \
+ fi
+ @rm -rf ../../umon_recover/$(TGTDIR)
+ @mkdir ../../umon_recover/$(TGTDIR)
+ @mkdir ../../umon_recover/$(TGTDIR)/$(BUILDDIR)
+ @cp $(BUILDDIR)/boot.bin ../../umon_recover/$(TGTDIR)/$(BUILDDIR)
+ @cp $(BUILDDIR)/ramtst.elf ../../umon_recover/$(TGTDIR)/$(BUILDDIR)
+ @cp bdi2000.cfg ../../umon_recover/$(TGTDIR)
+ @cp bdi_hookup.jpg ../../umon_recover/$(TGTDIR)
+ @echo Recovery file set for $(PLATFORM):
+ @find ../../umon_recover/$(TGTDIR) -type f
+
+
+
+###########################################################################
+#
+# dld:
+# Use the ttftp tool to download the ramtst elf image into TFS.
+#
+dld: strip
+ifndef TARGET_IP
+ @echo "Must specify TARGET_IP on command line (or environment)."
+ @exit 1
+endif
+ @if ! test -f $(BUILDDIR)/ramtst.elf ; \
+ then \
+ echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \
+ exit 1; \
+ fi
+ $(TOOLBIN)/ttftp $(TARGET_IP) put $(BUILDDIR)/ramtst.elf ramtst,E
+
+###########################################################################
+#
+# dldbin:
+# Use the ttftp tool to download the ramtst binary image into RAM.
+#
+dldbin:
+ifndef TARGET_IP
+ @echo "Must specify TARGET_IP on command line (or environment)."
+ @exit 1
+endif
+ @if ! test -f $(BUILDDIR)/ramtst.bin ; \
+ then \
+ echo File $(BUILDDIR)/ramtst.bin doesn\'t exist; \
+ exit 1; \
+ fi
+ $(TOOLBIN)/ttftp $(TARGET_IP) put $(BUILDDIR)/ramtst.bin $(RAMTSTBASE)
+
+
+###########################################################################
+#
+# help:
+# Dump the common make targets and their purpose:
+#
+help: help_local
+ @echo The following generic make-targets are available:
+ @echo "boot: Build a bootrom-resident version of uMon"
+ @echo "ramtst: Build a ram-resident version of uMon for testing"
+ @echo "clobber: Remove all files built by this makefile."
+ @echo "clean: Remove all object files built by this makefile."
+ @echo "ctags: Build a tags file for use by most source editors."
+ @echo "cscope: Build a cscope.files file for use by cscope."
+ @echo "libgcc: Dump the libgcc used."
+ @echo "depend: Create a dependency list (file=depends) for the build."
+ @echo "map: Dump a map of the build using objdump."
+ @echo " This requires BUILD=xxxx to be specified on the"
+ @echo " make command line. The value of xxxx will usually"
+ @echo " be 'boot', 'ram' or 'ramtst'."
+ @echo " Example: make BUILD=boot map"
+ @echo "emap: Dump a map of the build using the 'elf' tool."
+ @echo " See notes on 'map' above regarding BUILD."
+ @echo "monsym: Create the symbol table file (*.usym) used by"
+ @echo " MicroMonitor. See note in 'map' above regarding BUILD."
+ @echo "dis: Create a source/disassembly file (*.dis) of the image."
+ @echo " See note in 'map' above regarding BUILD."
+ @echo "rebuild: Concatenation of \"clobber, depend, boot and ramtst\""
+ @echo "newmon: Run through the steps needed to burn a new monitor"
+ @echo " Must specify TARGET_IP=a.b.c.d"
+ @echo "dld: Download the ramtst image to the target."
+ @echo " Must specify TARGET_IP=a.b.c.d"
+ @echo "rundisable:"
+ @echo " Rebuild with the tfs run functionality disabled."
+ @echo "bdibuild: Build the files used for BDI2000 disaster recovery."
+ @echo
+ @echo Build-specific outputs for $(PLATFORM) are suffixed as follows:
+ @echo " *.bin: Raw binary image of build, suitable for transfer"
+ @echo " directly to memory."
+ @echo " *.elf: ELF-formatted image."
+ @echo " *.dis: Disassembly of uMon build."
+ @echo " *.gsym: Symbol table formatted by gnu tools (nm)."
+ @echo " *.usym: Symbol table formatted by uMon tools (monsym)."
+ @echo and will be placed in the directory \"build_$(PLATFORM)\".
+ @echo
diff --git a/main/zlib/README b/main/zlib/README
new file mode 100644
index 0000000..f71730c
--- /dev/null
+++ b/main/zlib/README
@@ -0,0 +1,25 @@
+ This code is taken from ftp://ftp.freesoftware.com/pub/infozip/zlib/.
+ For conditions of distribution and use, see copyright notice in zlib.h
+ Most of the code is untouched from the original. The gzio.c file contains
+ the majority of the rework for use within MicroMonitor.
+
+ The ZLIB homepage is http://www.info-zip.org/pub/infozip/zlib
+
+
+ General notice:
+ This code is part of a boot-monitor package developed as a generic base
+ platform for embedded system designs. As such, it is likely to be
+ distributed to various projects beyond the control of the original
+ author. Please notify the author of any enhancements made or bugs found
+ so that all may benefit from the changes. In addition, notification back
+ to the author will allow the new user to pick up changes that may have
+ been made by other users after this version of the code was distributed.
+
+ Note1: the majority of this code was edited with 4-space tabs.
+ Note2: as more and more contributions are accepted, the term "author"
+ is becoming a mis-representation of credit.
+
+ Original author: Ed Sutter
+ Email: esutter@lucent.com
+ Phone: 908-582-2351
+
diff --git a/main/zlib/adler32.c b/main/zlib/adler32.c
new file mode 100644
index 0000000..3b8249f
--- /dev/null
+++ b/main/zlib/adler32.c
@@ -0,0 +1,46 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/main/zlib/adler_mail_1.txt b/main/zlib/adler_mail_1.txt
new file mode 100644
index 0000000..6084cd2
--- /dev/null
+++ b/main/zlib/adler_mail_1.txt
@@ -0,0 +1,23 @@
+Subject: Re: copies of zlib source code
+Date: Wed, 15 Dec 1999 13:12:37 -0800
+From: Mark Adler <Mark.Adler@quest.jpl.nasa.gov>
+To: esutter@lucent.com
+CC: jloup@gzip.org
+
+At 1:03 PM -0600 12/15/99, Ed wrote:
+>Is there any problem with providing copies of the zlib source
+>within the directory structure of the other code I am releasing
+>or must I indirectly refer to your zlib web site and have users
+>get it from there?
+
+No there is no problem, you can distribute it directly. You must not
+misrepresent the origin of the source. If you have modified the zlib
+sources at all, then you have to mark them as such and include that
+in the ChangeLog.
+
+I recommend that you include a reference to the zlib web site so that
+users can if they wish get the latest version.
+
+ http://www.cdrom.com/pub/infozip/zlib/
+
+mark
diff --git a/main/zlib/adler_mail_2.txt b/main/zlib/adler_mail_2.txt
new file mode 100644
index 0000000..9aa117c
--- /dev/null
+++ b/main/zlib/adler_mail_2.txt
@@ -0,0 +1,12 @@
+Subject: Re: copies of zlib source code
+Date: Thu, 16 Dec 1999 13:29:34 -0800
+From: Mark Adler <Mark.Adler@quest.jpl.nasa.gov>
+To: esutter@lucent.com
+
+At 4:04 PM -0500 12/16/99, Ed Sutter wrote:
+>Is there any license associated with zlib?
+
+It is simply the copyright notice, which is in zlib.h, and repeated
+in the README file. That gives you license to use the code.
+
+mark
diff --git a/main/zlib/deflate.h b/main/zlib/deflate.h
new file mode 100644
index 0000000..f94fa4a
--- /dev/null
+++ b/main/zlib/deflate.h
@@ -0,0 +1,316 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zutil.h"
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ int pending; /* nb of bytes in the pending buffer */
+ int noheader; /* suppress zlib header and adler32 */
+ Byte data_type; /* UNKNOWN, BINARY or ASCII */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif
diff --git a/main/zlib/gzio.c b/main/zlib/gzio.c
new file mode 100644
index 0000000..8225dc0
--- /dev/null
+++ b/main/zlib/gzio.c
@@ -0,0 +1,455 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * This has been seriously re-arranged for use within MicroMonitor.
+ * The majority of the rework is to strip out unnecessary parts because this
+ * will reside in flash space. Also, there is no file system interface, all
+ * decompression is done from one point in memory to another point in memory.
+ */
+
+#include "config.h"
+#if INCLUDE_UNZIP
+#include "tfs.h"
+#include "cli.h"
+#include "tfsprivate.h"
+#include "genlib.h"
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free((char *)p);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+} gz_stream;
+
+
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ gzInit():
+ Rewritten (from gzopen()) to support only decompression of data in
+ memory. The next_in member points directly to the compressed data and
+ avail_in is the number of bytes remaining.
+ Things get simpler because of the removal of the file system interface
+ as well as the "only decompression" mode.
+*/
+gz_stream *
+gzInit(unsigned char *compressed_data,int size)
+{
+ int err;
+ gz_stream *s;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s)
+ return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = compressed_data;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = size;
+ s->stream.avail_out = 0;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->crc = zcrc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+ s->mode = 'r';
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK) {
+ destroy(s);
+ return((gz_stream *)Z_NULL);
+ }
+
+ s->stream.avail_out = Z_BUFSIZE;
+ check_header(s); /* skip the .gz header */
+ return(s);
+}
+
+/* ===========================================================================
+ get_byte()
+ Simple now because we assume that avail_in is pointing to the number
+ of bytes in the source buffer that are remaining to be decompressed
+ and next_in is the pointer to the next byte to be retrieved from the
+ buffer.
+*/
+local int
+get_byte(s)
+gz_stream *s;
+{
+ if (s->z_eof)
+ return EOF;
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ return EOF;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ check_header():
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void
+check_header(s)
+gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte(s);
+ if (c != gz_magic[len]) {
+ if (len != 0) {
+ s->stream.avail_in++;
+ s->stream.next_in--;
+ }
+ if (c != EOF) {
+ s->stream.avail_in++;
+ s->stream.next_in--;
+ s->transparent = 1;
+ }
+ s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+ return;
+ }
+ }
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++)
+ (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+/* ===========================================================================
+ destroy():
+ Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+*/
+local int
+destroy (s)
+gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL)
+ err = inflateEnd(&(s->stream));
+
+ if (s->z_err < 0)
+ err = s->z_err;
+
+ TRYFREE(s->outbuf);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ gzRead():
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzRead returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT
+gzRead (gzFile file, voidp buf,unsigned len)
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ while (s->stream.avail_out != 0) {
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy((char *)s->stream.next_out, (char *)s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ int i, c;
+
+ for(i=0;i<(int)(s->stream.avail_out);i++) {
+ c = get_byte(s);
+ if (c == EOF)
+ break;
+ *next_out++ = (Byte)c;
+ s->stream.avail_out--;
+ }
+ }
+ len -= s->stream.avail_out;
+ s->stream.total_in += (uLong)len;
+ s->stream.total_out += (uLong)len;
+ if (len == 0)
+ s->z_eof = 1;
+ return (int)len;
+ }
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may
+ * be different from s->stream.total_out) in case of
+ * concatenated .gz files. Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ uLong total_in = s->stream.total_in;
+ uLong total_out = s->stream.total_out;
+
+ inflateReset(&(s->stream));
+ s->stream.total_in = total_in;
+ s->stream.total_out = total_out;
+ s->crc = zcrc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof)
+ break;
+ }
+ s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ return (int)(len - s->stream.avail_out);
+}
+
+/* ===========================================================================
+ getLong():
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong
+getLong (s)
+gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ unZip():
+ This is the front end to the whole zlib decompressor.
+ It is a chop-up of the original minigzip.c code that came with
+ the zlib source.
+*/
+int
+unZip(char *src, int srclen, char *dest, int destlen)
+{
+ int len;
+ gz_stream *s;
+
+ if ((s = gzInit((unsigned char *)src,srclen)) == Z_NULL) {
+ printf("gzInit(0x%lx,%d) failed!\n",(ulong)src,srclen);
+ return(-1);
+ }
+ len = gzRead(s,dest,destlen);
+ if (len < 0)
+ printf("gzRead() returned %d\n",len);
+
+ destroy(s);
+
+ if (len > 0) {
+ flushDcache(dest,len);
+ invalidateIcache(dest,len);
+ }
+
+ return(len);
+}
+
+char *UnzipHelp[] = {
+ "Decompress memory (or file) to some other block of memory.",
+ "-[v:] {src} [dest]",
+ " src: addr,len | filename",
+ " dest: addr[,len]",
+ "Options:",
+ " -v{varname} place decompress size into shellvar",
+ 0,
+};
+
+/* Unzip():
+ * Access ZLIB decompressor from monitor command line.
+ */
+int
+Unzip(int argc,char *argv[])
+{
+ int opt, tot;
+ ulong srclen, destlen;
+ char *varname, *asc_src, *asc_dst, *comma, *src, *dest;
+
+ destlen = 99999999;
+ varname = asc_dst = (char *)0;
+ dest = (char *)getAppRamStart();
+
+ while((opt=getopt(argc,argv,"v:")) != -1) {
+ switch(opt) {
+ case 'v':
+ varname = optarg;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc == optind+1) {
+ asc_src = argv[optind];
+ }
+ else if (argc == optind+2) {
+ asc_src = argv[optind];
+ asc_dst = argv[optind+1];
+ }
+ else {
+ return(CMD_PARAM_ERROR);
+ }
+
+ comma = strchr(asc_src,',');
+ if (comma) {
+ *comma = 0;
+ src = (char *)strtoul(asc_src,(char **)0,0);
+ srclen = strtoul(comma+1,(char **)0,0);
+ }
+ else {
+ TFILE *tfp;
+ tfp = tfsstat(asc_src);
+ if (!tfp) {
+ printf("%s: file not found\n",asc_src);
+ return(CMD_FAILURE);
+ }
+ src = TFS_BASE(tfp);
+ srclen = TFS_SIZE(tfp);
+ }
+
+ if (asc_dst) {
+ comma = strchr(asc_dst,',');
+ if (comma) {
+ *comma = 0;
+ destlen = strtoul(comma+1,(char **)0,0);
+ }
+ dest = (char *)strtoul(asc_dst,(char **)0,0);
+ }
+
+ tot = unZip(src,srclen,dest,destlen);
+ printf("Decompressed %ld bytes from 0x%lx to %d bytes at 0x%lx.\n",
+ srclen,(ulong)src,tot,(ulong)dest);
+
+ if (varname)
+ shell_sprintf(varname,"%d",tot);
+
+ return(0);
+}
+
+/* Front end to the rest of the unZip() stuff...
+ Return the size of the decompressed data or -1 if failure.
+ The same front API end is available if unpack is used instead of unzip.
+*/
+int
+decompress(char *src,int srclen, char *dest)
+{
+ return(unZip(src,srclen,dest,99999999));
+}
+#else
+int
+decompress(char *src,int srclen, char *dest)
+{
+ return(-1);
+}
+#endif
diff --git a/main/zlib/infblock.c b/main/zlib/infblock.c
new file mode 100644
index 0000000..b51113a
--- /dev/null
+++ b/main/zlib/infblock.c
@@ -0,0 +1,400 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+extern int memcpy(char *,char *,int);
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (c != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ inflate_codes_free(s->sub.decode.codes, z);
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+ Tracev((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Tracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, Z_NULL);
+ return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Tracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy((char *)q, (char *)p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts, z);
+ if (t != Z_OK)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ r = t;
+ if (r == Z_DATA_ERROR)
+ s->mode = BAD;
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts, z);
+ ZFREE(z, s->sub.trees.blens);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ s->mode = BAD;
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_blocks_reset(s, z, Z_NULL);
+ ZFREE(z, s->window);
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ Tracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy((char *)s->window, (char *)d, n);
+ s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+ return s->mode == LENS;
+}
diff --git a/main/zlib/infblock.h b/main/zlib/infblock.h
new file mode 100644
index 0000000..bd25c80
--- /dev/null
+++ b/main/zlib/infblock.h
@@ -0,0 +1,39 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+extern int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+extern void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+extern int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp));
+
+extern void inflate_set_dictionary OF((
+ inflate_blocks_statef *s,
+ const Bytef *d, /* dictionary */
+ uInt n)); /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+ inflate_blocks_statef *s));
diff --git a/main/zlib/infcodes.c b/main/zlib/infcodes.c
new file mode 100644
index 0000000..d4e5ee9
--- /dev/null
+++ b/main/zlib/infcodes.c
@@ -0,0 +1,257 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ inflate_codes_mode mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+ f = (uInt)(q - s->window) < c->sub.copy.dist ?
+ s->end - (c->sub.copy.dist - (q - s->window)) :
+ q - c->sub.copy.dist;
+#else
+ f = q - c->sub.copy.dist;
+ if ((uInt)(q - s->window) < c->sub.copy.dist)
+ f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
diff --git a/main/zlib/infcodes.h b/main/zlib/infcodes.h
new file mode 100644
index 0000000..6c750d8
--- /dev/null
+++ b/main/zlib/infcodes.h
@@ -0,0 +1,27 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+extern int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+extern void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
diff --git a/main/zlib/inffast.c b/main/zlib/inffast.c
new file mode 100644
index 0000000..61a78ee
--- /dev/null
+++ b/main/zlib/inffast.c
@@ -0,0 +1,170 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ if ((uInt)(q - s->window) >= d) /* offset before dest */
+ { /* just copy */
+ r = q - d;
+ *q++ = *r++; c--; /* minimum count is three, */
+ *q++ = *r++; c--; /* so unroll loop a little */
+ }
+ else /* else offset after destination */
+ {
+ e = d - (uInt)(q - s->window); /* bytes from offset to end */
+ r = s->end - e; /* pointer to offset */
+ if (c > e) /* if source crosses, */
+ {
+ c -= e; /* copy to end of window */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window; /* copy rest from start of window */
+ }
+ }
+ do { /* copy all or what's left */
+ *q++ = *r++;
+ } while (--c);
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ t += t->base;
+ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
diff --git a/main/zlib/inffast.h b/main/zlib/inffast.h
new file mode 100644
index 0000000..8facec5
--- /dev/null
+++ b/main/zlib/inffast.h
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+ uInt,
+ uInt,
+ inflate_huft *,
+ inflate_huft *,
+ inflate_blocks_statef *,
+ z_streamp ));
diff --git a/main/zlib/inffixed.h b/main/zlib/inffixed.h
new file mode 100644
index 0000000..77f7e76
--- /dev/null
+++ b/main/zlib/inffixed.h
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+ };
+local inflate_huft fixed_td[] = {
+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+ };
diff --git a/main/zlib/inflate.c b/main/zlib/inflate.c
new file mode 100644
index 0000000..bcdebe1
--- /dev/null
+++ b/main/zlib/inflate.c
@@ -0,0 +1,370 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "config.h"
+#include "genlib.h"
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Tracev((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ WATCHDOG_MACRO;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r == Z_OK)
+ r = f;
+ if (r != Z_STREAM_END)
+ return r;
+ r = f;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ static Byte mark[4] = {0, 0, 0xff, 0xff};
+ if (*p == mark[m])
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+ return Z_STREAM_ERROR;
+ return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/main/zlib/inftrees.c b/main/zlib/inftrees.c
new file mode 100644
index 0000000..35dacc0
--- /dev/null
+++ b/main/zlib/inftrees.c
@@ -0,0 +1,457 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+const char inflate_copyright[] =
+ " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ inflate_huft *, /* space for trees */
+ uInt *, /* hufts used in space */
+ uIntf * )); /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= 288) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+inflate_huft *hp; /* space for trees */
+uInt *hn; /* hufts used in space */
+uIntf *v; /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ r.base = 0; /* Suppress use-before-init warning */
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate new table */
+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
+ return Z_MEM_ERROR; /* not enough memory */
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ j = i >> (w - l);
+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ else
+ *t = q; /* first table is returned result */
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
+ while ((i & mask) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate work area */
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+#endif
+ }
+
+ /* done */
+ ZFREE(z, v);
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for memory allocation */
+{
+#ifdef BUILDFIXED
+ /* build fixed tables if not already */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ uInt f = 0; /* number of hufts used in fixed_mem */
+ uIntf *c; /* length list for huft_build */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate memory */
+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ {
+ ZFREE(z, c);
+ return Z_MEM_ERROR;
+ }
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 9;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+ fixed_mem, &f, v);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+ fixed_mem, &f, v);
+
+ /* done */
+ ZFREE(z, v);
+ ZFREE(z, c);
+ fixed_built = 1;
+ }
+#endif
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
diff --git a/main/zlib/inftrees.h b/main/zlib/inftrees.h
new file mode 100644
index 0000000..85853e0
--- /dev/null
+++ b/main/zlib/inftrees.h
@@ -0,0 +1,58 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit int's) */
+ uInt base; /* literal, length base, distance base,
+ or table offset */
+};
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 huft structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The actual maximum is not known, but the
+ value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+extern int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp)); /* for memory allocation */
diff --git a/main/zlib/infutil.c b/main/zlib/infutil.c
new file mode 100644
index 0000000..4c9fd54
--- /dev/null
+++ b/main/zlib/infutil.c
@@ -0,0 +1,88 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+extern int memcpy(char *,char *, int);
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy((char *)p, (char *)q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy((char *)p, (char *)q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
diff --git a/main/zlib/infutil.h b/main/zlib/infutil.h
new file mode 100644
index 0000000..99d1135
--- /dev/null
+++ b/main/zlib/infutil.h
@@ -0,0 +1,98 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ BAD} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ inflate_huft *hufts; /* single malloc for tree space */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#endif
diff --git a/main/zlib/trees.c b/main/zlib/trees.c
new file mode 100644
index 0000000..0bbf974
--- /dev/null
+++ b/main/zlib/trees.c
@@ -0,0 +1,1212 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1998 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is ascii or binary */
+ if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute first the block length in bytes*/
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/main/zlib/trees.h b/main/zlib/trees.h
new file mode 100644
index 0000000..72facf9
--- /dev/null
+++ b/main/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/main/zlib/uncompr.c b/main/zlib/uncompr.c
new file mode 100644
index 0000000..61e1dc6
--- /dev/null
+++ b/main/zlib/uncompr.c
@@ -0,0 +1,56 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/main/zlib/zconf.h b/main/zlib/zconf.h
new file mode 100644
index 0000000..79b58e6
--- /dev/null
+++ b/main/zlib/zconf.h
@@ -0,0 +1,277 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define compress2 z_compress2
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+# ifndef STDC
+# define STDC
+# endif
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+# define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR _far
+# endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+# if defined(_WINDOWS) || defined(WINDOWS)
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR _cdecl _export
+# endif
+# endif
+# if defined (__BORLANDC__)
+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+# include <windows.h>
+# define ZEXPORT __declspec(dllexport) WINAPI
+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
+# else
+# if defined (_Windows) && defined (__DLL__)
+# define ZEXPORT _export
+# define ZEXPORTVA _export
+# endif
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# if defined (ZLIB_DLL)
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+#endif
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(inflate_blocks,"INBL")
+# pragma map(inflate_blocks_new,"INBLNE")
+# pragma map(inflate_blocks_free,"INBLFR")
+# pragma map(inflate_blocks_reset,"INBLRE")
+# pragma map(inflate_codes_free,"INCOFR")
+# pragma map(inflate_codes,"INCO")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_flush,"INFLU")
+# pragma map(inflate_mask,"INMA")
+# pragma map(inflate_set_dictionary,"INSEDI2")
+# pragma map(inflate_copyright,"INCOPY")
+# pragma map(inflate_trees_bits,"INTRBI")
+# pragma map(inflate_trees_dynamic,"INTRDY")
+# pragma map(inflate_trees_fixed,"INTRFI")
+# pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/main/zlib/zcrc32.c b/main/zlib/zcrc32.c
new file mode 100644
index 0000000..55ba233
--- /dev/null
+++ b/main/zlib/zcrc32.c
@@ -0,0 +1,33 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zlib.h"
+
+#define local static
+extern unsigned long crc32tab[];
+
+#define DO1(buf) crc = crc32tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT zcrc32(crc, buf, len)
+uLong crc;
+const Bytef *buf;
+uInt len;
+{
+ if (buf == Z_NULL)
+ return 0L;
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return crc ^ 0xffffffffL;
+}
diff --git a/main/zlib/zlib.h b/main/zlib/zlib.h
new file mode 100644
index 0000000..923ad45
--- /dev/null
+++ b/main/zlib/zlib.h
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.3, July 9th, 1998
+
+ Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.3"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ the compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero).
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may some
+ introduce some output latency (reading input without producing any output)
+ except when forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ If a preset dictionary is needed at this point (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the
+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+ it sets strm->adler to the adler32 checksum of all output produced
+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+ an error code as described below. At the end of the stream, inflate()
+ checks that its computed adler32 checksum is equal to that saved by the
+ compressor and returns Z_STREAM_END only if the checksum is correct.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+ case, the application may then call inflateSync to look for a good
+ compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.
+
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. If a compressed stream with a larger window size is given as
+ input, inflate() will return with the error code Z_DATA_ERROR instead of
+ trying to allocate a larger window.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h". (See the description
+ of deflateInit2 for more information about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ const voidp buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT zcrc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = zcrc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = zcrc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int err));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/main/zlib/zutil.c b/main/zlib/zutil.c
new file mode 100644
index 0000000..1819bd6
--- /dev/null
+++ b/main/zlib/zutil.c
@@ -0,0 +1,236 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+
+#ifndef HAVE_MEMCPY
+
+void
+zmemcpy(dest, source, len)
+Bytef* dest;
+const Bytef* source;
+uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ extern char *malloc(int);
+ extern int memset(char *,int,int);
+ char *cp;
+
+ if (opaque)
+ items += size - size; /* make compiler happy */
+ cp = malloc(items*size);
+ if (cp) {
+ memset(cp,0,items*size);
+ return((voidpf)cp);
+ }
+ return((voidpf)0);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ extern void free(char *);
+
+ free((char *)ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/main/zlib/zutil.h b/main/zlib/zutil.h
new file mode 100644
index 0000000..52e9378
--- /dev/null
+++ b/main/zlib/zutil.h
@@ -0,0 +1,217 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+typedef unsigned long ulong;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EOF
+#define EOF -1
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# define fdopen(fd,type) _fdopen(fd,type)
+#endif
+
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+ uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
diff --git a/ports/csb740/.vimrc b/ports/csb740/.vimrc
new file mode 100755
index 0000000..2a127e5
--- /dev/null
+++ b/ports/csb740/.vimrc
@@ -0,0 +1,13 @@
+" Very basic VIM startup file
+"
+" Set tab stop to 4 characters:
+set ts=4
+
+" Turn off syntax-sensitive coloring:
+" syntax off
+
+" Enable C-style indentation:
+" set cindent
+
+" Disable the highlighting of search items:
+set nohlsearch
diff --git a/ports/csb740/CSB740_boot.ldt b/ports/csb740/CSB740_boot.ldt
new file mode 100755
index 0000000..c8bc089
--- /dev/null
+++ b/ports/csb740/CSB740_boot.ldt
@@ -0,0 +1,63 @@
+/* CSB740_boot.ld:
+ * This is the memory map file used for the boot-flash based version
+ * of MicroMonitor. The only value that should be considered adjustable
+ * here is the base address of the 'dram' memory block.
+ *
+ */
+MEMORY
+{
+ rom : org = ROMBASE, len = ROMLEN
+ dram : org = DRAMBASE, len = DRAMLEN
+}
+
+SECTIONS
+{
+ .text :
+ {
+ boot_base = .;
+ rom_reset.o(.text)
+ *(.glue_7t)
+ *(.glue_7)
+ } >rom
+
+ .data :
+ {
+ *(.data)
+ } >rom
+
+ .sdata :
+ {
+ *(.sdata)
+ } >rom
+
+ .sdata2 :
+ {
+ *(.sdata2)
+ } >rom
+
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata.str1.4)
+ } >rom
+
+ .got :
+ {
+ *(.got)
+ } >rom
+
+ .bss :
+ {
+ bss_start = .;
+ atag_space = .;
+ . += ATAGSIZE;
+ end_atag_space = .;
+ *(.bss) *(COMMON)
+ } >dram
+
+ .sbss :
+ {
+ *(.sbss)
+ bss_end = .;
+ } >dram
+}
diff --git a/ports/csb740/CSB740_ramtst.ldt b/ports/csb740/CSB740_ramtst.ldt
new file mode 100755
index 0000000..76fbce4
--- /dev/null
+++ b/ports/csb740/CSB740_ramtst.ldt
@@ -0,0 +1,59 @@
+etheraddr = MACADDRBASE;
+alt_tfsdevtbl_base = ALTTFSDEVTBLBASE;
+
+MEMORY
+{
+ rom : org = RAMTSTROMBASE, len = RAMTSTROMLEN
+}
+
+SECTIONS
+{
+ .text :
+ {
+ boot_base = .;
+ ram_reset.o(.text)
+ *(.glue_7t)
+ *(.glue_7)
+ } >rom
+
+ .data :
+ {
+ *(.data)
+ } >rom
+
+ .sdata :
+ {
+ *(.sdata)
+ } >rom
+
+ .sdata2 :
+ {
+ *(.sdata2)
+ } >rom
+
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata.str1.4)
+ } >rom
+
+ .got :
+ {
+ *(.got)
+ } >rom
+
+ .bss :
+ {
+ bss_start = .;
+ atag_space = .;
+ . += ATAGSIZE;
+ end_atag_space = .;
+ *(.bss) *(COMMON)
+ } >rom
+
+ .sbss :
+ {
+ *(.sbss)
+ bss_end = .;
+ } >rom
+}
diff --git a/ports/csb740/_vimrc b/ports/csb740/_vimrc
new file mode 100755
index 0000000..2a127e5
--- /dev/null
+++ b/ports/csb740/_vimrc
@@ -0,0 +1,13 @@
+" Very basic VIM startup file
+"
+" Set tab stop to 4 characters:
+set ts=4
+
+" Turn off syntax-sensitive coloring:
+" syntax off
+
+" Enable C-style indentation:
+" set cindent
+
+" Disable the highlighting of search items:
+set nohlsearch
diff --git a/ports/csb740/ad7843.c b/ports/csb740/ad7843.c
new file mode 100755
index 0000000..79e37ba
--- /dev/null
+++ b/ports/csb740/ad7843.c
@@ -0,0 +1,334 @@
+//==========================================================================
+//
+// ad7843.c
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 03/06/03
+// Description: AD7843 Interface routines for CSB740
+// Modified from MC9328mxl version to use SPI1
+//
+//==========================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "omap3530.h"
+#include "cpu_gpio.h"
+#include "ad7843.h"
+#include "cli.h"
+#include "umongpio.h"
+
+//--------------------------------------------------------------------------
+// function prototypes
+//
+int ads_init(void);
+int ads_rd(uchar ads_ctl);
+
+extern void udelay(int delay);
+
+#ifdef AD7843_GPIOMODE
+
+// After several days trying to get the OMAP's SPI3 controller to interface
+// to the AD7843, I gave up and implemented the protocol with GPIO...
+// SPI_CS: GPIO_91
+// SPI_CLK: GPIO_88
+// SPI_MOSI: GPIO_89
+// SPI_MISO: GPIO_90
+
+#define clrSpiCs() GPIO3_REG(GPIO_DATAOUT) &= ~BIT27
+#define setSpiCs() GPIO3_REG(GPIO_DATAOUT) |= BIT27
+#define clrSpiClk() GPIO3_REG(GPIO_DATAOUT) &= ~BIT24
+#define setSpiClk() GPIO3_REG(GPIO_DATAOUT) |= BIT24
+#define clrSpiMosi() GPIO3_REG(GPIO_DATAOUT) &= ~BIT25
+#define setSpiMosi() GPIO3_REG(GPIO_DATAOUT) |= BIT25
+#define getSpiMiso() (GPIO3_REG(GPIO_DATAIN) & BIT26) ? 1 : 0
+
+
+// ads_rd():
+// A bit-banged implementation of the SPI access for AD7843...
+// Slow and steady gets the job done!
+//
+int
+ads_rd(uchar ads_ctl)
+{
+ ushort mask, val;
+
+ clrSpiClk();
+ clrSpiCs();
+
+ for(mask = 0x80;mask != 0;mask >>= 1) {
+ if (ads_ctl & mask)
+ setSpiMosi();
+ else
+ clrSpiMosi();
+
+ setSpiClk();
+ clrSpiClk();
+ }
+
+ val = 0;
+ for(mask = 0x8000;mask != 0;mask >>= 1) {
+ setSpiClk();
+ if (getSpiMiso())
+ val |= mask;
+ clrSpiClk();
+ }
+
+ clrSpiClk();
+ setSpiCs();
+ return(val);
+}
+
+int
+ads_init(void)
+{
+ GPIO3_REG(GPIO_OE) &= ~(BIT27 | BIT25 | BIT24); // 0 = out
+ GPIO3_REG(GPIO_OE) |= BIT26;
+ setSpiCs();
+ clrSpiClk();
+ clrSpiMosi();
+ return(0);
+}
+
+#else
+
+//--------------------------------------------------------------------------
+// ads_init()/ads_rd():
+//
+// This routine sets up the OMAP3530 SPI3 port. It also turns on
+// the AD7843 pen interrupt via a dummy read. We are using CS0 on SPI3.
+// Can't get this to work. Signals look good on scope, but we're not
+// able to read the data back; hence the need for a GPIO version (above).
+
+int
+ads_rd(uchar ads_ctl)
+{
+ volatile ulong rxval;
+
+ SPI3_REG(SPI_IRQSTATUS) = 0x0003777f;
+ SPI3_REG(SPI_IRQENABLE) = 0x0000007f;
+ SPI3_REG(SPI_CH0_CTRL) = 0x00000001; // Enable SPI3 Channel 0
+
+ // We have this OMAP3530 SPI ctrlr set up in 24-bit data mode, full
+ // duplex transmit/receive. So, put the byte to be transferred in the
+ // upper 8 bits of the 24-bit word, then read back the next 16 bits...
+ SPI3_REG(SPI_TXD0) = ads_ctl << 16;
+
+ // Wait for the receive channel to be full...
+ while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL));
+
+ SPI3_REG(SPI_IRQSTATUS) = 0x0003777f;
+
+ // Read the value...
+ rxval = SPI3_REG(SPI_RXD0);
+
+ SPI3_REG(SPI_CH0_CTRL) = 0x00000000; // Disable SPI3 Channel 0
+
+// if (rxval)
+// printf("%08x\n",rxval);
+
+ return (rxval);
+}
+
+int
+ads_init()
+{
+ unsigned long conf;
+
+
+ // Soft reset...
+ SPI3_REG(SPI_SYSCONFIG) = 0x00000002;
+
+ // Wait for reset done...
+ while((SPI3_REG(SPI_SYSSTATUS) & 1) == 0);
+
+ // Configure chan zero of SPI3...
+ SPI3_REG(SPI_IRQSTATUS) = 0x0003777f;
+ SPI3_REG(SPI_IRQENABLE) = 0x0000007f;
+ SPI3_REG(SPI_MODULCTRL) = 0x00000000; // Master, auto CS generation
+ SPI3_REG(SPI_CH0_CTRL) = 0x00000001; // Enable SPI3 Channel 0
+
+ conf = SPI_CH_CONF_DPE0
+ | SPI_CH_CONF_TRM_TR
+ | SPI_CH_CONF_WL(23) // 24-bit data mode
+ | SPI_CH_CONF_EPOL // CS is active low
+ | SPI_CH_CONF_SB_POL //
+ | SPI_CH_CONF_CLKD(9); // divide by 512 = 93Khz
+
+ SPI3_REG(SPI_CH0_CONF) = conf;
+
+ // enable the AD7843 so it can generate a touch interrupt.
+ // this consists of reading any channel, but setting the
+ // power down mode in the control byte to 00b. note we
+ // flush the returned data
+
+ if (ads_rd(AD7843_S | AD7843_ADD_DFR_Y | AD7843_PD_MOD0) == -1)
+ {
+ printf("Error returned from ads_rd(0x%02x)!\n", (AD7843_S | AD7843_ADD_DFR_Y | AD7843_PD_MOD0));
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+
+//--------------------------------------------------------------------------
+char *adsHelp[] = {
+ "Screen touch demo using AD7843 and OMAP3530 SPI port.",
+ "",
+ "Detect screen touches and display the x,y values via",
+ "the AD7843 and OMAP3530 SPI port.",
+ 0
+};
+
+int ads(int argc, char *argv[])
+{
+ uchar c;
+ int pen, i;
+ //int last_x, last_y;
+ int sum_x, sum_y, average_x, average_y;
+
+ // init the SPI and AD7843
+ if (ads_init() == -1)
+ {
+ printf("Error intializing AD7843!\n");
+ return (CMD_FAILURE);
+ }
+
+ printf("Waiting for Touch (Press \'X\' to end test)...\n");
+
+ pen = 0;
+ while (1)
+ {
+ if (gotachar())
+ {
+ c = getchar();
+ if ((c == 'X') || (c == 'x')) goto done;
+ if (c == 'L') {
+ printf("In ads_rd loop...\n");
+ while(1)
+ ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X);
+ }
+ }
+ if (GPIO_tst(PIRQ) == 0)
+ {
+ printf("Pen Down....\n");
+ pen = 1;
+ //last_x = last_y = 0;
+ while(GPIO_tst(PIRQ) == 0) // keep reading until touch goes away
+ {
+ sum_x = sum_y = 0;
+
+ // display every 4 samples
+ for (i = 0; i < 64 ; i++)
+ {
+ sum_x += ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X);
+ sum_y += ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_Y);
+ }
+ average_x = sum_x/4;
+ average_y = sum_y/4;
+
+ //if ((average_x != last_x) || (average_y != last_y))
+ printf("X = %04d, Y = %04d\n", average_x, average_y);
+
+ //last_x = average_x;
+ //last_y = average_y;
+
+ } // while pen is down
+ }
+ if (pen)
+ {
+ printf("Pen Up....\n");
+ pen = 0;
+ }
+
+ }
+
+done:
+ return(CMD_SUCCESS);
+}
+
+
+/* The next four functions are required for the "scribble" feature in
+ * the FBI command to work...
+ */
+#include "tsi.h"
+
+#define TOUCH_MAX_YVAL 32760
+#define TOUCH_MAX_XVAL 30752
+
+/* tsi_init():
+ * Used to initialize the touch screen interface.
+ */
+int
+tsi_init(void)
+{
+ return(ads_init());
+}
+
+/* tsi_active():
+ * Return 1 if the screen is being touched, else 0.
+ */
+int
+tsi_active(void)
+{
+ if (GPIO_tst(PIRQ) == 0)
+ return(1);
+ return(0);
+}
+
+/* tsi_getx()/tsi_gety():
+ * Return the current 'x' or 'y' position detected by the touch screen.
+ * Notice that these functions return a value that is relative to the
+ * frame-buffer coordinates, not raw the coordinates generated by the
+ * touch-screen hardware.
+ * This requires not only that the incoming value from the AD7843 be
+ * normalized to the range of the X/Y coordinates of the frame buffer,
+ * but it also requires that the 'Y' coordinate be adjusted to be from
+ * top-down, not bottom up.
+ */
+int
+tsi_getx(void)
+{
+ int i, val, tot, stot, tmp;
+
+ tot = stot = 0;
+
+ /* Attempt 8 samples, then average...
+ */
+ for(i=0;i<8;i++) {
+ tmp = ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X);
+ if ((tmp > 0) && (tmp < TOUCH_MAX_XVAL)) {
+ tot += tmp;
+ stot++;
+ }
+ }
+ tot /= stot;
+
+ val = tot / (TOUCH_MAX_XVAL/PIXELS_PER_ROW);
+ return(val);
+}
+
+int
+tsi_gety(void)
+{
+ int i, val, tot, stot, tmp;
+
+ tot = stot = 0;
+
+ /* Attempt 8 samples, then average...
+ */
+ for(i=0;i<8;i++) {
+ tmp = ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_Y);
+ if ((tmp > 0) && (tmp < TOUCH_MAX_YVAL)) {
+ tot += tmp;
+ stot++;
+ }
+ }
+ tot /= stot;
+
+ val = PIXELS_PER_COL - (tot/(TOUCH_MAX_YVAL/PIXELS_PER_COL));
+ return(val);
+}
diff --git a/ports/csb740/ad7843.h b/ports/csb740/ad7843.h
new file mode 100755
index 0000000..f4a0b71
--- /dev/null
+++ b/ports/csb740/ad7843.h
@@ -0,0 +1,35 @@
+//==========================================================================
+//
+// ad7843.h
+//
+// Author(s): Michael Kelly, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 03/06/03
+// Description: This file contains register offsets and bit defines
+// for the Analog Devices AD7843 Touch Screen Controller
+//
+
+//
+// Bit positions for AD7843 Control byte
+//
+#define AD7843_S 0x80 // Start bit, always 1
+#define AD7843_8BIT 0x08 // 0 = 12-bit conversion, 1 = 8-bits
+#define AD7843_SER 0x04 // 0 = Differential, 1 = Single ended
+
+// Address select defines for Single-Ended mode
+#define AD7843_ADD_SER_Y (AD7843_SER | (0x1 << 4)) // Y position measurement
+#define AD7843_ADD_SER_IN3 (AD7843_SER | (0x2 << 4)) // auxillary input 1 measurement
+#define AD7843_ADD_SER_X (AD7843_SER | (0x5 << 4)) // X position measurement
+#define AD7843_ADD_SER_IN4 (AD7843_SER | (0x6 << 4)) // auxillary input 2 measurement
+
+// Address select defines for Differential mode
+#define AD7843_ADD_DFR_Y (0x1 << 4) // Y position measurement
+#define AD7843_ADD_DFR_X (0x5 << 4) // X position measurement
+
+// Power Down Modes
+#define AD7843_PD_MOD0 0x0 // low-power mode, no power-up delay, *IRQ is enabled
+#define AD7843_PD_MOD1 0x1 // same as low-power mode, except *IRQ is disabled
+#define AD7843_PD_MOD2 0x2 // device on, *IRQ is enabled
+#define AD7843_PD_MOD3 0x3 // device on, *IRQ is disabled
+
+//#define AD7843_GPIOMODE
diff --git a/ports/csb740/ads7846.c b/ports/csb740/ads7846.c
new file mode 100755
index 0000000..e3b2a68
--- /dev/null
+++ b/ports/csb740/ads7846.c
@@ -0,0 +1,180 @@
+//==========================================================================
+//
+// ads7846.c
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 03/06/03
+// Description: ADS7846 Interface routines for CSB740
+// Modified from MC9328mxl version to use SPI1
+//
+//==========================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "omap3530.h"
+#include "cpu_gpio.h"
+#include "ads7846.h"
+#include "cli.h"
+#include "umongpio.h"
+
+//--------------------------------------------------------------------------
+// function prototypes
+//
+int ads_init(void);
+int ads_rd(uchar ads_ctl);
+
+extern void udelay(int delay);
+
+//--------------------------------------------------------------------------
+// ads_init()
+//
+// This routine sets up the OMAP3530 SPI3 port in Microwire mode
+// (8 bit control, 16 bit data, 24 bit total). It also turns on
+// the ADS7843 pen interrupt via a dummy read. Note that we assume
+// that PERCLK2 is 12Mhz (HCLK/4). We are using CS0 on SPI3.
+//
+int ads_init()
+{
+ volatile uchar temp;
+
+
+ SPI3_REG(SPI_CH0_CTRL) = 0x00; // Disable SPI3 Channel 0
+
+ SPI3_REG(SPI_CH0_CONF) = SPI_CH_CONF_CLKG
+ | SPI_CH_CONF_DPE0 // no transmission on SPI3_MISO
+ | SPI_CH_CONF_WL(7) // 8-bit data mode
+ | SPI_CH_CONF_EPOL // CS is active low
+// | SPI_CH_CONF_SB_POL //
+// | SPI_CH_CONF_SBE //
+ | SPI_CH_CONF_CLKD(9); // divide by 512 = 93Khz
+// | SPI_CH_CONF_PHA; // Data is latched on even numbered edges
+// | SPI_CH_CONF_POL; // SPI clock is active low
+
+ SPI3_REG(SPI_MODULCTRL) = 0x0; // Functional mode, Master, and auto CS generation
+
+ SPI3_REG(SPI_CH0_CTRL) = 0x01; // Enable SPI3 Channel 0
+
+ // enable the ADS7846 so it can generate a touch interrupt.
+ // this consists of reading any channel, but setting the
+ // power down mode in the control byte to 00b. note we
+ // flush the returned data
+ //ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_X);
+ ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_Y);
+// ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_Y);
+ temp = SPI3_REG(SPI_RXD0);
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+int ads_rd(uchar ads_ctl)
+{
+ int timeout = 100;
+ volatile uchar temp0, temp1;
+
+ // the OMAP3530 only handles up to 16-bits per transfer
+ // so we send 8-bits at a time to get our total of 24
+
+// SPI3_REG(SPI_TXD0) = ads_ctl;
+// udelay(10);
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY));
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL));
+// temp0 = SPI3_REG(SPI_RXD0);
+//
+// SPI3_REG(SPI_TXD0) = 0;
+// udelay(10);
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY));
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL));
+// temp0 = SPI3_REG(SPI_RXD0);
+//
+// SPI3_REG(SPI_TXD0) = 0;
+// udelay(10);
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY));
+// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL));
+// temp1 = SPI3_REG(SPI_RXD0);
+
+ SPI3_REG(SPI_TXD0) = ads_ctl;
+ udelay(10);
+ while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY));
+ while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL));
+ temp0 = SPI3_REG(SPI_RXD0);
+
+ SPI3_REG(SPI_TXD0) = 0;
+ udelay(10);
+ while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY));
+ while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL));
+ temp0 = SPI3_REG(SPI_RXD0);
+
+// SPI3_REG(SPI_TXD0) = 0;
+// udelay(10);
+// while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY));
+// while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL));
+// temp1 = SPI3_REG(SPI_RXD0);
+ temp1 = 0;
+ return ((temp0 << 8) | temp1);
+}
+
+//--------------------------------------------------------------------------
+char *adsHelp[] = {
+ "Screen touch demo using ADS7846 and OMAP3530 SPI port.",
+ "",
+ 0
+};
+
+int ads(int argc, char *argv[])
+{
+ uchar c;
+ int pen, i;
+ int average_x, average_y;
+
+ // init the SPI and ADS7846
+ if (ads_init() == -1)
+ {
+ printf("Error intializing ADS7846!\n");
+ return (CMD_FAILURE);
+ }
+
+ printf("Waiting for Touch (Press \'X\' to end test)...\n");
+
+ pen = 0;
+ while (1)
+ {
+ if (gotachar())
+ {
+ c = getchar();
+ if ((c == 'X') || (c == 'x')) goto done;
+ }
+ if (GPIO_tst(PIRQ) == 0)
+ {
+ printf("Pen Down....\n");
+ pen = 1;
+ while(GPIO_tst(PIRQ) == 0) // keep reading until touch goes away
+ {
+ average_x = 0;
+ average_y = 0;
+
+ // display every 256 samples (less if pen is down a short time)
+ for (i = 0; i < 256 ; i++)
+ {
+// average_x += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_X);
+// average_y += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_Y);
+ average_x += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_X);
+ average_y += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_Y);
+ }
+ printf("X = %04d, Y = %04d\n", average_x/i, average_y/i);
+
+ } // while pen is down
+ }
+ if (pen)
+ {
+ printf("Pen Up....\n");
+ pen = 0;
+ }
+
+ }
+
+done:
+ return(CMD_SUCCESS);
+}
diff --git a/ports/csb740/ads7846.h b/ports/csb740/ads7846.h
new file mode 100755
index 0000000..9ee33dc
--- /dev/null
+++ b/ports/csb740/ads7846.h
@@ -0,0 +1,56 @@
+//==========================================================================
+//
+// ads7846.h
+//
+// Author(s): Michael Kelly, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 03/06/03
+// Description: This file contains register offsets and bit defines
+// for the TI ADS7846 Touch Screen Controller
+//
+
+//
+// Bit positions for ADS7846E Control byte
+//
+#define ADS7846E_S 0x80 // Start bit, always 1
+#define ADS7846E_8BIT 0x08 // 0 = 12-bit conversion, 1 = 8-bits
+#define ADS7846E_SER 0x04 // 0 = Differential, 1 = Single ended
+
+//
+// Address select defines for single ended mode (or'ed with the single ended select bit)
+//
+// USE FOR ADS7846
+//#define ADS7846E_ADD_SER_TEMP0 (ADS7846E_SER | (0x0 << 4)) // temperature measurement 1
+//#define ADS7846E_ADD_SER_Y (ADS7846E_SER | (0x1 << 4)) // Y position measurement
+//#define ADS7846E_ADD_SER_BAT (ADS7846E_SER | (0x2 << 4)) // battery input measurement
+//#define ADS7846E_ADD_SER_Z1 (ADS7846E_SER | (0x3 << 4)) // pressure measurement 1
+//#define ADS7846E_ADD_SER_Z2 (ADS7846E_SER | (0x4 << 4)) // pressure measurement 2
+//#define ADS7846E_ADD_SER_X (ADS7846E_SER | (0x5 << 4)) // X position measurement
+//#define ADS7846E_ADD_SER_AUX (ADS7846E_SER | (0x6 << 4)) // auxillary input measurement
+//#define ADS7846E_ADD_SER_TEMP1 (ADS7846E_SER | (0x7 << 4)) // temperature measurement 2
+
+// USE FOR ADS7843
+//#define ADS7846E_ADD_SER_TEMP0 (ADS7846E_SER | (0x0 << 4)) // temperature measurement 1
+#define ADS7846E_ADD_SER_Y (ADS7846E_SER | (0x1 << 4)) // Y position measurement
+//#define ADS7846E_ADD_SER_BAT (ADS7846E_SER | (0x2 << 4)) // battery input measurement
+//#define ADS7846E_ADD_SER_Z1 (ADS7846E_SER | (0x2 << 4)) // pressure measurement 1
+//#define ADS7846E_ADD_SER_Z2 (ADS7846E_SER | (0x6 << 4)) // pressure measurement 2
+#define ADS7846E_ADD_SER_X (ADS7846E_SER | (0x5 << 4)) // X position measurement
+//#define ADS7846E_ADD_SER_AUX (ADS7846E_SER | (0x6 << 4)) // auxillary input measurement
+//#define ADS7846E_ADD_SER_TEMP1 (ADS7846E_SER | (0x7 << 4)) // temperature measurement 2
+
+//
+// Address select defines for differential mode
+//
+#define ADS7846E_ADD_DFR_X (0x1 << 4) // Y position measurement
+//#define ADS7846E_ADD_DFR_Z1 (0x2 << 4) // pressure measurement 1
+//#define ADS7846E_ADD_DFR_Z2 (0x6 << 4) // pressure measurement 2
+#define ADS7846E_ADD_DFR_Y (0x5 << 4) // X position measurement
+
+//
+// Power Down Modes
+//
+#define ADS7846E_PD_LPWR 0x0 // low-power mode, no power-up delay, *IRQ is enabled
+#define ADS7846E_PD_REF 0x1 // 2.5V reference off, ADC on, requires delay before conversion
+#define ADS7846E_PD_ADC 0x2 // ADC off, REF on, no delay required
+#define ADS7846E_PD_IRQ 0x3 // device on, but *IRQ is disabled
diff --git a/ports/csb740/bashrc b/ports/csb740/bashrc
new file mode 100755
index 0000000..b329597
--- /dev/null
+++ b/ports/csb740/bashrc
@@ -0,0 +1,12 @@
+PS1=CSB740:
+export TITLE="COGENT CSB740 ARM Monitor Development"
+export UMONTOP=../../umon_main
+export tools=$UMONTOP/host
+export target=$UMONTOP/target
+export cpu=$target/cpu
+export zlib=$target/zlib
+export com=$target/common
+export misc=$target/misc
+export make=$target/make
+export flash=$target/flash
+export dev=$target/dev
diff --git a/ports/csb740/bdi2000.cfg b/ports/csb740/bdi2000.cfg
new file mode 100755
index 0000000..93a82cf
--- /dev/null
+++ b/ports/csb740/bdi2000.cfg
@@ -0,0 +1,188 @@
+; bdiGDB configuration for TI OMAP3430 ES1.0
+; ------------------------------------------
+;
+; To halt the core as soon as possible after power-up,
+; select EMU1=1,EMU0=0 (Wait In Reset mode WIR).
+;
+; Commands supported in the SCANINIT and SCANPOST strings:
+;
+; I<n>=<...b2b1b0> write IR, b0 is first scanned
+; D<n>=<...b2b1b0> write DR, b0 is first scanned
+; n : the number of bits 1..256
+; bx : a data byte, two hex digits
+; W<n> wait for n (decimal) micro seconds
+; T1 assert TRST
+; T0 release TRST
+; R1 assert RESET
+; R0 release RESET
+; CH<n> clock TCK n (decimal) times with TMS high
+; CL<n> clock TCK n (decimal) times with TMS low
+;
+;
+[INIT]
+WREG CPSR 0x000001D3 ;select ARM / supervisor mode
+
+WM32 0x48314048 0x0000aaaa ;disable watchdog WDT2
+WM32 0x48314048 0x00005555 ;disable watchdog WDT2
+
+WGPR 11 0x40200020 ;set frame pointer to free RAM
+WM32 0x40200020 0x40200028 ;dummy stack frame
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Initialize Pins
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+WM32 0x48002170 0x01190019 ; Enable UART2 RX and TX
+WM32 0x48002a18 0x0018010f ; Enable SYS_CLKOUT1
+WM32 0x480021e0 0x0018010f ; Enable SYS_CLKOUT2
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Initialize Clocks
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;WM32 0x48306d70 0x00000000 ; disable sys_clk1
+;WM32 0x4830729C 0x00000006 ; set polarity
+WM32 0x48306814 0x00000000 ; Enable Interface clock to be Free running
+WM32 0x48004e10 0x00000001 ; Enable L3_ICLK and L4_ICLK
+WM32 0x48004a30 0x00006000 ; Enable Auto Clock for UART1 and UART2
+;WM32 0x48004d70 0x00000000 ; Enable source for SYS_CLKOUT2
+;WM32 0x48004d70 0x00000080 ; Enable SYS_CLKOUT2
+WM32 0x48004a00 0xc3fffe01 ; Turn on all available module clocks
+WM32 0x48004a10 0x7ffffedb ; Turn on all available peripheral clocks
+;WM32 0x48306d70 0x00000080 ; enable sys_clk1
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Initialize CS0
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+WM32 0x6E000010 0x08 ; Set No-idle, Normal Mode, CLK free running
+WM32 0x6E000078 0x00000C48 ; Config7
+WM32 0x6E000060 0x00001200 ; Config1
+WM32 0x6E000064 0x000f0f01 ; Config2
+WM32 0x6E000068 0x00020201 ; Config3
+WM32 0x6E00006C 0x0C060C06 ; Config4
+WM32 0x6E000070 0x01131F1F ; Config5
+WM32 0x6E000074 0x0F030000 ; Config6
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Initialize DDR
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;/* SDRAM software reset */
+;/* No idle ack and RESET enable */
+;__raw_writel(0x1A, SDRC_REG(SYSCONFIG));
+WM32 0x6D000010 0x0000001A ; reset DDR
+;sdelay(100);
+DELAY 100
+;/* No idle ack and RESET disable */
+;__raw_writel(0x18, SDRC_REG(SYSCONFIG));
+WM32 0x6D000010 0x00000018 ; release reset
+DELAY 100
+;
+;/* SDRC Sharing register */
+;/* 32-bit SDRAM on data lane [31:0] - CS0 */
+;/* pin tri-stated = 1 */
+;__raw_writel(0x00000100, SDRC_REG(SHARING));
+WM32 0x6D000044 0x00000100
+;
+;/* ----- SDRC Registers Configuration --------- */
+;/* SDRC_MCFG0 register */
+;__raw_writel(0x02584099, SDRC_REG(MCFG_0));
+WM32 0x6D000080 0x02584099
+;
+;/* SDRC_RFR_CTRL0 register */
+;__raw_writel(0x54601, SDRC_REG(RFR_CTRL_0));
+WM32 0x6D0000a4 0x00054601
+;
+;/* SDRC_ACTIM_CTRLA0 register */
+;__raw_writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0));
+WM32 0x6D00009c 0xA29DB4C6
+;
+;/* SDRC_ACTIM_CTRLB0 register */
+;__raw_writel(0x12214, SDRC_REG(ACTIM_CTRLB_0));
+WM32 0x6D0000A0 0x00012214
+;
+;/* Disble Power Down of CKE due to 1 CKE on combo part */
+;__raw_writel(0x00000081, SDRC_REG(POWER));
+WM32 0x6D000070 0x00000081
+;
+;/* SDRC_MANUAL command register */
+;/* NOP command */
+;__raw_writel(0x00000000, SDRC_REG(MANUAL_0));
+WM32 0x6D0000A8 0x00000000
+;
+;/* Precharge command */
+;__raw_writel(0x00000001, SDRC_REG(MANUAL_0));
+WM32 0x6D0000A8 0x00000001
+;
+;/* Auto-refresh command */
+;__raw_writel(0x00000002, SDRC_REG(MANUAL_0));
+WM32 0x6D0000A8 0x00000002
+;
+;/* Auto-refresh command */
+;__raw_writel(0x00000002, SDRC_REG(MANUAL_0));
+WM32 0x6D0000A8 0x00000002
+;
+;/* SDRC MR0 register Burst length=4 */
+;__raw_writel(0x00000032, SDRC_REG(MR_0));
+WM32 0x6D000084 0x00000032
+;
+;/* SDRC DLLA control register */
+;__raw_writel(0x0000000A, SDRC_REG(DLLA_CTRL));
+WM32 0x6D000060 0x0000000A
+
+[TARGET]
+CPUTYPE OMAP3430
+CLOCK 1 ; JTAG clock
+POWERUP 2000 ; power-up delay
+TRST PUSHPULL ; TRST driver type (OPENDRAIN | PUSHPULL)
+RESET HARD ; NONE | HARD <n> (ms)
+STARTUP HALT ; let boot code setup the system
+;STARTUP RUN ; let boot code setup the system
+ENDIAN LITTLE ; memory model (LITTLE | BIG)
+;MEMACCESS CORE 10 ; memory access via core (8 TCK's access delay)
+MEMACCESS AHB 8 ; memory access via AHB (64 TCK's access delay)
+;VECTOR CATCH 0x1B ; catch Abort, Undef, Reset
+
+SCANPRED 1 6 ; count for ICEPick TAP
+SCANSUCC 1 8 ; Xilinx
+
+; Configure ICEPick module to make Cortex-A8 DAP-TAP visible
+SCANINIT t1:w1000:t0:w1000: ; toggle TRST,
+SCANINIT ch10:w1000: ; clock TCK with TMS high and wait
+SCANINIT i6=07:d8=89:i6=02: ; connect and select router
+SCANINIT d32=81000080: ; IP control: KeepPowered
+SCANINIT d32=a3002048: ; TAP3: DebugConnect, ForcePower, ForceActive
+SCANINIT d32=81000081: ; IP control: KeepPowered, SysReset
+SCANINIT d32=a3002148: ; enable TAP3
+SCANINIT cl10:i10=ffff ; clock 10 times in RTI, scan bypass
+
+;assert SysSeset after debugger has setup
+;SCANPOST i10=ffff: ; scan bypass
+;SCANPOST i10=002f: ; IP(router) - TAP3(bypass)
+;SCANPOST d33=0102000102: ; IP control = SysReset
+;SCANPOST i10=ffff ; scan bypass
+
+[HOST]
+IP 192.168.1.3
+FILE build_csb740\ramtst.elf
+FORMAT ELF
+LOAD MANUAL ;load file MANUAL or AUTO after reset
+PROMPT CSB740_>
+TELNET NOECHO
+
+[FLASH]
+WORKSPACE 0x80001000 ;workspace at 0x1000
+CHIPSIZE 0x4000000
+CHIPTYPE MIRRORX16
+BUSWIDTH 16
+FILE build_csb740\boot.bin
+FORMAT BIN 0x08000000
+ERASE 0x08000000
+ERASE 0x08020000
+ERASE 0x08040000
+ERASE 0x08060000
+ERASE 0x08080000
+
+[REGS]
+FILE C:\els\abatron\arm11\regOMAP3430.def
diff --git a/ports/csb740/config.h b/ports/csb740/config.h
new file mode 100755
index 0000000..8a05ff1
--- /dev/null
+++ b/ports/csb740/config.h
@@ -0,0 +1,202 @@
+/*
+ * Monitor configuration file for CSB740
+ *
+ * Adapted by Luis Torrico, Cogent Computer Systems, Inc.
+ * email: luis@cogcomp.com
+ *
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Author: Ed Sutter
+ * email: esutter@lucent.com
+ * phone: 908-582-2351
+ */
+
+/*
+ * The target_putchar() function also drops the character at the
+ * LCD...
+ */
+//#define MORE_PUTCHAR lcd_putchar
+//#define CONSOLE_UART_BASE (OMAP35XX_L4_IO_BASE+0x6C000)
+#define CONSOLE_UART_BASE 0x4806C000
+
+#define SIO_STEP 4
+#define IEN_DEFAULT 0x40
+#define MCTL_DEFAULT 0x01
+
+#define TIMER_TICKS_PER_MSEC 545000
+
+/* DEFAULT_ETHERADD & DEFAULT_IPADD:
+ * Refer to notes in ethernet.c function EthernetStartup() for details
+ * regarding the use of these definitions.
+ * DEFAULT_IPADD could be set to "DHCP" or "BOOTP" as well.
+ */
+#define DEFAULT_ETHERADD "00:30:23:40:00:" // Cogent Block
+#define DEFAULT_IPADD "192.168.254.110"
+
+#define CPU_LE
+
+// override the app ram base to set it to 2Mbyte. This reserves space
+// for umon and the LCD controller buffer
+#define APPRAMBASE_OVERRIDE 0x80400000
+
+// Establish a user defined function to be called when uMon
+// prints out the startup banner...
+// If this is defined, then the output similar to the following will
+// be printed just above the uMon header...
+// Silicon ID: 1.0
+// CPU Rev: 2, Variant: 1
+// CM Rev: 1.0, PRM Rev: 1.0
+// #define USR_HEADER_FUNC show_revision
+
+/* Defining DONT_CENTER_MONHEADER eliminates the automatic centering
+ * of the monitor's startup banner...
+ */
+#define DONT_CENTER_MONHEADER
+
+/* XBUFCNT & RBUFCNT:
+ * Number of transmit and receive buffers allocated to ethernet.
+ * The total of XBUFCNT+RBUFCNT should not exceed MAXEBDS
+ */
+#define XBUFCNT 8
+#define RBUFCNT 8
+#define XBUFSIZE 2048
+#define RBUFSIZE 2048
+
+/* LOOPS_PER_SECOND:
+ * Approximately the size of a loop that will cause a 1-second delay.
+ * This can be guestimated or modified with the sleep -c command at the
+ * monitor command line.
+ */
+#define LOOPS_PER_SECOND 15000
+
+#define INCLUDE_NANDCMD 0
+
+#if INCLUDE_NANDCMD
+/* Needed for NAND to work with TFSRAM:
+ */
+#define NAND_TFS_BASE 0x10000 // base of TFS in NAND
+
+#define FLASHRAM_BASE 0x80300000
+#define FLASHRAM_END 0x8037ffff
+#define FLASHRAM_SECTORSIZE 0x00010000
+#define FLASHRAM_SPARESIZE FLASHRAM_SECTORSIZE
+#define FLASHRAM_BANKNUM 1
+#define FLASHRAM_SECTORCOUNT 8
+#endif
+
+/* Flash bank configuration:
+ */
+#ifdef FLASHRAM_BASE
+#define FLASHBANKS 2
+#else
+#define FLASHBANKS 1
+#endif
+#define SINGLE_FLASH_DEVICE 1
+#define FLASH_COPY_TO_RAM 1
+#define FLASH_BANK0_BASE_ADDR 0x08000000
+#define FLASH_PROTECT_RANGE "0-2"
+#define FLASH_BANK0_WIDTH 2
+#define FLASH_LARGEST_SECTOR 0x20000
+#define FLASH_LOOP_TIMEOUT 10000000
+#define BUFFERED_WRITE
+
+/* TFS definitions:
+ * TFSSTART: Base address in FLASH at which TFS starts.
+ * TFSEND: End address of TFS in FLASH.
+ * TFSSPARE: Location of sector that is used as the spare sector
+ * by TFS for defragmentation.
+ * TFSSPARESIZE: Size of the spare sector used by TFS for defragmentation.
+ * TFSSECTORCOUNT: Number of eraseable sectors that TFS covers, not including
+ * the TFSSPARE sector.
+ */
+#define TFSSPARESIZE FLASH_LARGEST_SECTOR
+#define TFS_DEVTOT 1
+#define TFSSTART (FLASH_BANK0_BASE_ADDR+0x060000)
+//#define TFSEND (FLASH_BANK0_BASE_ADDR+0x007dffff) // 8MB Flash
+#define TFSEND (FLASH_BANK0_BASE_ADDR+0x00edffff) // 16MB Flash
+//#define TFSEND (FLASH_BANK0_BASE_ADDR+0x03dfffff) // 64MB Flash
+#define TFSSPARE (TFSEND+1)
+#define TFSSECTORCOUNT ((TFSSPARE-TFSSTART)/0x20000)
+#define TFS_EBIN_ELFMSBIN 1
+#define TFS_VERBOSE_STARTUP 1
+#define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base
+
+/* Specify CPU/PLATFORM type and name so that common code can be used
+ * for a similar cpu, on different platforms.
+ * The 'TYPE' definition is used for ifdefs in the code and the 'NAME'
+ * is used for printfs in the code.
+ */
+#define CPU_TYPE OMAP3530
+#define CPU_NAME "TI OMAP3530 Cortex-A8"
+#define PLATFORM_TYPE CSB740
+#define PLATFORM_NAME "Cogent CSB740"
+
+/* Specify the size of the memory block (in monitor space) that is to be
+ * allocated to malloc in the monitor. Note that this size can be dynamically
+ * increased using the heap extension option in the heap command.
+ */
+#define ALLOCSIZE (64*1024)
+#define MONSTACKSIZE (16*1024)
+
+// Cogent specific options
+#define INCLUDE_I2C 0
+#define INCLUDE_LCD 1
+
+/* Specify inclusion of subsystems within the monitor here.
+ * Refer to comments in common/monitor/inc_check.h for details on
+ * each of these macros.
+ */
+
+#define INCLUDE_MEMTRACE 1
+#define INCLUDE_MEMCMDS 1
+#define INCLUDE_EDIT 1
+#define INCLUDE_DISASSEMBLER 0
+#define INCLUDE_UNZIP 1
+#define INCLUDE_ETHERNET 1
+#define INCLUDE_ICMP 1
+#define INCLUDE_TFTP 1
+#define INCLUDE_DHCPBOOT 1
+#define INCLUDE_TFS 1
+#define INCLUDE_TFSCLI 1
+#define INCLUDE_TFSAPI 1
+#define INCLUDE_TFSSCRIPT 1
+#define INCLUDE_TFSSYMTBL 1
+#define INCLUDE_XMODEM 1
+#define INCLUDE_LINEEDIT 1
+#define INCLUDE_EE 0
+#define INCLUDE_FLASH 1
+#define INCLUDE_STRACE 1
+#define INCLUDE_CAST 0
+#define INCLUDE_STRUCT 1
+#define INCLUDE_REDIRECT 1
+#define INCLUDE_QUICKMEMCPY 1
+#define INCLUDE_PROFILER 1
+#define INCLUDE_BBC 0
+#define INCLUDE_STOREMAC 1
+#define INCLUDE_SHELLVARS 1
+#define INCLUDE_MALLOC 1
+#define INCLUDE_PORTCMD 0
+#define INCLUDE_SYSLOG 1
+#define INCLUDE_HWTMR 1
+#define INCLUDE_VERBOSEHELP 1
+#define INCLUDE_GDB 1
+#define INCLUDE_USRLVL 0
+#define INCLUDE_JFFS2 0
+#define INCLUDE_JFFS2ZLIB 0
+#define INCLUDE_FBI 1
+#define INCLUDE_TSI 1
+#define INCLUDE_SD 0
+#define INCLUDE_DNS 1
+
+/* Inclusion of this next file will make sure that all of the above
+ * inclusions are legal; and warn/adjust where necessary.
+ */
+#include "inc_check.h"
diff --git a/ports/csb740/cpu.h b/ports/csb740/cpu.h
new file mode 100755
index 0000000..ddedd7b
--- /dev/null
+++ b/ports/csb740/cpu.h
@@ -0,0 +1,25 @@
+/* cpu.h:
+ General notice:
+ This code is part of a boot-monitor package developed as a generic base
+ platform for embedded system designs. As such, it is likely to be
+ distributed to various projects beyond the control of the original
+ author. Please notify the author of any enhancements made or bugs found
+ so that all may benefit from the changes. In addition, notification back
+ to the author will allow the new user to pick up changes that may have
+ been made by other users after this version of the code was distributed.
+
+ Author: Ed Sutter
+ email: esutter@lucent.com
+ phone: 908-582-2351
+
+*/
+#include "omap3530.h"
+
+#define RESETMACRO() \
+{ \
+ WD2_REG(WD_WCRR) = 0xfffffff0; \
+ WD2_REG(WD_WSPR) = 0x0000bbbb; \
+ while(*(volatile unsigned long *)(WD2_BASE_ADD + WD_WWPS)); \
+ WD2_REG(WD_WSPR) = 0x00004444; \
+ while(1); \
+}
diff --git a/ports/csb740/cpu_gpio.h b/ports/csb740/cpu_gpio.h
new file mode 100755
index 0000000..cf071db
--- /dev/null
+++ b/ports/csb740/cpu_gpio.h
@@ -0,0 +1,113 @@
+
+//=============================================================================
+//
+// cpu_gpio.h
+//
+// CPU/Board Specific GPIO assignments
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Date: 05/12/2008
+// Description: This file contains the GPIOIO usage for the CSB733
+//
+//
+//=============================================================================
+
+// PORT 1 - Virtual GPIO Bits 0-31
+#define PORT1_VBIT 0
+// Signal Bit Dir Active Usage
+
+// Define initial direction (0 = output) and value
+#define PORT1_OE 0xFFFFFFFF
+// Define data value
+#define PORT1_DR 0
+
+// -----------------------------------------------------------------------------------------------
+// PORT 2
+#define PORT2_VBIT 32
+// Signal Bit Dir Active Usage
+#define N_RDY_BIT BIT30 // In High NAND Ready
+#define N_RDY PORT2_VBIT + 30
+#define LCD_BKL_BIT BIT26 // Out High LCD Backlight Enable
+#define LCD_BKL PORT2_VBIT + 26
+#define EXP_INT_BIT BIT25 // In Low Expansion Interrupt
+#define EXP_INT PORT2_VBIT + 25
+
+// Define initial direction (0 = output) and value
+#define PORT2_OE ~(LCD_BKL_BIT)
+// Define data value
+#define PORT2_DR (LCD_BKL_BIT)
+
+// -----------------------------------------------------------------------------------------------
+// PORT 3
+#define PORT3_VBIT 64
+
+// Signal Bit Dir Active Usage
+#define GPIO7_BIT BIT28 // In High Set as GPIO Input, pulled high. Shared with SPI1_CS1
+#define GPIO7 PORT3_VBIT + 28
+#define SPI3_CS0_BIT BIT27 // In High SPI3_CS0
+#define SPI3_CS0 PORT3_VBIT + 27
+#define E_INT_BIT BIT1 // In Low LAN9211 Interrupt
+#define E_INT PORT3_VBIT + 1
+
+// Define initial direction (0 = output) and value
+#define PORT3_OE ~(SPI3_CS0_BIT)
+// Define data value
+#define PORT3_DR SPI3_CS0_BIT
+
+// -----------------------------------------------------------------------------------------------
+// PORT 4
+#define PORT4_VBIT 96
+
+// Signal Bit Dir Active Usage
+#define PIRQ_BIT BIT31 // In Low Touch Interrupt from ADS7843
+#define PIRQ PORT4_VBIT + 31
+#define I2C_INT_BIT BIT30 // In Low I2C Interrupt
+#define I2C_INT PORT4_VBIT + 30
+
+// Define initial direction (0 = output) and value
+#define PORT4_OE 0xFFFFFFFF
+// Define data value
+#define PORT4_DR 0
+
+// -----------------------------------------------------------------------------------------------
+// PORT 5
+#define PORT5_VBIT 128
+
+// Signal Bit Dir Active Usage
+#define U_SEL_BIT BIT12 // Out N/A Selects between USB Host or Device
+#define U_SEL PORT5_VBIT + 12
+#define GPIO1_BIT BIT1 // In High Push button on CSB703
+#define GPIO1 PORT5_VBIT + 1
+#define GPIO0_BIT BIT0 // Out N/A LED on CSB703
+#define GPIO0 PORT5_VBIT + 0
+
+// Define initial direction (0 = output) and value
+#define PORT5_OE ~(U_SEL_BIT | GPIO0_BIT)
+// Define data value
+#define PORT5_DR (U_SEL_BIT | GPIO0_BIT)
+
+// -----------------------------------------------------------------------------------------------
+// PORT 6
+#define PORT6_VBIT 160
+
+// Signal Bit Dir Active Usage
+#define GPIO9_BIT BIT25 // In High Set as GPIO Input, pulled high.
+#define GPIO9 PORT6_VBIT + 25
+#define GPIO8_BIT BIT24 // In High Set as GPIO Input, pulled high.
+#define GPIO8 PORT6_VBIT + 24
+#define GPIO2_BIT BIT22 // In High Set as GPIO Input, pulled high.
+#define GPIO2 PORT6_VBIT + 22
+#define GPIO3_BIT BIT21 // In High Set as GPIO Input, pulled high.
+#define GPIO3 PORT6_VBIT + 21
+#define GPIO4_BIT BIT20 // In High Set as GPIO Input, pulled high.
+#define GPIO4 PORT6_VBIT + 20
+#define GPIO5_BIT BIT19 // In High Set as GPIO Input, pulled high.
+#define GPIO5 PORT6_VBIT + 19
+#define GPIO6_BIT BIT17 // In High Set as GPIO Input, pulled high.
+#define GPIO6 PORT6_VBIT + 17
+
+// Define initial direction (0 = output) and value
+#define PORT6_OE 0xFFFFFFFF
+// Define data value
+#define PORT6_DR 0
+
diff --git a/ports/csb740/cpu_i2c.c b/ports/csb740/cpu_i2c.c
new file mode 100755
index 0000000..53c3ebb
--- /dev/null
+++ b/ports/csb740/cpu_i2c.c
@@ -0,0 +1,322 @@
+//==========================================================================
+//
+// cpu_i2c.c
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 03/26/2003
+// Description: Generic IIC Routines - requires I2C_SCL and I2C_SDA to
+// be defined in cpu_gpio.h
+//
+//==========================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "cli.h"
+#include "cpu_gpio.h"
+#include "cpu_gpio.h"
+#include "umongpio.h"
+
+//--------------------------------------------------------------------------
+// function prototypes
+//
+ulong i2c_init(void);
+ulong i2c_wr_device(uchar dev, uchar reg, uchar data);
+ulong i2c_rd_device(uchar dev, uchar reg, uchar *data);
+ulong i2c_wr_byte(uchar data);
+uchar i2c_rd_byte(void);
+void i2c_start(void);
+void i2c_stop(void);
+int i2c(int argc,char *argv[]);
+
+extern void udelay(int delay);
+
+//--------------------------------------------------------------------------
+// I2C Macros
+//
+#define I2C_SCL_CLR GPIO_out(I2C_SCL)
+#define I2C_SCL_SET GPIO_in(I2C_SCL)
+
+#define I2C_SDA_CLR GPIO_out(I2C_SDA)
+#define I2C_SDA_SET GPIO_in(I2C_SDA)
+
+#define I2C_SCL_RD GPIO_tst(I2C_SCL)
+#define I2C_SDA_RD GPIO_tst(I2C_SDA)
+
+#define I2C_DELAY udelay(1000)
+
+//--------------------------------------------------------------------------
+// i2c_init()
+//
+// I2C is a shared bus. We drive a low by setting the SCL/SDA GPIO as
+// an output. We must preset a 0 in the GPIO output bit so the line will
+// go low whenever we make it an output. For a high, we make the GPIO an
+// input, thus letting the external pullup to pull the line high.
+//
+ulong i2c_init()
+{
+ GPIO_out(I2C_SCL);
+ GPIO_clr(I2C_SCL);
+ GPIO_in(I2C_SCL);
+
+ GPIO_out(I2C_SDA);
+ GPIO_clr(I2C_SDA);
+ GPIO_in(I2C_SDA);
+
+ return 0;
+
+}
+
+//--------------------------------------------------------------------------
+// i2c_wr_device()
+//
+// This function writes an 8-bit value to the I2C device at the requested
+// register.
+//
+ulong i2c_wr_device(uchar dev, uchar reg, uchar data)
+{
+
+ // issue a start command
+ i2c_start();
+
+ // write the 7-bit device address with write = 0
+ if(i2c_wr_byte((dev << 1) & 0xfe)){
+ return -1;
+ }
+ // Write the 8-bit register address
+ if(i2c_wr_byte(reg)){
+ return -1;
+ }
+ // Write the 8-bit data value
+ if(i2c_wr_byte(data)){
+ return -1;
+ }
+
+ // issue a stop
+ i2c_stop();
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_rd_device()
+//
+// This function reads an 8-bit value from the I2C device at the requested
+// register.
+//
+ulong i2c_rd_device(uchar dev, uchar reg, uchar *data)
+{
+
+ // issue a start command
+ i2c_start();
+
+ // write the 7-bit device address with write = 0
+ if(i2c_wr_byte((dev << 1) & 0xfe)){
+ return -1;
+ }
+ // Write the 8-bit register address
+ if(i2c_wr_byte(reg)){
+ return -1;
+ }
+ // repeat the start command
+ i2c_start();
+ // write the 7-bit device address again plus data direction (read = 1)
+ if(i2c_wr_byte((dev << 1) | 0x01)){
+ return -1;
+ }
+ *data = i2c_rd_byte();
+
+ // issue a stop
+ i2c_stop();
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_wr_byte()
+//
+// This function writes an 8-bit value to the I2C bus, MSB first.
+// Data is written by changing SDA during SCL low, then bringing
+// SCL high. SCL is returned low to setup for the next transition.
+//
+ulong i2c_wr_byte(uchar data)
+{
+
+ int i;
+
+ for (i = 0; i < 8; i++){
+ if (data & 0x80) {
+ // write a 1 bit
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ else {
+ // write a 0 bit
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ data = data << 1;
+ }
+ // Release SDA, bring SCL high, then read SDA.
+ // A low indicates an acknowledge.
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ if(I2C_SDA_RD){ // a high means no ack
+ // re-enable SDA for output
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ return -1;
+ }
+
+ I2C_SCL_CLR;
+ I2C_DELAY;
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_rd_byte()
+//
+// This function reads an 8-bit data value from the I2C bus, MSB first.
+// Data is read from SDA after each low to high SCL transition.
+//
+uchar i2c_rd_byte()
+{
+
+ int i;
+ uchar volatile data;
+
+ data = 0;
+
+ for (i = 0; i < 8; i++){
+ data = data << 1;
+ data = data & 0xfe;
+ // clock the data out of the slave
+ I2C_SCL_SET;
+ I2C_DELAY;
+ // check it
+ if (I2C_SDA_RD){
+ data = data | 0x01;
+ }
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ // generate an extra SCL transition
+ // The slave generates no acknowledge for reads.
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+
+ return data;
+}
+
+
+//--------------------------------------------------------------------------
+// i2c_start()
+//
+// This function issues an I2C start command which is a high to low
+// transition on SDA while SCL is high.
+//
+void i2c_start()
+{
+
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ I2C_SDA_SET;
+ I2C_DELAY;
+}
+
+//--------------------------------------------------------------------------
+// i2c_stop()
+//
+// This function issues an I2C stop command which is a low to high
+// transition on SDA while SCL is high.
+//
+void i2c_stop()
+{
+
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+}
+
+char *i2cHelp[] = {
+ " This command allows the user to read ",
+ " and write devices on the i2c bus. \n ",
+ " Usage:",
+ " i2c -[w] {device} {register} {val/count}",
+ " Options...",
+ " -w write val to device/register",
+ " no options, read from device/register up to count",
+ 0
+};
+
+int i2c(int argc,char *argv[])
+{
+ int i, opt;
+ int write = 0;
+ uchar dev, reg, data, count;
+
+ while ((opt=getopt(argc,argv,"w")) != -1) {
+ if (opt == 'w') write = 1;
+ }
+
+ // make sure we have the right number of paramters
+ if (argc < (optind+3))
+ return(CMD_PARAM_ERROR);
+
+ dev = (uchar) strtoul(argv[optind],(char **)0,0);
+ reg = (uchar) strtoul(argv[optind+1],(char **)0,0);
+
+ // 3rd arg is the data value if it's a write, count if it's a read
+ data = (uchar) strtoul(argv[optind+2],(char **)0,0);
+ count = data;
+ // do it
+ if (write)
+ {
+ printf("Writing 0x%02x to Device 0x%02x @ Register 0x%02x.\n", data, dev, reg);
+ if(i2c_wr_device(dev, reg, data))
+ {
+ printf("I2C Bus Failure - Check Paramters!\n");
+ return (CMD_FAILURE);
+ }
+ }
+ else
+ {
+ for (i = 0; i < count; i++)
+ {
+ printf("Read Device 0x%02x, Register 0x%02x = ", dev, reg + i);
+ if(i2c_rd_device(dev, reg + i, &data))
+ {
+ printf("I2C Bus Failure - Check Paramters!\n");
+ return (CMD_FAILURE);
+ }
+ printf("0x%02x.\n", data);
+ }
+ }
+ return(CMD_SUCCESS);
+}
+
diff --git a/ports/csb740/cpu_i2c.h b/ports/csb740/cpu_i2c.h
new file mode 100755
index 0000000..779ee67
--- /dev/null
+++ b/ports/csb740/cpu_i2c.h
@@ -0,0 +1,269 @@
+//==========================================================================
+//
+// cpu_i2c.c
+//
+// Author(s): Michael Kelly - Cogent Computer Systems, Inc.
+// Date: 03/30/2002
+// Description: CSB272 - 405GP Single Board IIC Routines
+//
+//==========================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+
+//--------------------------------------------------------------------------
+// some 405GP I2C register and bit defines
+//
+#define I2C_XCTL *(vulong *)(0xef60050f) // extended control register
+#define I2C_XCTL_SRST 0x01000000 // Soft Reset Bit - must be set
+ // to 1 to use direct control
+
+#define I2C_DCTL *(vulong *)(0xef600510) // direct control of IIC bits
+#define I2C_DCTL_SDA_OUT 0x08000000 // SDA Out, 0 = drive low, 1 = tri-state
+#define I2C_DCTL_SCL_OUT 0x04000000 // SCL Out, 0 = drive low, 1 = tri-state
+#define I2C_DCTL_SDA_IN 0x02000000 // SDA In, Direct Read
+#define I2C_DCTL_SCL_IN 0x01000000 // SCL In, Direct Read
+
+//--------------------------------------------------------------------------
+// Low level I2C Macros
+//
+#define I2C_SCL_CLR I2C_DCTL &= ~(I2C_DCTL_SCL_OUT)
+#define I2C_SCL_SET I2C_DCTL |= (I2C_DCTL_SCL_OUT)
+
+#define I2C_SDA_CLR I2C_DCTL &= ~(I2C_DCTL_SDA_OUT)
+#define I2C_SDA_SET I2C_DCTL |= (I2C_DCTL_SDA_OUT)
+
+#define I2C_SDA_RD I2C_DCTL & I2C_DCTL_SDA_IN
+#define I2C_SCL_RD I2C_DCTL & I2C_DCTL_SCL_IN
+
+#define I2C_DELAY udelay(100)
+
+//--------------------------------------------------------------------------
+// function prototypes
+//
+ulong i2c_init(void);
+ulong i2c_wr_device(uchar dev, uchar reg, uchar data);
+ulong i2c_rd_device(uchar dev, uchar reg, uchar *data);
+ulong i2c_wr_byte(uchar data);
+uchar i2c_rd_byte(void);
+void i2c_start(void);
+void i2c_stop(void);
+
+extern void udelay(int delay);
+
+extern ulong sed_disp_mode;
+
+//--------------------------------------------------------------------------
+// i2c_init()
+//
+// Initialize the I2C registers for direct I2C control
+ulong i2c_init()
+{
+ // place the automatic I2C logic in reset
+ I2C_XCTL |= I2C_XCTL_SRST;
+
+ // Set the SCL and SDA outputs into tristate
+ I2C_DCTL |= (I2C_DCTL_SDA_OUT | I2C_DCTL_SCL_OUT);
+
+ return 0;
+
+}
+
+//--------------------------------------------------------------------------
+// i2c_wr_device()
+//
+// This function writes an 8-bit value to the I2C device at the requested
+// register.
+//
+ulong i2c_wr_device(uchar dev, uchar reg, uchar data)
+{
+
+ // issue a start command
+ i2c_start();
+
+ // write the 7-bit device address with write = 0
+ if(i2c_wr_byte((dev << 1) & 0xfe)){
+ return -1;
+ }
+ // Write the 8-bit register address
+ if(i2c_wr_byte(reg)){
+ return -1;
+ }
+ // Write the 8-bit data value
+ if(i2c_wr_byte(data)){
+ return -1;
+ }
+
+ // issue a stop
+ i2c_stop();
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_rd_device()
+//
+// This function reads an 8-bit value from the I2C device at the requested
+// register.
+//
+ulong i2c_rd_device(uchar dev, uchar reg, uchar *data)
+{
+
+ // issue a start command
+ i2c_start();
+
+ // write the 7-bit device address with write = 0
+ if(i2c_wr_byte((dev << 1) & 0xfe)){
+ return -1;
+ }
+ // Write the 8-bit register address
+ if(i2c_wr_byte(reg)){
+ return -1;
+ }
+ // repeat the start command
+ i2c_start();
+ // write the 7-bit device address again plus data direction (read = 1)
+ if(i2c_wr_byte((dev << 1) | 0x01)){
+ return -1;
+ }
+ *data = i2c_rd_byte();
+
+ // issue a stop
+ i2c_stop();
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_wr_byte()
+//
+// This function writes an 8-bit value to the I2C bus, MSB first.
+// Data is written by changing SDA during SCL low, then bringing
+// SCL high. SCL is returned low to setup for the next transition.
+//
+ulong i2c_wr_byte(uchar data)
+{
+
+ int i;
+
+ for (i = 0; i < 8; i++){
+ if (data & 0x80) {
+ // write a 1 bit
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ else {
+ // write a 0 bit
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ data = data << 1;
+ }
+ // Release SDA, bring SCL high, then read SDA.
+ // A low indicates an acknowledge.
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ if(I2C_SDA_RD){ // a high means no ack
+ // re-enable SDA for output
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ return -1;
+ }
+
+ I2C_SCL_CLR;
+ I2C_DELAY;
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------
+// i2c_rd_byte()
+//
+// This function reads an 8-bit data value from the I2C bus, MSB first.
+// Data is read from SDA after each low to high SCL transition.
+//
+uchar i2c_rd_byte()
+{
+
+ int i;
+ uchar volatile data;
+
+ data = 0;
+
+ for (i = 0; i < 8; i++){
+ data = data << 1;
+ data = data & 0xfe;
+ // clock the data out of the slave
+ I2C_SCL_SET;
+ I2C_DELAY;
+ // check it
+ if (I2C_SDA_RD){
+ data = data | 0x01;
+ }
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ }
+ // generate an extra SCL transition
+ // The slave generates no acknowledge for reads.
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+
+ return data;
+}
+
+
+//--------------------------------------------------------------------------
+// i2c_start()
+//
+// This function issues an I2C start command which is a high to low
+// transition on SDA while SCL is high.
+//
+void i2c_start()
+{
+
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+ I2C_SDA_SET;
+ I2C_DELAY;
+}
+
+//--------------------------------------------------------------------------
+// i2c_stop()
+//
+// This function issues an I2C stop command which is a low to high
+// transition on SDA while SCL is high.
+//
+void i2c_stop()
+{
+
+ I2C_SDA_CLR;
+ I2C_DELAY;
+ I2C_SCL_SET;
+ I2C_DELAY;
+ I2C_SDA_SET;
+ I2C_DELAY;
+ I2C_SCL_CLR;
+ I2C_DELAY;
+}
+
+
diff --git a/ports/csb740/cpuio.c b/ports/csb740/cpuio.c
new file mode 100755
index 0000000..0a9a262
--- /dev/null
+++ b/ports/csb740/cpuio.c
@@ -0,0 +1,313 @@
+//=============================================================================
+//
+// cpuio.c
+//
+// CPU/Board Specific IO
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Date: 12/04/2008
+// Description: This file contains the IO functions required by Micro Monitor
+// that are unique to the CSB740
+//
+//
+//=============================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "ether.h"
+#include "stddefs.h"
+#include "warmstart.h"
+#include "omap3530.h"
+#include "omap3530_mem.h"
+#include "cpu_gpio.h"
+#include "fb_draw.h"
+#include "uart16550.h"
+#include "umongpio.h"
+#include "ad7843.h"
+
+#define __raw_readl(a) (*(volatile unsigned int *)(a))
+
+extern ulong i2c_init(void);
+extern ulong getpsr(void);
+extern void putpsr(ulong);
+
+uchar bcolor=0; // vga black
+
+/******************************************************
+// Delay for some usecs. - Not accurate, assumes ROM mode
+// and no Cache
+ ******************************************************/
+void udelay(int delay)
+{
+ volatile int i;
+ for ( i = LOOPS_PER_USEC * delay; i ; i--);
+}
+
+/******************************************************
+ * Routine: wait_for_command_complete
+ * Description: Wait for posting to finish on watchdog
+ ******************************************************/
+void wait_for_command_complete(unsigned int wd_base)
+{
+ int pending = 1;
+ do {
+ pending = __raw_readl(wd_base + WD_WWPS);
+ } while (pending);
+}
+
+/******************************************************
+// getUARTDivisor is called from UART16550.c
+ ******************************************************/
+int
+getUartDivisor(int baud, unsigned char *hi, unsigned char *lo)
+{
+ *lo = ((48000000/16)/baud) & 0x00ff;
+ *hi = (((48000000/16)/baud) & 0xff00) >> 8;
+ return(0);
+}
+
+/******************************************************
+// Set pads (pins) to correct mode. Refer to section 7.4.4
+ in TI omap35xx_tech_ref_manual for bit defines.
+ ******************************************************/
+void pads_init()
+{
+ // Set up chip selects
+ SCM_REG(PADCONFS_GPMC_NCS3) = 0x00180018; // NCS3[15:0], NCS4[31:16]
+ SCM_REG(PADCONFS_GPMC_NCS5) = 0x011C0018; // NCS5[15:0], EXP_INTX[31:16]
+
+ // Set LCD_BKL_X to output, pullup enabled, mode 4
+ // Set LCLK to output, no pull-type and disabled, mode 0
+ SCM_REG(PADCONFS_GPMC_NCS7) = 0x0000001C; // LCD_BKL_X[15:0], LCLK(or GPIO_59)[31:16]
+
+ // Set LCD pads to outputs, pull-type = up, pullud disabled, mode 0
+ SCM_REG(PADCONFS_DSS_PCLK) = 0x00100010; // LCD_PCLK_X[15:0], LCD_HS_X[31:16]
+ SCM_REG(PADCONFS_DSS_VSYNC) = 0x00100010; // LCD_VS_X[15:0], LCD_OE_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA0) = 0x00100010; // LCD_B0_X[15:0], LCD_B1_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA2) = 0x00100010; // LCD_B2_X[15:0], LCD_B3_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA4) = 0x00100010; // LCD_B4_X[15:0], LCD_B5_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA6) = 0x00100010; // LCD_G0_X[15:0], LCD_G1_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA8) = 0x00100010; // LCD_G2_X[15:0], LCD_G3_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA10) = 0x00100010; // LCD_G4_X[15:0], LCD_G5_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA12) = 0x00100010; // LCD_R0_X[15:0], LCD_R1_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA14) = 0x00100010; // LCD_R2_X[15:0], LCD_R3_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA16) = 0x00100010; // LCD_R4_X[15:0], LCD_R5_X[31:16]
+
+ // Set D_TXD for output and D_RXD for input. Set both to pullup enabled and mode 1
+ SCM_REG(PADCONFS_MCBSP3_CLKX) = 0x01190019; // D_TXD[15:0], D_RXD[31:16]
+
+#ifdef AD7843_GPIOMODE
+ // Depending on AD7843_GPIOMODE setting, we either configure the SPI
+ // interface to the AD7843 as a real SPI device using the OMAP's SPI
+ // controller, or we set it up with GPIO bits...
+ SCM_REG(PADCONFS_DSS_DATA18) = 0x00040004;
+ SCM_REG(PADCONFS_DSS_DATA20) = 0x00040104;
+#else
+ SCM_REG(PADCONFS_DSS_DATA18) = 0x0002011A; // SPI1_CLK_X[15:0], SPI1_MOSI_X[31:16]
+ SCM_REG(PADCONFS_DSS_DATA20) = 0x001A011A; // SPI1_MISO_X[15:0], *SPI1_CS0_X[31:16]
+#endif
+
+ // Set PIRQ for ADS7843 touch interrupt. Set both to pullup enabled and mode 4
+ SCM_REG(PADCONFS_MMC1_DAT4) = 0x01040104; // *I2C_INT_X[15:0], *PIRQ_X[31:16]
+
+ // GPIO1 is the push button on CSB703(set as input), GPIO0 is is LED on CSB703(set as output)
+ SCM_REG(PADCONFS_MMC1_DAT6) = 0x01040004; // GPIO0_X[15:0], GPIO1_X[31:16]
+
+ // Set E_INT* to be an input in GPIO mode
+ SCM_REG(PADCONFS_GPMC_WAIT2) = 0x011C011f; // NA[15:0], E_INTX[31:16]
+
+ // Set SYS_CLKOUT1 for USB_CLK
+ SCM_REG(PADCONFS_SYS_OFF_MODE) = 0x0000010f; // OFF_MODE_X[15:0], SYS_CLKOUT1[31:16]
+
+ // Set SYS_CLKOUT2 for debug purposes
+ SCM_REG(PADCONFS_SYS_NIRQ) = 0x0000011f; // FIQ[15:0], SYS_CLK2[31:16]
+
+}
+
+int
+devInit(int baud)
+{
+ // Initialize pads
+ pads_init();
+
+ // Disable MPU Watchdog WDT2
+ WD2_REG(WD_WSPR) = 0x0000aaaa;
+ wait_for_command_complete(WD2_BASE_ADD);
+ WD2_REG(WD_WSPR) = 0x00005555;
+
+ // Initialize GPIO
+ GPIO_init();
+
+ // Setup UART pins to UART mode before calling InitUART from uart16550.c
+ UART2_REG(UART_MDR1) = 0x0000;
+ // Initialize the UART
+ InitUART(baud);
+
+ // Setup CS0 for 110ns Spansion Flash
+ GPMC_REG(GPMC_CS0_CONFIG7) = 0x00000c48; // Base addr 0x08000000, 64M
+ GPMC_REG(GPMC_CS0_CONFIG1) = 0x00001210;
+ //GPMC_REG(GPMC_CS0_CONFIG5) = 0x00080808; // Config5
+
+ // Setup CS4 for LAN9211, on the CSB740 it is refered to as CS2
+ // and mapped to E_CS
+ GPMC_REG(GPMC_CS4_CONFIG7) = 0x00000F6C; // Base addr 0x2C000000, 16M
+ GPMC_REG(GPMC_CS4_CONFIG1) = 0x00001200;
+
+ return 0;
+}
+
+/* Referring to table 25-10 of the TRM, install
+ * the RAM exception vectors...
+ */
+void
+ram_vector_install(void)
+{
+ extern unsigned long abort_data;
+ extern unsigned long abort_prefetch;
+ extern unsigned long undefined_instruction;
+ extern unsigned long software_interrupt;
+ extern unsigned long interrupt_request;
+ extern unsigned long fast_interrupt_request;
+ extern unsigned long not_assigned;
+
+ *(ulong **)0x4020ffe4 = &undefined_instruction;
+ *(ulong **)0x4020ffe8 = &software_interrupt;
+ *(ulong **)0x4020ffec = &abort_prefetch;
+ *(ulong **)0x4020fff0 = &abort_data;
+ *(ulong **)0x4020fff4 = &not_assigned;
+ *(ulong **)0x4020fff8 = &interrupt_request;
+ *(ulong **)0x4020fffc = &fast_interrupt_request;
+}
+
+void
+initCPUio()
+{
+ volatile unsigned register cntens;
+ volatile unsigned register usren;
+ volatile unsigned register pmnc;
+
+ ram_vector_install();
+
+ /* Do this stuff to enable the cycle counter
+ * (for use by target_timer)...
+ */
+ /* Allow user mode to have access to performance monitor registers:
+ */
+ asm volatile (" MRC p15, 0, %0, c9, c14, 0" : "=r" (usren));
+ usren |= 1;
+ asm volatile (" MCR p15, 0, %0, c9, c14, 0" : : "r" (usren));
+
+ /* Enable all counters, and reset Cycle counter...
+ */
+ asm volatile (" MRC p15, 0, %0, c9, c12, 0" : "=r" (pmnc));
+ pmnc |= 5;
+ asm volatile (" MCR p15, 0, %0, c9, c12, 0" : : "r" (pmnc));
+
+ /* Enable all performance counter registers...
+ */
+ asm volatile (" MRC p15, 0, %0, c9, c12, 1" : "=r" (cntens));
+ cntens |= 0x8000000f;
+ asm volatile (" MCR p15, 0, %0, c9, c12, 1" : : "r" (cntens));
+}
+
+/* target_reset():
+ * Set the counter to 16 ticks before trigger, then enable the
+ * watchdog timer (WDT2) and wait...
+ */
+void
+target_reset(void)
+{
+ // Preload the count-up register...
+ WD2_REG(WD_WCRR) = 0xfffffff0;
+
+ // Start MPU Watchdog WDT2
+ WD2_REG(WD_WSPR) = 0x0000bbbb;
+ wait_for_command_complete(WD2_BASE_ADD);
+ WD2_REG(WD_WSPR) = 0x00004444;
+
+ // Now just wait...
+ while(1);
+}
+
+void
+intsrestore(psr)
+ulong psr;
+{
+ putpsr(psr);
+}
+
+/*
+ * Read the program status register (CPSR)
+ * and set the FIQ and IRQ bits.
+ */
+ulong
+intsoff(void)
+{
+ ulong psr;
+
+ psr = getpsr();
+
+ /*
+ * Set bit 6, bit 7 to disable interrupts.
+ */
+ putpsr(psr | 0x000000c0);
+ return(psr);
+}
+
+/* show_revision():
+ * Called when the system banner is printed...
+ */
+void
+show_revision(int center)
+{
+ int (*pfunc)(char *, ...);
+ volatile unsigned register main_id;
+ volatile unsigned register silicon_id;
+
+ if (center)
+ pfunc = cprintf;
+ else
+ pfunc = printf;
+
+ asm(" MRC p15, 0, %0, c0, c0, 0" : "=r" (main_id));
+ asm(" MRC p15, 1, %0, c0, c0, 7" : "=r" (silicon_id));
+
+ pfunc("Silicon ID: %d.%d\n",
+ ((silicon_id & 0xf0)>>4),(silicon_id & 0xf));
+
+ pfunc("CPU Rev: %d, Variant: %d\n",
+ main_id & 0xf,(main_id & 0x00f00000) >> 20);
+
+ pfunc("CM Rev: %d.%d, PRM Rev: %d.%d\n",
+ CM_REV_MAJ(),CM_REV_MIN(),PRM_REV_MAJ(),PRM_REV_MIN());
+}
+
+/* target_timer():
+ * Used in conjunction with INCLUDE_HWTMR and TIMER_TICKS_PER_MSEC
+ * to set up a hardware based time base.
+ */
+unsigned long
+target_timer(void)
+{
+ volatile unsigned register ccr;
+
+ asm(" MRC p15, 0, %0, c9, c13, 0" : "=r" (ccr));
+
+ return(ccr);
+}
+
+/* cacheInitForTarget():
+ Enable instruction cache only...
+*/
+void
+cacheInitForTarget()
+{
+ asm(" MRC p15, 0, r0, c1, c0, 0");
+ asm(" ORR r0, r0, #0x1000"); /* bit 12 is ICACHE enable*/
+ asm(" MCR p15, 0, r0, c1, c0, 0");
+
+ /* Flush instruction cache */
+ asm(" MCR p15, 0, r0, c7, c5, 0");
+}
+
diff --git a/ports/csb740/cpuio.h b/ports/csb740/cpuio.h
new file mode 100755
index 0000000..64ff49c
--- /dev/null
+++ b/ports/csb740/cpuio.h
@@ -0,0 +1,76 @@
+//=============================================================================
+//
+// cpuio.h
+//
+// CPU/Board Specific IO
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Date: 05-16-2008
+// Description: This file contains the IO functions required by Micro Monitor
+// that are unique to each CPU/Board combination
+//
+//
+// cpuio.h for the CSB740 OMAP3530 Cortex-A8
+//
+//=============================================================================
+
+// board specific defines for micro monitor
+#define DEFAULT_BAUD_RATE 38400
+#define MON_CPU_CLOCK 400000000
+
+#define LOOPS_PER_USEC 5
+
+#define BASE_OF_NAND 0x1000
+#define SIZE_OF_NAND 0x100000
+
+// SMSC LAN9211 Ethernet
+#define SMSC911X_BASE_ADDRESS 0x2C000000 // CS4 on OMAP3530 but we call it CS2
+
+// LCD Defines
+//
+// The LCD frame buffer is fixed at 0x80200000, which is 2Mbyte from the
+// beginning of SDRAM space. Note that we access it 16-bits at a time.
+
+#define LCD_BUF_ADD 0x80200000
+#define LCD_BUF(_x_) *(vushort *)(LCD_BUF_ADD + _x_) // Frame Buffer
+#define USE_FONT8X8
+#define LCD_GET_PIXEL_ADD(_X_, _Y_) (((_Y_ * PIXELS_PER_ROW) + _X_)*2)
+
+// defines for the display geometry - OSD043TN24 480x272 TFT
+// (some of these defines are also used by uMon's frame buffer interface)
+#define PIXELS_PER_ROW 480 //
+#define PIXELS_PER_COL 272 //
+#define BITS_PER_PIXEL 16 //
+#define PIXFMT_IS_RGB565 1
+#define FBDEV_SETSTART fbdev_setstart
+#define FRAME_BUFFER_BASE_ADDR LCD_BUF_ADD
+#define LCD_H_WIDTH 41 // pulse width in pixels
+#define LCD_H_FRONT 2 // front porch (sync to enable)
+#define LCD_H_BACK 2 // back porch (enable to sync)
+#define LCD_V_WIDTH 10 // pulse width in lines
+#define LCD_V_FRONT 2 // front porch (sync to enable)
+#define LCD_V_BACK 2 // back porch (enable to sync)
+//#define LCD_PCD 2 // LCD PERCLK3 = 32Mhz/PCD +1 = Pixel Clock ~ 4Mhz
+
+#define TOP 1
+#define BOTTOM (PIXELS_PER_COL-1)
+#define LEFT 0
+#define RIGHT (PIXELS_PER_ROW-1)
+#define CENTER_X (PIXELS_PER_ROW/2)
+#define CENTER_Y (PIXELS_PER_COL/2)
+
+#define ROWS_PER_SCREEN 17
+#define COLS_PER_SCREEN 60
+
+#define LCD_BG_DEF 9
+#define LCD_FG_DEF 15
+
+#define LCD_FB_SIZE(_depth_) (((PIXELS_PER_COL * PIXELS_PER_ROW) * _depth_) / 8)
+
+#define LCD_ROW_SIZE(_depth_) ((PIXELS_PER_ROW * _depth_) / 8)
+
+#define LCD_GET_ADD(_row_, _col_, _depth_) (((((_row_ * PIXELS_PER_ROW) * FONT_HEIGHT) \
+ + (_col_ * FONT_WIDTH)) \
+ * _depth_) / 8)
+
+
diff --git a/ports/csb740/etherdev.c b/ports/csb740/etherdev.c
new file mode 100755
index 0000000..690d21b
--- /dev/null
+++ b/ports/csb740/etherdev.c
@@ -0,0 +1,241 @@
+//=============================================================================
+//
+// etherdev.c
+//
+// Ethernet Abstraction Layer for Micro Monitor
+//
+// Author(s): Michael Kelly, Cogent Computer Systems, Inc.
+// Contributors: Luis Torrico, Cogent Computer Systems, Inc.
+// Date: 05-26-2002
+// Modified: 06-26-2007
+// Description: This file contains the interface layer between Micro Monitor
+// and the Ethernet driver for the LAN921x on the CSB733.
+//
+//=============================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "ether.h"
+
+extern void smsc911x_reset(void);
+extern ushort smsc911x_rx(uchar *pktbuf);
+extern int smsc911x_init(void);
+extern ulong smsc911x_tx(ulong txbuf, ulong length);
+extern void smsc911x_enable_promiscuous_reception(void);
+extern void smsc911x_disable_promiscuous_reception(void);
+extern void smsc911x_enable_multicast_reception(void);
+extern void smsc911x_disable_multicast_reception(void);
+extern void smsc911x_enable_broadcast_reception(void);
+extern void smsc911x_disable_broadcast_reception(void);
+
+ulong tx_buf[400];
+
+#if INCLUDE_ETHERNET
+
+/*
+ * enreset():
+ * Reset the PHY and MAC.
+ */
+void
+enreset(void)
+{
+ smsc911x_reset();
+}
+
+/*
+ * eninit():
+ * This would include establishing buffer descriptor tables and
+ * all the support code that will be used by the ethernet device.
+ *
+ * It can be assumed at this point that the array uchar BinEnetAddr[6]
+ * contains the 6-byte MAC address.
+ *
+ * Return 0 if successful; else -1.
+ */
+int
+eninit(void)
+{
+ return smsc911x_init();
+
+}
+
+int
+EtherdevStartup(int verbose)
+{
+ /* Initialize local device error counts (if any) here. */
+ /* OPT_ADD_CODE_HERE */
+
+ /* Put ethernet controller in reset: */
+ enreset();
+
+ /* Initialize controller: */
+ eninit();
+
+ return(0);
+}
+
+/* disablePromiscuousReception():
+ * Provide the code that disables promiscuous reception.
+ */
+void
+disablePromiscuousReception(void)
+{
+ smsc911x_disable_promiscuous_reception();
+}
+
+/* enablePromiscuousReception():
+ * Provide the code that enables promiscuous reception.
+ */
+void
+enablePromiscuousReception(void)
+{
+ smsc911x_enable_promiscuous_reception();
+}
+
+/* disableBroadcastReception():
+ * Provide the code that disables broadcast reception.
+ */
+void
+disableBroadcastReception(void)
+{
+ smsc911x_disable_broadcast_reception();
+}
+
+/* enableBroadcastReception():
+ * Provide the code that enables broadcast reception.
+ */
+void
+enableBroadcastReception(void)
+{
+ smsc911x_enable_broadcast_reception();
+}
+
+void
+disableMulticastReception(void)
+{
+ smsc911x_disable_multicast_reception();
+}
+
+void
+enableMulticastReception(void)
+{
+ smsc911x_enable_multicast_reception();
+}
+
+
+/*
+ * enselftest():
+ * Run a self test of the ethernet device(s). This can be stubbed
+ * with a return(1).
+ * Return 1 if success; else -1 if failure.
+ */
+int
+enselftest(int verbose)
+{
+ return(1);
+}
+
+/* ShowEtherdevStats():
+ * This function is used to display device-specific stats (error counts
+ * usually).
+ */
+void
+ShowEtherdevStats(void)
+{
+ /* OPT_ADD_CODE_HERE */
+}
+
+/* getXmitBuffer():
+ * Return a pointer to the buffer that is to be used for transmission of
+ * the next packet. Since the monitor's driver is EXTREMELY basic,
+ * there will only be one packet ever being transmitted. No need to queue
+ * up transmit packets.
+ */
+uchar *
+getXmitBuffer(void)
+{
+ return((uchar *) tx_buf);
+}
+
+/* sendBuffer():
+ * Send out the packet assumed to be built in the buffer returned by the
+ * previous call to getXmitBuffer() above.
+ */
+int
+sendBuffer(int length)
+{
+ ulong temp32;
+
+ if (length < 64)
+ length = 64;
+
+ if (EtherVerbose & SHOW_OUTGOING)
+ printPkt((struct ether_header *)tx_buf,length,ETHER_OUTGOING);
+
+ // tell the cs8900a to send the tx buffer pointed to by tx_buf
+ temp32 = smsc911x_tx((ulong)tx_buf, (ulong)length);
+
+ EtherXFRAMECnt++;
+ if (temp32) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* DisableEtherdev():
+ * Fine as it is...
+ */
+void
+DisableEtherdev(void)
+{
+ enreset();
+}
+
+/* extGetIpAdd():
+ * If there was some external mechanism (other than just using the
+ * IPADD shell variable established in the monrc file) for retrieval of
+ * the board's IP address, then do it here...
+ */
+char *
+extGetIpAdd(void)
+{
+ return((char *)0);
+}
+
+/* extGetEtherAdd():
+ * If there was some external mechanism (other than just using the
+ * ETHERADD shell variable established in the monrc file) for retrieval of
+ * the board's MAC address, then do it here...
+ */
+char *
+extGetEtherAdd(void)
+{
+ return((char *)0);
+}
+
+/*
+ * polletherdev():
+ * Called continuously by the monitor (ethernet.c) to determine if there
+ * is any incoming ethernet packets.
+ */
+int
+polletherdev(void)
+{
+ ulong pktbuf[RBUFSIZE/4];
+ int pktlen, pktcnt = 0;
+
+ pktlen = smsc911x_rx((uchar *)pktbuf);
+
+ if(pktlen) {
+ pktcnt = 1;
+ EtherRFRAMECnt++;
+ processPACKET((struct ether_header *)pktbuf, pktlen);
+ }
+ return(pktcnt);
+}
+
+#endif
diff --git a/ports/csb740/fbidemo b/ports/csb740/fbidemo
new file mode 100755
index 0000000..1a9e21c
--- /dev/null
+++ b/ports/csb740/fbidemo
@@ -0,0 +1,163 @@
+# This is a useful demo script to show off some of the functionality
+# of uMon's FBI interface...
+# It expects to find two files: fb/splash.bin and fb/umon1 that are
+# assumed to be two frame-buffer formatted images.
+#
+echo "Image file \#1: \c"
+read IMAGEFILE1
+echo "Image file \#2: \c"
+read IMAGEFILE2
+set FBICOLOR 0x005500
+
+fbi font 0 1 1 0xf0f0f0 0x101010
+fbi consolemode off
+fbi fill $IMAGEFILE1
+sleep 2
+
+fbi -t1 color $FBICOLOR
+fbi font 0 4 4 -- transparent
+fbi -o 1,0 print "MicroMonitor"
+fbi font 0 2 2 -- --
+fbi -o 7,3 print "(aka uMon)"
+fbi -o 2,5 print "FBI:"
+fbi -o 2,6 print "Frame Buffer Interface"
+fbi -o 2,7 print "***** Demo *****"
+sleep 2
+
+fbi -t2 color $FBICOLOR
+fbi font 0 1 1 -- --
+fbi -o 5,1 print "print small"
+sleep 1
+fbi font 0 3 3 -- --
+fbi -o 5,1 print "or..."
+sleep 1
+fbi font 0 7 7 -- --
+fbi -o 1,1 print "large"
+sleep 2
+
+fbi -t3 color $FBICOLOR
+fbi font 0 2 4 -- --
+sleep 1
+fbi -o 8,1 print "Independent"
+fbi -o 8,2 print " x & y"
+fbi -o 8,3 print "dimensions..."
+sleep 1
+
+fbi -t1 color $FBICOLOR
+fbi font 0 5 1 -- --
+fbi -o 1,1 print "print wide"
+sleep 1
+fbi font 0 3 3 -- --
+fbi -o 3,3 print "or..."
+sleep 1
+fbi font 0 2 18 -- --
+fbi -o 15,0 print "tall"
+sleep 2
+
+fbi -t2 color $FBICOLOR
+fbi font 0 3 3 -- --
+fbi -o 3,2 print "or"
+sleep 1
+fbi -o 3,4 print "mix it up..."
+sleep 1
+
+fbi -t3 color $FBICOLOR
+fbi font 0 1 1 -- --
+fbi -o 0,1 print 1
+fbi font 0 1 2 -- --
+fbi print 2
+fbi font 0 1 3 -- --
+fbi print 3
+fbi font 0 1 4 -- --
+fbi print 4
+fbi font 0 1 5 -- --
+fbi print 5
+fbi font 0 1 6 -- --
+fbi print 6
+fbi font 0 1 7 -- --
+fbi print 7
+fbi font 0 1 8 -- --
+fbi print 8
+fbi font 0 1 9 -- --
+fbi print 9
+fbi font 0 2 9 -- --
+fbi -o 5,1 print 0
+fbi font 0 2 8 -- --
+fbi -o 6,1 print 9
+fbi font 0 3 7 -- --
+fbi -o 5,1 print 8
+fbi font 0 4 6 -- --
+fbi -o 5,1 print 7
+fbi font 0 5 5 -- --
+fbi -o 5,1 print 6
+fbi font 0 6 4 -- --
+fbi -o 5,1 print 5
+fbi font 0 7 3 -- --
+fbi -o 5,1 print 4
+fbi font 0 8 2 -- --
+fbi -o 5,1 print 3
+fbi font 0 9 1 -- --
+fbi -o 5,1 print 2
+fbi font 0 10 1 -- --
+fbi -o 5,0 print 1
+sleep 4
+
+fbi -t1 color $FBICOLOR
+fbi font 0 3 3 -- --
+fbi -o 3,1 print "or"
+sleep 1
+fbi -o 3,3 print "console mode..."
+fbi -o 3,4 print "(normal font)"
+sleep 2
+
+fbi font 0 1 1 -- --
+fbi consolemode on
+echo uMON\>
+sleep 1
+tfs ls
+echo uMON\>
+sleep 1
+tfs cat monrc
+echo uMON\>
+sleep 1
+fbi consolemode off
+
+fbi -t2 color $FBICOLOR
+fbi font 0 3 3 -- --
+fbi consolemode on
+fbi -o 3,1 print "or"
+sleep 1
+fbi -o 3,3 print "console mode..."
+fbi -o 3,4 print "(taller font)"
+sleep 2
+fbi consolemode off
+
+fbi font 0 1 2 -- --
+fbi consolemode on
+echo uMON\>
+sleep 1
+tfs ls
+echo uMON\>
+sleep 1
+tfs cat monrc
+echo uMON\>
+sleep 1
+fbi font 0 1 1 -- --
+fbi consolemode off
+
+
+# SPLASHLOOPINIT:
+set TTYPE 1
+
+# SPLASHLOOP:
+if $TTYPE gt 3 goto SPLASHLOOPINIT
+if -tgc exit
+fbi -t $TTYPE fill $IMAGEFILE1
+if -tgc exit
+sleep 2
+if -tgc exit
+fbi -t $TTYPE fill $IMAGEFILE2
+set TTYPE=$TTYPE+1
+sleep 2
+if -tgc exit
+goto SPLASHLOOP
diff --git a/ports/csb740/font8x16.h b/ports/csb740/font8x16.h
new file mode 100755
index 0000000..808c9e4
--- /dev/null
+++ b/ports/csb740/font8x16.h
@@ -0,0 +1,3679 @@
+//------------------------------------------------------------------------
+// font8x16.h
+//
+// Simple 8 x 16 font printable characters only. To lookoup, subtract
+// FIRST_CHAR from the character, multiply x FONT_HEIGHT and get the next
+// FONT_WIDTH bytes.
+//
+// 10.03.2003 : added font8x16 def.
+
+#define FONT_WIDTH 8
+#define FONT_HEIGHT 16
+#define FIRST_CHAR 0x20
+#define LAST_CHAR 0x7f
+#define CURSOR_ON 0x7F
+#define CURSOR_OFF 0x20
+
+#if 0
+const uchar fonttbl[] = {
+/* 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 */
+/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x21 ! */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* 0x22 " */ 0x00, 0x00, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x23 # */ 0x00, 0x00, 0x00, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00,
+/* 0x24 $ */ 0x00, 0x10, 0x10, 0x7c, 0x92, 0x90, 0x90, 0x7c, 0x12, 0x12, 0x92, 0x7c, 0x10, 0x10, 0x00, 0x00,
+/* 0x25 % */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x94, 0x68, 0x10, 0x2c, 0x52, 0x8c, 0x00, 0x00, 0x00, 0x00,
+/* 0x26 & */ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x56, 0x8c, 0x88, 0x8c, 0x76, 0x00, 0x00, 0x00, 0x00,
+/* 0x27 ' */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x28 ( */ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+/* 0x29 ) */ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00,
+/* 0x2a * */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0xfe, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2b + */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2c , */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+/* 0x2d - */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2e . */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+/* 0x2f / */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x30 0 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x31 1 */ 0x00, 0x00, 0x00, 0x08, 0x18, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+/* 0x32 2 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* 0x33 3 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x34 4 */ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+/* 0x35 5 */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x36 6 */ 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x37 7 */ 0x00, 0x00, 0x00, 0x7e, 0x42, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 0x38 8 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x39 9 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,
+/* 0x3a : */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3b ; */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00,
+/* 0x3c < */ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
+/* 0x3d = */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3e > */ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+/* 0x3f ? */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+/* 0x40 @ */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x4e, 0x52, 0x52, 0x4e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x41 A */ 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x42 B */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0x43 C */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x44 D */ 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00,
+/* 0x45 E */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* 0x46 F */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+/* 0x47 G */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00,
+/* 0x48 H */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x49 I */ 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+/* 0x4a J */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x4b K */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x4c L */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* 0x4d M */ 0x00, 0x00, 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00,
+/* 0x4e N */ 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x4f O */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x50 P */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+/* 0x51 Q */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x4a, 0x3c, 0x04, 0x06, 0x00, 0x00,
+/* 0x52 R */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x53 S */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x20, 0x18, 0x04, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x54 T */ 0x00, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 0x55 U */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x56 V */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00,
+/* 0x57 W */ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00,
+/* 0x58 X */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x59 Y */ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x44, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 0x5a Z */ 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* 0x5b [ */ 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x5c \ */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5d ] */ 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x5e ^ */ 0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5f _ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+/* 0x60 ` */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x61 a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+/* 0x62 b */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+/* 0x63 c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x64 d */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+/* 0x65 e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x66 f */ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+/* 0x67 g */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x42, 0x3c, 0x00, 0x00,
+/* 0x68 h */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x69 i */ 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+/* 0x6a j */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1c, 0x00, 0x00,
+/* 0x6b k */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x42, 0x44, 0x78, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x6c l */ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+/* 0x6d m */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xee, 0x92, 0x92, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00,
+/* 0x6e n */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x6f o */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x70 p */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x00,
+/* 0x71 q */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x03, 0x00, 0x00,
+/* 0x72 r */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+/* 0x73 s */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x38, 0x04, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+/* 0x74 t */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00,
+/* 0x75 u */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00,
+/* 0x76 v */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00,
+/* 0x77 w */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00,
+/* 0x78 x */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00,
+/* 0x79 y */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x04, 0x78, 0x00, 0x00,
+/* 0x7a z */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00,
+/* 0x7b { */ 0x00, 0x00, 0x00, 0x06, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00,
+/* 0x7c | */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+/* 0x7d } */ 0x00, 0x00, 0x00, 0x60, 0x10, 0x10, 0x10, 0x0c, 0x10, 0x10, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00,
+/* 0x7e ~ */ 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x82, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#else
+
+const uchar fonttbl[] = {
+
+
+/* Character (0x20):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ! (0x21):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | **** |
+ | **** |
+ | **** |
+ | **** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x3c,
+0x3c,
+0x3c,
+0x3c,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character " (0x22):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | * * |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x36,
+0x36,
+0x36,
+0x36,
+0x14,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character # (0x23):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x6c,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0xfe,
+0x6c,
+0x6c,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character $ (0x24):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** |
+ | **** |
+ | **** |
+ | ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x7c,
+0xc6,
+0xc0,
+0x78,
+0x3c,
+0x06,
+0xc6,
+0x7c,
+0x18,
+0x18,
+0x00,
+0x00,
+
+/* Character % (0x25):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** * |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x62,
+0x66,
+0x0c,
+0x18,
+0x30,
+0x66,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character & (0x26):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ | *** |
+ | ** |
+ | *** ** |
+ | ****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x38,
+0x6c,
+0x38,
+0x30,
+0x76,
+0x7e,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ' (0x27):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ( (0x28):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ) (0x29):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x30,
+0x18,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x30,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character * (0x2a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ | *** |
+ |******* |
+ | *** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0x38,
+0xfe,
+0x38,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character + (0x2b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ****** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x7e,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character , (0x2c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+
+/* Character - (0x2d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character . (0x2e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character / (0x2f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ |* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x02,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x80,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 0 (0x30):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ |** **** |
+ |**** ** |
+ |*** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xce,
+0xde,
+0xf6,
+0xe6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 1 (0x31):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x78,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 2 (0x32):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc6,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 3 (0x33):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ | ** |
+ | ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0x06,
+0x06,
+0x3c,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 4 (0x34):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | *** |
+ | **** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x1c,
+0x3c,
+0x6c,
+0xcc,
+0xcc,
+0xfe,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 5 (0x35):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** |
+ |** |
+ |** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc0,
+0xc0,
+0xc0,
+0xfc,
+0x06,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 6 (0x36):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |****** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xfc,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 7 (0x37):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc6,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x30,
+0x30,
+0x30,
+0x30,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 8 (0x38):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character 9 (0x39):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7e,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character : (0x3a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ; (0x3b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x0c,
+0x18,
+0x00,
+0x00,
+0x00,
+
+/* Character < (0x3c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character = (0x3d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ | |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x00,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character > (0x3e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x0c,
+0x18,
+0x30,
+0x60,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ? (0x3f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0x0c,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character @ (0x40):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** **** |
+ |** **** |
+ |** **** |
+ |** *** |
+ |** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xde,
+0xde,
+0xde,
+0xdc,
+0xc0,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character A (0x41):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character B (0x42):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character C (0x43):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** ** |
+ |** * |
+ |** |
+ |** |
+ |** |
+ |** |
+ |** * |
+ | ** ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x66,
+0xc2,
+0xc0,
+0xc0,
+0xc0,
+0xc0,
+0xc2,
+0x66,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character D (0x44):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xf8,
+0x6c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x6c,
+0xf8,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character E (0x45):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x66,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character F (0x46):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ | ** ** |
+ | ** |
+ | ** * |
+ | ***** |
+ | ** * |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0x66,
+0x60,
+0x64,
+0x7c,
+0x64,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character G (0x47):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xce,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character H (0x48):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xfe,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character I (0x49):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character J (0x4a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0xd8,
+0xd8,
+0x70,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character K (0x4b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |**** |
+ |**** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xcc,
+0xd8,
+0xf0,
+0xf0,
+0xd8,
+0xcc,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character L (0x4c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |**** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xf0,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x62,
+0x66,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character M (0x4d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |*** *** |
+ |*** *** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xee,
+0xee,
+0xfe,
+0xd6,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character N (0x4e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |*** ** |
+ |*** ** |
+ |**** ** |
+ |** **** |
+ |** *** |
+ |** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xe6,
+0xe6,
+0xf6,
+0xde,
+0xce,
+0xce,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character O (0x4f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character P (0x50):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Q (0x51):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ | ***** |
+ | ** |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0x7c,
+0x06,
+0x00,
+0x00,
+0x00,
+
+/* Character R (0x52):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |****** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfc,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x78,
+0x6c,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character S (0x53):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ | *** |
+ | *** |
+ | ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0x70,
+0x1c,
+0x06,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character T (0x54):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ****** |
+ | * ** * |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7e,
+0x5a,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character U (0x55):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character V (0x56):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character W (0x57):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ |*** *** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0xee,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character X (0x58):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Y (0x59):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x3c,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character Z (0x5a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |******* |
+ |** ** |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** * |
+ |** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xfe,
+0xc6,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x60,
+0xc2,
+0xc6,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character [ (0x5b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x60,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character \ (0x5c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ |* |
+ |** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x80,
+0xc0,
+0x60,
+0x30,
+0x18,
+0x0c,
+0x06,
+0x02,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ] (0x5d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ***** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x7c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ^ (0x5e):
+ ht=16, width=8
+ +--------+
+ | |
+ | * |
+ | *** |
+ | ** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x10,
+0x38,
+0x6c,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character _ (0x5f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ |********|
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xff,
+0x00,
+0x00,
+
+/* Character ` (0x60):
+ ht=16, width=8
+ +--------+
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x18,
+0x18,
+0x18,
+0x0c,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character a (0x61):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | **** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x78,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xdc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character b (0x62):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xfc,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character c (0x63):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ |** |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0xc0,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character d (0x64):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ****** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x7c,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character e (0x65):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |******* |
+ |** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xfe,
+0xc0,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character f (0x66):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x1c,
+0x36,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x78,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character g (0x67):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** *** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xce,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character h (0x68):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ***** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x7c,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character i (0x69):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x00,
+0x38,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x3c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character j (0x6a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |** ** |
+ |** ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0c,
+0x0c,
+0x00,
+0x1c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0x0c,
+0xcc,
+0xcc,
+0x78,
+0x00,
+0x00,
+
+/* Character k (0x6b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ |*** |
+ | ** |
+ | ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | **** |
+ | ** ** |
+ | ** ** |
+ |*** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0xe0,
+0x60,
+0x60,
+0x66,
+0x66,
+0x6c,
+0x78,
+0x6c,
+0x66,
+0xe6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character l (0x6c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x1c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character m (0x6d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ** ** |
+ |******* |
+ |** * ** |
+ |** * ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x6c,
+0xfe,
+0xd6,
+0xd6,
+0xc6,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character n (0x6e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x66,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character o (0x6f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character p (0x70):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ** ** |
+ | ***** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x66,
+0x66,
+0x66,
+0x7c,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+
+/* Character q (0x71):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | *** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ***** |
+ | ** |
+ | ** |
+ | **** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x76,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x7c,
+0x0c,
+0x0c,
+0x1e,
+0x00,
+0x00,
+
+/* Character r (0x72):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** *** |
+ | ** ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ |**** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xdc,
+0x66,
+0x60,
+0x60,
+0x60,
+0x60,
+0xf0,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character s (0x73):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | ***** |
+ |** ** |
+ |** |
+ | ***** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x7c,
+0xc6,
+0xc0,
+0x7c,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character t (0x74):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ |****** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x30,
+0x30,
+0x30,
+0xfc,
+0x30,
+0x30,
+0x30,
+0x30,
+0x36,
+0x1c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character u (0x75):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | *** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0xcc,
+0x76,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character v (0x76):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | * |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x10,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character w (0x77):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** * ** |
+ |** * ** |
+ |** * ** |
+ |******* |
+ | ** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xd6,
+0xd6,
+0xd6,
+0xfe,
+0x6c,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character x (0x78):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ | ** ** |
+ | *** |
+ | ** ** |
+ |** ** |
+ |** ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0x6c,
+0x38,
+0x6c,
+0xc6,
+0xc6,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character y (0x79):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** ** |
+ |** *** |
+ | *** ** |
+ | ** |
+ |** ** |
+ | ***** |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xc6,
+0xc6,
+0xc6,
+0xc6,
+0xce,
+0x76,
+0x06,
+0xc6,
+0x7c,
+0x00,
+0x00,
+
+/* Character z (0x7a):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ |******* |
+ |* ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** * |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0xfe,
+0x86,
+0x0c,
+0x18,
+0x30,
+0x62,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character { (0x7b):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x70,
+0x18,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character | (0x7c):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x18,
+0x18,
+0x18,
+0x18,
+0x18,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character } (0x7d):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | ** |
+ | ** |
+ | ** |
+ | ** |
+ | *** |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x70,
+0x18,
+0x18,
+0x18,
+0x0e,
+0x18,
+0x18,
+0x18,
+0x18,
+0x70,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character ~ (0x7e):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | *** ** |
+ |** *** |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x76,
+0xdc,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+/* Character  (0x7f):
+ ht=16, width=8
+ +--------+
+ | |
+ | |
+ | |
+ | |
+ | |
+ | * |
+ | *** |
+ | *** |
+ | ** ** |
+ | ** ** |
+ |******* |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +--------+ */
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+0x10,
+0x38,
+0x38,
+0x6c,
+0x6c,
+0xfe,
+0x00,
+0x00,
+0x00,
+0x00,
+0x00,
+
+};
+
+#endif
+
+//#define font8x16 fonttbl
diff --git a/ports/csb740/gdbregs.c b/ports/csb740/gdbregs.c
new file mode 100755
index 0000000..7930f9c
--- /dev/null
+++ b/ports/csb740/gdbregs.c
@@ -0,0 +1 @@
+#include "gdbregs_arm.c"
diff --git a/ports/csb740/lcd_lut.h b/ports/csb740/lcd_lut.h
new file mode 100755
index 0000000..9b074f6
--- /dev/null
+++ b/ports/csb740/lcd_lut.h
@@ -0,0 +1,289 @@
+//------------------------------------------------------------------------
+// lcd_lut.h: Lookup Table Values
+//
+
+uchar lcd_lut[256][3] = {
+// RED, GREEN, BLUE // Entry
+ { 0x0, 0x0, 0x0, }, // 00
+ { 0x0, 0x0, 0xA, }, // 01
+ { 0x0, 0xA, 0x0, }, // 02
+ { 0x0, 0xA, 0xA, }, // 03
+ { 0xA, 0x0, 0x0, }, // 04
+ { 0xA, 0x0, 0xA, }, // 05
+ { 0xA, 0xA, 0x0, }, // 06
+ { 0xA, 0xA, 0xA, }, // 07
+ { 0x5, 0x5, 0x5, }, // 08
+ { 0x5, 0x5, 0xF, }, // 09
+ { 0x5, 0xF, 0x5, }, // 0A
+ { 0x5, 0xF, 0xF, }, // 0B
+ { 0xF, 0x5, 0x5, }, // 0C
+ { 0xF, 0x5, 0xF, }, // 0D
+ { 0xF, 0xF, 0x5, }, // 0E
+ { 0xF, 0xF, 0xF, }, // 0F
+ { 0x0, 0x0, 0x0, }, // 10
+ { 0x1, 0x1, 0x1, }, // 11
+ { 0x2, 0x2, 0x2, }, // 12
+ { 0x2, 0x2, 0x2, }, // 13
+ { 0x3, 0x3, 0x3, }, // 14
+ { 0x4, 0x4, 0x4, }, // 15
+ { 0x5, 0x5, 0x5, }, // 16
+ { 0x6, 0x6, 0x6, }, // 17
+ { 0x7, 0x7, 0x7, }, // 18
+ { 0x8, 0x8, 0x8, }, // 19
+ { 0x9, 0x9, 0x9, }, // 1A
+ { 0xA, 0xA, 0xA, }, // 1B
+ { 0xB, 0xB, 0xB, }, // 1C
+ { 0xC, 0xC, 0xC, }, // 1D
+ { 0xE, 0xE, 0xE, }, // 1E
+ { 0xF, 0xF, 0xF, }, // 1F
+ { 0x0, 0x0, 0xF, }, // 20
+ { 0x4, 0x0, 0xF, }, // 21
+ { 0x7, 0x0, 0xF, }, // 22
+ { 0xB, 0x0, 0xF, }, // 23
+ { 0xF, 0x0, 0xF, }, // 24
+ { 0xF, 0x0, 0xB, }, // 25
+ { 0xF, 0x0, 0x7, }, // 26
+ { 0xF, 0x0, 0x4, }, // 27
+ { 0xF, 0x0, 0x0, }, // 28
+ { 0xF, 0x4, 0x0, }, // 29
+ { 0xF, 0x7, 0x0, }, // 2A
+ { 0xF, 0xB, 0x0, }, // 2B
+ { 0xF, 0xF, 0x0, }, // 2C
+ { 0xB, 0xF, 0x0, }, // 2D
+ { 0x7, 0xF, 0x0, }, // 2E
+ { 0x4, 0xF, 0x0, }, // 2F
+ { 0x0, 0xF, 0x0, }, // 30
+ { 0x0, 0xF, 0x4, }, // 31
+ { 0x0, 0xF, 0x7, }, // 32
+ { 0x0, 0xF, 0xB, }, // 33
+ { 0x0, 0xF, 0xF, }, // 34
+ { 0x0, 0xB, 0xF, }, // 35
+ { 0x0, 0x7, 0xF, }, // 36
+ { 0x0, 0x4, 0xF, }, // 37
+ { 0x7, 0x7, 0xF, }, // 38
+ { 0x9, 0x7, 0xF, }, // 39
+ { 0xB, 0x7, 0xF, }, // 3A
+ { 0xD, 0x7, 0xF, }, // 3B
+ { 0xF, 0x7, 0xF, }, // 3C
+ { 0xF, 0x7, 0xD, }, // 3D
+ { 0xF, 0x7, 0xB, }, // 3E
+ { 0xF, 0x7, 0x9, }, // 3F
+ { 0xF, 0x7, 0x7, }, // 40
+ { 0xF, 0x9, 0x7, }, // 41
+ { 0xF, 0xB, 0x7, }, // 42
+ { 0xF, 0xD, 0x7, }, // 43
+ { 0xF, 0xF, 0x7, }, // 44
+ { 0xD, 0xF, 0x7, }, // 45
+ { 0xB, 0xF, 0x7, }, // 46
+ { 0x9, 0xF, 0x7, }, // 47
+ { 0x7, 0xF, 0x7, }, // 48
+ { 0x7, 0xF, 0x9, }, // 49
+ { 0x7, 0xF, 0xB, }, // 4A
+ { 0x7, 0xF, 0xD, }, // 4B
+ { 0x7, 0xF, 0xF, }, // 4C
+ { 0x7, 0xD, 0xF, }, // 4D
+ { 0x7, 0xB, 0xF, }, // 4E
+ { 0x7, 0x9, 0xF, }, // 4F
+ { 0xB, 0xB, 0xF, }, // 50
+ { 0xC, 0xB, 0xF, }, // 51
+ { 0xD, 0xB, 0xF, }, // 52
+ { 0xE, 0xB, 0xF, }, // 53
+ { 0xF, 0xB, 0xF, }, // 54
+ { 0xF, 0xB, 0xE, }, // 55
+ { 0xF, 0xB, 0xD, }, // 56
+ { 0xF, 0xB, 0xC, }, // 57
+ { 0xF, 0xB, 0xB, }, // 58
+ { 0xF, 0xC, 0xB, }, // 59
+ { 0xF, 0xD, 0xB, }, // 5A
+ { 0xF, 0xE, 0xB, }, // 5B
+ { 0xF, 0xF, 0xB, }, // 5C
+ { 0xE, 0xF, 0xB, }, // 5D
+ { 0xD, 0xF, 0xB, }, // 5E
+ { 0xC, 0xF, 0xB, }, // 5F
+ { 0xB, 0xF, 0xB, }, // 60
+ { 0xB, 0xF, 0xC, }, // 61
+ { 0xB, 0xF, 0xD, }, // 62
+ { 0xB, 0xF, 0xE, }, // 63
+ { 0xB, 0xF, 0xF, }, // 64
+ { 0xB, 0xE, 0xF, }, // 65
+ { 0xB, 0xD, 0xF, }, // 66
+ { 0xB, 0xC, 0xF, }, // 67
+ { 0x0, 0x0, 0x7, }, // 68
+ { 0x1, 0x0, 0x7, }, // 69
+ { 0x3, 0x0, 0x7, }, // 6A
+ { 0x5, 0x0, 0x7, }, // 6B
+ { 0x7, 0x0, 0x7, }, // 6C
+ { 0x7, 0x0, 0x5, }, // 6D
+ { 0x7, 0x0, 0x3, }, // 6E
+ { 0x7, 0x0, 0x1, }, // 6F
+ { 0x7, 0x0, 0x0, }, // 70
+ { 0x7, 0x1, 0x0, }, // 71
+ { 0x7, 0x3, 0x0, }, // 72
+ { 0x7, 0x5, 0x0, }, // 73
+ { 0x7, 0x7, 0x0, }, // 74
+ { 0x5, 0x7, 0x0, }, // 75
+ { 0x3, 0x7, 0x0, }, // 76
+ { 0x1, 0x7, 0x0, }, // 77
+ { 0x0, 0x7, 0x0, }, // 78
+ { 0x0, 0x7, 0x1, }, // 79
+ { 0x0, 0x7, 0x3, }, // 7A
+ { 0x0, 0x7, 0x5, }, // 7B
+ { 0x0, 0x7, 0x7, }, // 7C
+ { 0x0, 0x5, 0x7, }, // 7D
+ { 0x0, 0x3, 0x7, }, // 7E
+ { 0x0, 0x1, 0x7, }, // 7F
+ { 0x3, 0x3, 0x7, }, // 80
+ { 0x4, 0x3, 0x7, }, // 81
+ { 0x5, 0x3, 0x7, }, // 82
+ { 0x6, 0x3, 0x7, }, // 83
+ { 0x7, 0x3, 0x7, }, // 84
+ { 0x7, 0x3, 0x6, }, // 85
+ { 0x7, 0x3, 0x5, }, // 86
+ { 0x7, 0x3, 0x4, }, // 87
+ { 0x7, 0x3, 0x3, }, // 88
+ { 0x7, 0x4, 0x3, }, // 89
+ { 0x7, 0x5, 0x3, }, // 8A
+ { 0x7, 0x6, 0x3, }, // 8B
+ { 0x7, 0x7, 0x3, }, // 8C
+ { 0x6, 0x7, 0x3, }, // 8D
+ { 0x5, 0x7, 0x3, }, // 8E
+ { 0x4, 0x7, 0x3, }, // 8F
+ { 0x3, 0x7, 0x3, }, // 90
+ { 0x3, 0x7, 0x4, }, // 91
+ { 0x3, 0x7, 0x5, }, // 92
+ { 0x3, 0x7, 0x6, }, // 93
+ { 0x3, 0x7, 0x7, }, // 94
+ { 0x3, 0x6, 0x7, }, // 95
+ { 0x3, 0x5, 0x7, }, // 96
+ { 0x3, 0x4, 0x7, }, // 97
+ { 0x5, 0x5, 0x7, }, // 98
+ { 0x5, 0x5, 0x7, }, // 99
+ { 0x6, 0x5, 0x7, }, // 9A
+ { 0x6, 0x5, 0x7, }, // 9B
+ { 0x7, 0x5, 0x7, }, // 9C
+ { 0x7, 0x5, 0x6, }, // 9D
+ { 0x7, 0x5, 0x6, }, // 9E
+ { 0x7, 0x5, 0x5, }, // 9F
+ { 0x7, 0x5, 0x5, }, // A0
+ { 0x7, 0x5, 0x5, }, // A1
+ { 0x7, 0x6, 0x5, }, // A2
+ { 0x7, 0x6, 0x5, }, // A3
+ { 0x7, 0x7, 0x5, }, // A4
+ { 0x6, 0x7, 0x5, }, // A5
+ { 0x6, 0x7, 0x5, }, // A6
+ { 0x5, 0x7, 0x5, }, // A7
+ { 0x5, 0x7, 0x5, }, // A8
+ { 0x5, 0x7, 0x5, }, // A9
+ { 0x5, 0x7, 0x6, }, // AA
+ { 0x5, 0x7, 0x6, }, // AB
+ { 0x5, 0x7, 0x7, }, // AC
+ { 0x5, 0x6, 0x7, }, // AD
+ { 0x5, 0x6, 0x7, }, // AE
+ { 0x5, 0x5, 0x7, }, // AF
+ { 0x0, 0x0, 0x4, }, // B0
+ { 0x1, 0x0, 0x4, }, // B1
+ { 0x2, 0x0, 0x4, }, // B2
+ { 0x3, 0x0, 0x4, }, // B3
+ { 0x4, 0x0, 0x4, }, // B4
+ { 0x4, 0x0, 0x3, }, // B5
+ { 0x4, 0x0, 0x2, }, // B6
+ { 0x4, 0x0, 0x1, }, // B7
+ { 0x4, 0x0, 0x0, }, // B8
+ { 0x4, 0x1, 0x0, }, // B9
+ { 0x4, 0x2, 0x0, }, // BA
+ { 0x4, 0x3, 0x0, }, // BB
+ { 0x4, 0x4, 0x0, }, // BC
+ { 0x3, 0x4, 0x0, }, // BD
+ { 0x2, 0x4, 0x0, }, // BE
+ { 0x1, 0x4, 0x0, }, // BF
+ { 0x0, 0x4, 0x0, }, // C0
+ { 0x0, 0x4, 0x1, }, // C1
+ { 0x0, 0x4, 0x2, }, // C2
+ { 0x0, 0x4, 0x3, }, // C3
+ { 0x0, 0x4, 0x4, }, // C4
+ { 0x0, 0x3, 0x4, }, // C5
+ { 0x0, 0x2, 0x4, }, // C6
+ { 0x0, 0x1, 0x4, }, // C7
+ { 0x2, 0x2, 0x4, }, // C8
+ { 0x2, 0x2, 0x4, }, // C9
+ { 0x3, 0x2, 0x4, }, // CA
+ { 0x3, 0x2, 0x4, }, // CB
+ { 0x4, 0x2, 0x4, }, // CC
+ { 0x4, 0x2, 0x3, }, // CD
+ { 0x4, 0x2, 0x3, }, // CE
+ { 0x4, 0x2, 0x2, }, // CF
+ { 0x4, 0x2, 0x2, }, // D0
+ { 0x4, 0x2, 0x2, }, // D1
+ { 0x4, 0x3, 0x2, }, // D2
+ { 0x4, 0x3, 0x2, }, // D3
+ { 0x4, 0x4, 0x2, }, // D4
+ { 0x3, 0x4, 0x2, }, // D5
+ { 0x3, 0x4, 0x2, }, // D6
+ { 0x2, 0x4, 0x2, }, // D7
+ { 0x2, 0x4, 0x2, }, // D8
+ { 0x2, 0x4, 0x2, }, // D9
+ { 0x2, 0x4, 0x3, }, // DA
+ { 0x2, 0x4, 0x3, }, // DB
+ { 0x2, 0x4, 0x4, }, // DC
+ { 0x2, 0x3, 0x4, }, // DD
+ { 0x2, 0x3, 0x4, }, // DE
+ { 0x2, 0x2, 0x4, }, // DF
+ { 0x2, 0x2, 0x4, }, // E0
+ { 0x3, 0x2, 0x4, }, // E1
+ { 0x3, 0x2, 0x4, }, // E2
+ { 0x3, 0x2, 0x4, }, // E3
+ { 0x4, 0x2, 0x4, }, // E4
+ { 0x4, 0x2, 0x3, }, // E5
+ { 0x4, 0x2, 0x3, }, // E6
+ { 0x4, 0x2, 0x3, }, // E7
+ { 0x4, 0x2, 0x2, }, // E8
+ { 0x4, 0x3, 0x2, }, // E9
+ { 0x4, 0x3, 0x2, }, // EA
+ { 0x4, 0x3, 0x2, }, // EB
+ { 0x4, 0x4, 0x2, }, // EC
+ { 0x3, 0x4, 0x2, }, // ED
+ { 0x3, 0x4, 0x2, }, // EE
+ { 0x3, 0x4, 0x2, }, // EF
+ { 0x2, 0x4, 0x2, }, // F0
+ { 0x2, 0x4, 0x3, }, // F1
+ { 0x2, 0x4, 0x3, }, // F2
+ { 0x2, 0x4, 0x3, }, // F3
+ { 0x2, 0x4, 0x4, }, // F4
+ { 0x2, 0x3, 0x4, }, // F5
+ { 0x2, 0x3, 0x4, }, // F6
+ { 0x2, 0x3, 0x4, }, // F7
+ { 0x0, 0x0, 0x0, }, // F8
+ { 0x0, 0x0, 0x0, }, // F9
+ { 0x0, 0x0, 0x0, }, // FA
+ { 0x0, 0x0, 0x0, }, // FB
+ { 0x0, 0x0, 0x0, }, // FC
+ { 0x0, 0x0, 0x0, }, // FD
+ { 0x0, 0x0, 0x0, }, // FE
+ { 0x0, 0x0, 0x0, }, // FF
+};
+
+// 16-bit pixels are RGB 565 - LSB of RED and BLUE are tied low at the
+// LCD Interface, while the LSB of GREEN is loaded as 0
+//#define RED_SUBPIXEL(n) (n & 0x1f) << 11
+//#define GREEN_SUBPIXEL(n) (n & 0x1f) << 6
+//#define BLUE_SUBPIXEL(n) (n & 0x1f) << 0
+
+// define a simple VGA style 16-color pallette
+//#define LU_BLACK RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+//#define LU_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f)
+//#define LU_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00)
+//#define LU_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f)
+//#define LU_RED RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+//#define LU_VIOLET RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f)
+//#define LU_YELLOW RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00)
+//#define LU_GREY RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f)
+//#define LU_WHITE RED_SUBPIXEL(0x17) | GREEN_SUBPIXEL(0x17) | BLUE_SUBPIXEL(0x17)
+//#define LU_BRT_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f)
+//#define LU_BRT_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x00)
+//#define LU_BRT_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+//#define LU_BRT_RED RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00)
+//#define LU_BRT_VIOLET RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f)
+//#define LU_BRT_YELLOW RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+//#define LU_BRT_WHITE RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f)
+
+
diff --git a/ports/csb740/makefile b/ports/csb740/makefile
new file mode 100755
index 0000000..3a350c6
--- /dev/null
+++ b/ports/csb740/makefile
@@ -0,0 +1,129 @@
+###############################################################################
+#
+# CSB740 board makefile.
+#
+#
+PLATFORM = CSB740
+TOPDIR = $(UMONTOP)
+TGTDIR = csb740
+CPUTYPE = arm
+FILETYPE = elf
+
+# Using tools installed by "sudo apt-get install gcc-arm-none-eabi"...
+ABIDIR = /usr/lib/gcc/arm-none-eabi/4.8.2
+LIBABIDIR = -L $(ABIDIR)
+TOOL_PREFIX = /usr/bin/arm-none-eabi
+
+COMMON_AFLAGS = -c -D PLATFORM_$(PLATFORM)=1 -D ASSEMBLY_ONLY
+CUSTOM_CFLAGS = -mcpu=arm1136j-s -O2 -isystem $(ABIDIR)/include -Wno-char-subscripts
+
+
+###############################################################################
+#
+# Memory map configuration:
+# The following variables are used to establish the system's memory map.
+#
+BOOTROMBASE=0x08000000
+BOOTROMLEN=0x100000
+BOOTRAMBASE=0x80000000
+BOOTRAMLEN=0x100000
+RAMTSTROMBASE=0x80100000
+RAMTSTROMLEN=0x100000
+ATAGSIZE=0x1000
+
+# These next two hard-coded values are used by the ramtst version of
+# uMon to allow it to know where these flash-based structures are located.
+MACADDRBASE=0x08000020
+ALTTFSDEVTBLBASE=0x08000040
+
+include $(TOPDIR)/target/make/common.make
+
+# Build each variable from a list of individual filenames...
+#
+LOCSSRC =
+CPUSSRC = vectors_arm.S
+LOCCSRC = ad7843.c cpuio.c etherdev.c nand740.c omap3530_gpio.c \
+ omap3530_lcd.c omap3530_sdmmc.c
+COMCSRC = arp.c cast.c cache.c chario.c cmdtbl.c \
+ docmd.c dhcp_00.c dhcpboot.c dns.c edit.c env.c ethernet.c \
+ flash.c gdb.c icmp.c if.c ledit_vt100.c monprof.c \
+ fbi.c font.c mprintf.c memcmds.c malloc.c moncom.c memtrace.c \
+ misccmds.c misc.c nand.c password.c redirect.c \
+ reg_cache.c sbrk.c sd.c \
+ start.c struct.c symtbl.c syslog.c tcpstuff.c tfs.c tfsapi.c \
+ tfsclean1.c tfscli.c tfsloader.c tfslog.c tftp.c timestuff.c \
+ tsi.c xmodem.c
+CPUCSRC = ldatags.c except_arm.c misc_arm.c strace_arm.c
+IODEVSRC = smsc911x.c uart16550.c fb_draw.c
+FLASHSRC = s29gl512n_16x1.c
+
+
+include $(TOPDIR)/target/make/objects.make
+
+OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \
+ $(FLASHOBJ) $(IODEVOBJ)
+
+#########################################################################
+#
+# Targets...
+
+# boot:
+# The default target is "boot", a shortcut to $(BUILDDIR)/boot.$(FILETYPE).
+# This builds the bootflash image that can be used by 'newmon' to
+# load a new version onto an already running system.
+#
+boot: $(BUILDDIR)/boot.$(FILETYPE)
+ @echo Boot version of uMon built under $(BUILDDIR) ...
+ @ls $(BUILDDIR)/boot*
+
+# ramtst:
+# A shortcut to $(BUILDDIR)/ramtst.$(FILETYPE). This is a version of uMon
+# that resides strictly in RAM and is used for two main purposes:
+# 1. To test new monitor features prior to burning the boot flash.
+# 2. To be downloaded into the RAM space of a board that has no programmed
+# boot flash. This provides a running monitor that can then accept
+# an incoming bootflash image using 'newmon'.
+#
+ramtst: $(BUILDDIR)/ramtst.$(FILETYPE)
+ @echo Ram-resident test version of uMon built under $(BUILDDIR) ...
+ @ls $(BUILDDIR)/ramtst*
+
+$(BUILDDIR)/boot.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a \
+ libg.a makefile
+ $(CC) $(ASMFLAGS) -o rom_reset.o rom_reset.S
+ $(MAKE_MONBUILT)
+ sed -e s/ROMBASE/$(BOOTROMBASE)/ -e s/ROMLEN/$(BOOTROMLEN)/ \
+ -e s/DRAMBASE/$(BOOTRAMBASE)/ -e s/DRAMLEN/$(BOOTRAMLEN)/ -e s/ATAGSIZE/$(ATAGSIZE)/ \
+ $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) > $(PLATFORM)_$(@F:.$(FILETYPE)=.ld)
+ $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a \
+ libg.a $(LIBABIDIR) $(LIBGCC)
+ $(MAKE_BINARY)
+ $(MAKE_GNUSYMS)
+
+$(BUILDDIR)/ramtst.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a \
+ libg.a makefile
+ $(CC) $(ASMFLAGS) -o ram_reset.o ram_reset.S
+ $(MAKE_MONBUILT)
+ sed -e s/RAMTSTROMBASE/$(RAMTSTROMBASE)/ \
+ -e s/RAMTSTROMLEN/$(RAMTSTROMLEN)/ -e s/ATAGSIZE/$(ATAGSIZE)/ \
+ -e s/MACADDRBASE/$(MACADDRBASE)/ -e s/ALTTFSDEVTBLBASE/$(ALTTFSDEVTBLBASE)/ \
+ $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) > $(PLATFORM)_$(@F:.$(FILETYPE)=.ld)
+
+ $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC)
+ $(MAKE_BINARY)
+ $(MAKE_GNUSYMS)
+
+include $(TOPDIR)/target/make/rules.make
+
+
+#########################################################################
+#
+# Miscellaneous...
+cscope_local:
+ ls rom_reset.S ram_reset.S >cscope.files
+ ls $(FLASHDIR)/s29gl512n_16x1.c >>cscope.files
+ ls $(FLASHDIR)/s29gl512n_16x1.h >>cscope.files
+
+help_local:
+
+varcheck:
diff --git a/ports/csb740/nand740.c b/ports/csb740/nand740.c
new file mode 100644
index 0000000..95a912a
--- /dev/null
+++ b/ports/csb740/nand740.c
@@ -0,0 +1,333 @@
+/*
+ * Board/device specific connection between the generic
+ * nand command and the CSB740's NAND memory access through
+ * the OMAP3530.
+ *
+ * The CSB740 uses K9K4GO8UOM NAND (512Mx8bit) device from Samsung.
+ * It is connected to the OMAP3530's CS3 through the CPLD.
+ * The device ID for this part number should be: 0xECDC109554
+ *
+ * Maker code: 0xEC
+ * Device code: 0xDC
+ * Third cycle: 0x10
+ * Fourth cycle: 0x95
+ * Fifth cycle: 0x54
+ *
+ * Blocksize: 128K (smallest eraseable chunk)
+ * Pagesize: 2K (64 pages per block)
+ *
+ * Taken from the NAND datasheet...
+ * The 528M byte physical space requires 30 addresses, thereby
+ * requiring five cycles for addressing :
+ * 2 cycles of column address, 3 cycles of row address, in that
+ * order. Page Read and Page Program need the same five address
+ * cycles following the required command input. In Block Erase
+ * operation, however, only the three row address cycles are used.
+ * Device operations are selected by writing specific commands into
+ * the command register.
+ *
+ * Taken from ONFI Spec:
+ * The address is comprised of a row address and a column address.
+ * The row address identifies the page, block, and LUN to be accessed.
+ * The column address identifies the byte or word within a page to access.
+ *
+ * Note:
+ * Apparently this Sansung device is not ONFI compliant. There was an
+ * earlier version of the CSB740 that had a Micron part on it and it was
+ * ONFI compliant (ONFI=Open Nand Flash Interface specification).
+ *
+ */
+#include "config.h"
+#if INCLUDE_NANDCMD
+#include "stddefs.h"
+#include "genlib.h"
+#include "omap3530.h"
+#include "omap3530_mem.h"
+#include "nand.h"
+
+static int pgSiz;
+static int blkSiz;
+static char onfi;
+
+#define NANDSTAT_FAIL 0x01
+#define NANDSTAT_READY 0x40
+#define NANDSTAT_NOTWP 0x80
+
+#define NAND_CMD(cs) (vuchar *)(0x6e00007C + (0x30 * cs))
+#define NAND_ADR(cs) (vuchar *)(0x6e000080 + (0x30 * cs))
+#define NAND_DAT(cs) (vuchar *)(0x6e000084 + (0x30 * cs))
+
+#define PREFETCH_READ_MODE() GPMC_REG(GPMC_PREFETCH_CONFIG1) &= ~1
+#define WRITE_POSTING_MODE() GPMC_REG(GPMC_PREFETCH_CONFIG1) |= 1
+
+#define NAND_CS_BASEADDR 0x18000000
+
+/* some discussion to follow:
+ * http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/p/29683/103192.aspx
+ * Address is "page/block/column"...
+ */
+
+/* nandBusyWait():
+ * Poll the WAIT3 bit of the gmpc-status register, waiting for
+ * it to go active.
+ * The R/B (ready/busy) pin of the NAND device is low when busy.
+ * It is tied to WAIT3 of the CPU.
+ */
+void
+nandHardBusyWait(void)
+{
+ while((GPMC_REG(GPMC_STATUS) & 0x800) == 0x800);
+ //while((GPMC_REG(GPMC_STATUS) & 0x800) == 0);
+}
+
+void
+nandSoftBusyWait(void)
+{
+ do {
+ *NAND_CMD(3) = 0x70;
+ } while((*NAND_DAT(3) & NANDSTAT_READY) == 0);
+}
+
+void
+nandSetColAddr(unsigned long addr)
+{
+ // Column1 (A07|A06|A05|A04|A03|A02|A01|A00):
+ *NAND_ADR(3) = ((addr & 0x000000ff));
+
+ // Column2 (---|---|---|---|A11|A10|A09|A08):
+ *NAND_ADR(3) = ((addr & 0x00000f00) >> 8);
+}
+
+void
+nandSetRowAddr(unsigned long addr)
+{
+ // Row1 (A19|A18|A17|A16|A15|A14|A13|A12):
+ *NAND_ADR(3) = ((addr & 0x000ff000) >> 12);
+
+ // Row2 (A27|A26|A25|A24|A23|A22|A21|A20):
+ *NAND_ADR(3) = ((addr & 0x0ff00000) >> 20);
+
+ // Row3 (---|---|---|---|---|---|A29|A28):
+ *NAND_ADR(3) = ((addr & 0x30000000) >> 28);
+}
+
+/* nandReadChunk():
+ * Transfer some chunk of memory from NAND to a destination.
+ */
+int
+nandReadChunk(char *src, char *dest, int len)
+{
+ unsigned long addr = (long)src;
+
+ PREFETCH_READ_MODE();
+
+ if (nandVerbose)
+ printf("nandReadChunk(src=0x%x,dest=0x%x,len=%d)\n",src,dest,len);
+
+ while(len > 0) {
+ int tot;
+
+ *NAND_CMD(3) = 0x00;
+ nandSetColAddr(addr);
+ nandSetRowAddr(addr);
+ *NAND_CMD(3) = 0x30;
+
+ nandHardBusyWait();
+
+ tot = len > pgSiz ? pgSiz : len;
+ memcpy(dest,(char *)NAND_CS_BASEADDR,tot);
+
+ len -= tot;
+ dest += tot;
+ }
+ return(0);
+}
+
+int
+nandWriteChunk(char *dest, char *src, int len)
+{
+ unsigned long addr = (long)dest;
+
+ WRITE_POSTING_MODE();
+
+ if (nandVerbose)
+ printf("nandWriteBlock(dest=0x%x,src=0x%x,len=%d)\n",dest,src,len);
+
+ *NAND_CMD(3) = 0x80;
+ nandSetColAddr(addr);
+ nandSetRowAddr(addr);
+ memcpy((char *)NAND_CS_BASEADDR,src,len);
+ *NAND_CMD(3) = 0x10;
+
+ nandSoftBusyWait();
+
+ return(0);
+}
+
+int
+nandEraseChunk(char *base, int len)
+{
+ unsigned long addr = (long)base;
+
+ if (nandVerbose)
+ printf("nandEraseChunk(addr=0x%x,len=%d)\n",addr,len);
+
+ *NAND_CMD(3) = 0x60;
+ nandSetRowAddr(addr);
+ *NAND_CMD(3) = 0xd0;
+
+ nandSoftBusyWait();
+
+ return(0);
+}
+
+void
+nandId(void)
+{
+ uchar d[5];
+ uchar d1[4];
+
+ *NAND_CMD(3) = 0x90;
+ *NAND_ADR(3) = 0x00;
+ d[0] = *NAND_DAT(3);
+ d[1] = *NAND_DAT(3);
+ d[2] = *NAND_DAT(3);
+ d[3] = *NAND_DAT(3);
+ d[4] = *NAND_DAT(3);
+
+ switch(d[3] & 3) {
+ case 0:
+ pgSiz = 1024;
+ break;
+ case 1:
+ pgSiz = 1024*2;
+ break;
+ case 2:
+ pgSiz = 1024*4;
+ break;
+ case 3:
+ pgSiz = 1024*8;
+ break;
+ }
+ switch((d[3] & 0x30) >> 4) {
+ case 0:
+ blkSiz = 1024*64;
+ break;
+ case 1:
+ blkSiz = 1024*128;
+ break;
+ case 2:
+ blkSiz = 1024*256;
+ break;
+ case 3:
+ blkSiz = 1024*512;
+ break;
+ }
+
+ *NAND_CMD(3) = 0x90;
+ *NAND_ADR(3) = 0x20;
+ d1[0] = *NAND_DAT(3);
+ d1[1] = *NAND_DAT(3);
+ d1[2] = *NAND_DAT(3);
+ d1[3] = *NAND_DAT(3);
+ if (memcmp((char *)d1,"ONFI",4) == 0)
+ onfi = 1;
+ else
+ onfi = 0;
+
+ if (nandVerbose) {
+ printf("nandID(): %02x%02x%02x%02x%02x\n",d[0],d[1],d[2],d[3],d[4]);
+ printf("nandID+(): %02x%02x%02x%02x%02x\n",d1[0],d1[1],d1[2],d1[3]);
+ printf("Page size: 0x%x\n",pgSiz);
+ printf("Block size: 0x%x\n",blkSiz);
+ printf("%sONFI compliant\n",onfi ? "" : "Not ");
+ }
+}
+
+int
+nandInit(void)
+{
+ vulong cfgreg;
+
+#if 0
+ printf("CFG1: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG1),GPMC_REG(GPMC_CS3_CONFIG1));
+ printf("CFG2: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG2),GPMC_REG(GPMC_CS3_CONFIG2));
+ printf("CFG3: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG3),GPMC_REG(GPMC_CS3_CONFIG3));
+ printf("CFG4: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG4),GPMC_REG(GPMC_CS3_CONFIG4));
+ printf("CFG5: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG5),GPMC_REG(GPMC_CS3_CONFIG5));
+ printf("CFG6: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG6),GPMC_REG(GPMC_CS3_CONFIG6));
+ printf("CFG7: dm -4 0x%08x 1 = %08x\n",
+ MYGPMC_REG(GPMC_CS3_CONFIG7),GPMC_REG(GPMC_CS3_CONFIG7));
+#endif
+
+
+ /* WAIT3 of the CPU is tied to the NAND's READY pin. The NAND
+ * is on CS3. Referring to section 11.1.7.2.10 of the OMAP3530 TRM,
+ * the GPMC_CONFIGX registers must be programmed...
+ */
+ GPMC_REG(GPMC_CONFIG) |= 0x1; // Force posted write.
+ GPMC_REG(GPMC_CONFIG) &= ~0x800; // WAIT3 active low.
+ GPMC_REG(GPMC_CS3_CONFIG7) = 0x00000858; // Base addr 0x18000000
+ GPMC_REG(GPMC_CS3_CONFIG1) = 0x00030800; // 8-bit NAND, WAIT3
+ GPMC_REG(GPMC_CS3_CONFIG2) = 0x00000000; // Chipselect timing
+ GPMC_REG(GPMC_CS3_CONFIG3) |= 0x7;
+ GPMC_REG(GPMC_CS3_CONFIG6) = 0x8f0307c0;
+
+ // Set drive strength of BE0/CLE
+ *(vulong *)0x48002444 |= 0x00000020;
+
+ /***********************************************************
+ *
+ * ALE and CLE on the NAND are both active high, so we want
+ * them to be pulled low...
+ *
+ * ALE config is the low half of this config register, so we only
+ * touch the bottom half...
+ */
+ cfgreg = SCM_REG(PADCONFS_GPMC_NADV_ALE); // NOE[31:16], NADV_ALE[15:0]
+ cfgreg &= 0xffff0000;
+ cfgreg |= 0x00000008;
+ SCM_REG(PADCONFS_GPMC_NADV_ALE) = cfgreg;
+ /*
+ * CLE config is the upper half of this config register, so we only
+ * touch the upper half...
+ */
+ cfgreg = SCM_REG(PADCONFS_GPMC_NWE); // NBE0_CLE[31:16], NWE[15:0]
+ cfgreg &= 0x0000ffff;
+ cfgreg |= 0x00080000;
+ SCM_REG(PADCONFS_GPMC_NWE) = cfgreg;
+
+
+ /* WAIT3 of CPU is tied to R/B pin of NAND...
+ * So, we configure that pin to run as WAIT3.
+ * NOTE:
+ * There is some confusion between this and what is in cpuio.c.
+ * The PADCONFS_GPMC_WAIT2 register sets this pin as GPIO-65 there;
+ * however the comments are confusing.
+ */
+ cfgreg = SCM_REG(PADCONFS_GPMC_WAIT2); // WAIT3[31:16], WAIT2[15:0]
+ cfgreg &= 0x0000ffff;
+ cfgreg |= 0x00080000;
+ SCM_REG(PADCONFS_GPMC_NWE) = cfgreg;
+
+ nandId();
+ return(0);
+}
+
+int
+nandInfo(void)
+{
+ nandId();
+ return(0);
+}
+
+
+#endif
+
+
diff --git a/ports/csb740/omap3530.h b/ports/csb740/omap3530.h
new file mode 100755
index 0000000..7b16ffc
--- /dev/null
+++ b/ports/csb740/omap3530.h
@@ -0,0 +1,497 @@
+//==========================================================================
+//
+// omap3530.h
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 05/02/2008
+// Description: This file contains register base addresses and offsets
+// and access macros for the OMAP3530 on-chip peripherals
+// Peripherals not used by UMON have not been tested (and
+// may not be defined). Use these defines with caution!!
+//
+
+#include "bits.h"
+
+/*
+ * 3530 specific Section
+ */
+
+/* Stuff on L3 Interconnect */
+#define SMX_APE_BASE 0x68000000
+
+/* L3 Firewall */
+#define A_REQINFOPERM0 (SMX_APE_BASE + 0x05048)
+#define A_READPERM0 (SMX_APE_BASE + 0x05050)
+#define A_WRITEPERM0 (SMX_APE_BASE + 0x05058)
+
+/* GPMC */
+#define OMAP35XX_GPMC_BASE 0x6E000000
+
+/* SMS */
+#define OMAP35XX_SMS_BASE 0x6C000000
+
+/* SDRC */
+#define OMAP35XX_SDRC_BASE 0x6D000000
+
+/*
+ * L4 Peripherals - L4 Wakeup and L4 Core now
+ */
+#define OMAP35XX_CORE_L4_IO_BASE 0x48000000
+
+#define OMAP35XX_WAKEUP_L4_IO_BASE 0x48300000
+
+#define OMAP35XX_L4_PER 0x49000000
+
+#define OMAP35XX_L4_IO_BASE OMAP35XX_CORE_L4_IO_BASE
+
+/* TAP information dont know for 3430*/
+#define OMAP35XX_TAP_BASE (0x49000000) /*giving some junk for virtio */
+
+/* base address for indirect vectors (internal boot mode) */
+#define SRAM_OFFSET0 0x40000000
+#define SRAM_OFFSET1 0x00200000
+#define SRAM_OFFSET2 0x0000F800
+#define SRAM_VECT_CODE (SRAM_OFFSET0|SRAM_OFFSET1|SRAM_OFFSET2)
+
+#define LOW_LEVEL_SRAM_STACK 0x4020FFFC
+
+/*-------------------------------------------------------------------------------------*/
+/* UART */
+/*-------------------------------------------------------------------------------------*/
+#define OMAP35XX_UART1 (OMAP35XX_L4_IO_BASE+0x6A000)
+#define OMAP35XX_UART2 (OMAP35XX_L4_IO_BASE+0x6C000)
+#define OMAP35XX_UART3 (OMAP35XX_L4_PER+0x20000)
+#define UART1_REG(_x_) *(vulong *)(OMAP35XX_UART1 + _x_)
+#define UART2_REG(_x_) *(vulong *)(OMAP35XX_UART2 + _x_)
+#define UART3_REG(_x_) *(vulong *)(OMAP35XX_UART3 + _x_)
+
+/* UART Register offsets */
+#define UART_RHR 0x00 // Receive Holding Register (read only)
+#define UART_THR 0x00 // Transmit Holding Register (write only)
+#define UART_DLL 0x00 // Baud divisor lower byte (read/write)
+#define UART_DLH 0x04 // Baud divisor higher byte (read/write)
+#define UART_IER 0x04 // Interrupt Enable Register (read/write)
+#define UART_IIR 0x08 // Interrupt Identification Register (read only)
+#define UART_FCR 0x08 // FIFO Control Register (write only)
+#define UART_EFR 0x08 // Enhanced Feature Register
+#define UART_LCR 0x0C // Line Control Register (read/write)
+#define UART_MCR 0x10 // Modem Control Register (read/write)
+#define UART_LSR 0x14 // Line Status Register (read only)
+#define UART_MSR 0x18 // Modem Status Register (read only)
+#define UART_TCR 0x18 //
+#define UART_TLR 0x1C //
+#define UART_SPR 0x1C // Scratch Pad Register (read/write)
+#define UART_MDR1 0x20 // Mode Definition Register 1
+#define UART_MDR2 0x24 // Mode Definition Register 2
+//#define UART_SFLSR 0x28 // Status FIFO Line Status Register (IrDA modes only)
+//#define UART_TXFLL 0x28 // Transmit Frame Length Register Low (IrDA modes only)
+//#define UART_RESUME 0x2C // Resume Register (IR-IrDA and IR-CIR modes only)
+//#define UART_TXFLH 0x2C // Transmit Frame Length Register High (IrDA modes only)
+//#define UART_RXFLL 0x30 // Receive Frame Length Register Low (IrDA modes only)
+//#define UART_SFREGL 0x30 // Status FIFO Register Low (IrDA modes only)
+//#define UART_RXFLH 0x34 // Receive Frame Length Register High (IrDA modes only)
+//#define UART_SFREGH 0x34 // Status FIFO Register High (IrDA modes only)
+//#define UART_BLR 0x38 // BOF Control Register (IrDA modes only)
+//#define UART_UASR 0x38 // UART Autobauding Status Register (UART autobauding mode only)
+//#define UART_ACREG 0x3C // Auxiliary Control Register (IrDA-CIR modes only)
+#define UART_SCR 0x40 // Supplementary Control Register
+#define UART_SSR 0x44 // Supplementary Status Register
+//#define UART_EBLR 0x48 // BOF Length Register (IR-IrDA and IR-CIR modes only)
+#define UART_SYSC 0x54 // System Configuration Register
+#define UART_SYSS 0x58 // System Status Register
+#define UART_WER 0x5C // Wake-up Enable Register
+#define UART_CFPS 0x60 // Carrier Frequency Prescaler Register
+
+/*-------------------------------------------------------------------------------------*/
+/* SPI - Serial Peripheral Interface */
+/*-------------------------------------------------------------------------------------*/
+#define SPI1_BASE_ADD (OMAP35XX_L4_IO_BASE+0x98000) // routed to I/O sites on CSB703
+#define SPI2_BASE_ADD (OMAP35XX_L4_IO_BASE+0x9A000)
+#define SPI3_BASE_ADD (OMAP35XX_L4_IO_BASE+0xB8000) // routed to AD7843 touch controller on CSB703
+#define SPI4_BASE_ADD (OMAP35XX_L4_IO_BASE+0xBA000)
+#define SPI1_REG(_x_) *(vulong *)(SPI1_BASE_ADD + _x_)
+#define SPI2_REG(_x_) *(vulong *)(SPI2_BASE_ADD + _x_)
+#define SPI3_REG(_x_) *(vulong *)(SPI3_BASE_ADD + _x_)
+#define SPI4_REG(_x_) *(vulong *)(SPI4_BASE_ADD + _x_)
+
+// SPI Register Defines
+#define SPI_SYSCONFIG 0x10 // System Configuration Register
+#define SPI_SYSSTATUS 0x14 // System Status Register
+#define SPI_IRQSTATUS 0x18 // Interrupt Status Register
+#define SPI_IRQENABLE 0x1C // Interrupt Enable/Disable Register
+#define SPI_WAKEUPENABLE 0x20 // WakeUp Enable/Disable Register
+#define SPI_SYST 0x24 // System Test Register
+#define SPI_MODULCTRL 0x28 // Serial Port Interface Configuration Register
+#define SPI_CH0_CONF 0x2C // Channel 0 Configuration Register
+#define SPI_CH1_CONF 0x40 // Channel 1 Configuration Register
+#define SPI_CH2_CONF 0x54 // Channel 2 Configuration Register
+#define SPI_CH3_CONF 0x68 // Channel 3 Configuration Register
+#define SPI_CH0_STAT 0x30 // Channel 0 Status Register
+#define SPI_CH1_STAT 0x44 // Channel 1 Status Register
+#define SPI_CH2_STAT 0x58 // Channel 2 Status Register
+#define SPI_CH3_STAT 0x6C // Channel 3 Status Register
+#define SPI_CH0_CTRL 0x34 // Channel 0 Control Register
+#define SPI_CH1_CTRL 0x48 // Channel 1 ControlRegister
+#define SPI_CH2_CTRL 0x5C // Channel 2 ControlRegister
+#define SPI_CH3_CTRL 0x70 // Channel 3 ControlRegister
+#define SPI_TXD0 0x38 // Channel 0 Transmit Data Register
+#define SPI_TXD1 0x4C // Channel 1 Transmit Data Register
+#define SPI_TXD2 0x60 // Channel 2 Transmit Data Register
+#define SPI_TXD3 0x74 // Channel 3 Transmit Data Register
+#define SPI_RXD0 0x3C // Channel 0 Receive Data Register
+#define SPI_RXD1 0x50 // Channel 1 Receive Data Register
+#define SPI_RXD2 0x64 // Channel 2 Receive Data Register
+#define SPI_RXD3 0x78 // Channel 3 Receive Data Register
+#define SPI_XFERLEVEL 0x7C // FIFO Transfer Levels Register
+
+// SPI Channel x Configuration Bit Defines
+#define SPI_CH_CONF_CLKG BIT29 // 1 = One clock cycle granularity
+#define SPI_CH_CONF_FFER BIT28 // 1 = FIFO buffer is used to Receive data
+#define SPI_CH_CONF_FFEW BIT27 // 1 = FIFO buffer is used to Transmit data
+#define SPI_CH_CONF_TCS_0_5 (0x00 << 25) // 0.5 clock cycles between CS toggling and first (or last) edge of SPI clock
+#define SPI_CH_CONF_TCS_1_5 (0x01 << 25) // 1.5 clock cycles between CS toggling and first (or last) edge of SPI clock
+#define SPI_CH_CONF_TCS_2_5 (0x02 << 25) // 2.5 clock cycles between CS toggling and first (or last) edge of SPI clock
+#define SPI_CH_CONF_TCS_3_5 (0x03 << 25) // 3.5 clock cycles between CS toggling and first (or last) edge of SPI clock
+#define SPI_CH_CONF_SB_POL BIT24 // 1 = Start bit polarity is held to 1 during SPI transfer
+#define SPI_CH_CONF_SBE BIT23 // 1 = Start bit added before SPI transfer, 0 = default length specified by WL
+#define SPI_CH_CONF_SPIENSLV_0 (0x00 << 21) // Slave select detection enabled on CS0
+#define SPI_CH_CONF_SPIENSLV_1 (0x01 << 21) // Slave select detection enabled on CS1
+#define SPI_CH_CONF_SPIENSLV_2 (0x02 << 21) // Slave select detection enabled on CS2
+#define SPI_CH_CONF_SPIENSLV_3 (0x03 << 21) // Slave select detection enabled on CS3
+#define SPI_CH_CONF_FORCE BIT20 // 1 = CSx high when EPOL is 0 and low when EPOL is 1
+#define SPI_CH_CONF_TURBO BIT19 // 1 = Turbo is activated
+#define SPI_CH_CONF_IS BIT18 // 1 = spim_simo selected for reception, 0 = spim_somi selected for reception
+#define SPI_CH_CONF_DPE1 BIT17 // 1 = no transmission on spim_simo, 0 = spim_simo selected for transmission
+#define SPI_CH_CONF_DPE0 BIT16 // 1 = no transmission on spim_somi, 0 = spim_somi selected for transmission
+#define SPI_CH_CONF_DMAR BIT15 // 1 = DMA read request enabled
+#define SPI_CH_CONF_DMAW BIT14 // 1 = DMA write request enabled
+#define SPI_CH_CONF_TRM_TR (0x00 << 12) // Transmit and receive mode
+#define SPI_CH_CONF_TRM_RO (0x01 << 12) // Receive-only mode
+#define SPI_CH_CONF_TRM_TO (0x02 << 12) // Transmit-only mode
+#define SPI_CH_CONF_WL(_x_) ((_x_ & 0x1f) << 7) // SPI word length, 0x7 = 8-bit
+#define SPI_CH_CONF_EPOL BIT6 // 1 = SPIM_CSx is low during active state, 0 = high during active state
+#define SPI_CH_CONF_CLKD(_x_) ((_x_ & 0xf) << 2) // Frequency divider for spim_clk
+#define SPI_CH_CONF_POL BIT1 // 1 = spim_clk is low during active state, 0 = high during active state
+#define SPI_CH_CONF_PHA BIT0 // 1 = data latched on even-numbered edges, 0 = data latched on odd-numbered edges
+
+// SPI Interrupt Status Register Bit Defines
+#define SPI_RX3_FULL BIT14 //
+#define SPI_TX3_EMPTY BIT12 //
+#define SPI_RX2_FULL BIT10 //
+#define SPI_TX2_EMPTY BIT8 //
+#define SPI_RX1_FULL BIT14 //
+#define SPI_TX1_EMPTY BIT6 //
+#define SPI_RX0_FULL BIT2 //
+#define SPI_TX0_EMPTY BIT0 //
+
+// SPI Channel Status Register Bit Defines
+#define SPI_RXF_FULL BIT6 //
+#define SPI_RXF_EMPTY BIT5 //
+#define SPI_TXF_FULL BIT4 //
+#define SPI_TXF_EMPTY BIT3 //
+#define SPI_CH_EOT BIT2 //
+#define SPI_CH_TX0_EMPTY BIT1 //
+#define SPI_CH_RX0_FULL BIT0 //
+
+/*-------------------------------------------------------------------------------------*/
+/* General Purpose Timers */
+/*-------------------------------------------------------------------------------------*/
+#define OMAP35XX_GPT1 0x48318000
+#define OMAP35XX_GPT2 0x49032000
+#define OMAP35XX_GPT3 0x49034000
+#define OMAP35XX_GPT4 0x49036000
+#define OMAP35XX_GPT5 0x49038000
+#define OMAP35XX_GPT6 0x4903A000
+#define OMAP35XX_GPT7 0x4903C000
+#define OMAP35XX_GPT8 0x4903E000
+#define OMAP35XX_GPT9 0x49040000
+#define OMAP35XX_GPT10 0x48086000
+#define OMAP35XX_GPT11 0x48088000
+#define OMAP35XX_GPT12 0x48304000
+
+/*-------------------------------------------------------------------------------------*/
+/* General Purpose I/O */
+/*-------------------------------------------------------------------------------------*/
+#define GPIO1_BASE_ADD 0x48310000
+#define GPIO2_BASE_ADD 0x49050000
+#define GPIO3_BASE_ADD 0x49052000
+#define GPIO4_BASE_ADD 0x49054000
+#define GPIO5_BASE_ADD 0x49056000
+#define GPIO6_BASE_ADD 0x49058000
+#define GPIO1_REG(_x_) *(vulong *)(GPIO1_BASE_ADD + _x_)
+#define GPIO2_REG(_x_) *(vulong *)(GPIO2_BASE_ADD + _x_)
+#define GPIO3_REG(_x_) *(vulong *)(GPIO3_BASE_ADD + _x_)
+#define GPIO4_REG(_x_) *(vulong *)(GPIO4_BASE_ADD + _x_)
+#define GPIO5_REG(_x_) *(vulong *)(GPIO5_BASE_ADD + _x_)
+#define GPIO6_REG(_x_) *(vulong *)(GPIO6_BASE_ADD + _x_)
+
+/* GPIO Register offsets */
+#define GPIO_SYSCONFIG 0x10 //
+#define GPIO_SYSSTATUS 0x14 //
+#define GPIO_CTRL 0x30 //
+#define GPIO_OE 0x34 //
+#define GPIO_DATAIN 0x38 //
+#define GPIO_DATAOUT 0x3C //
+#define GPIO_CLEARDATAOUT 0x90 //
+#define GPIO_SETDATAOUT 0x94 //
+
+/*-------------------------------------------------------------------------------------*/
+/* WatchDog Timers (1 secure, 3 GP) */
+/*-------------------------------------------------------------------------------------*/
+#define WD1_BASE_ADD 0x4830C000
+#define WD2_BASE_ADD 0x48314000
+#define WD3_BASE_ADD 0x49030000
+#define WD1_REG(_x_) *(vulong *)(WD1_BASE_ADD + _x_)
+#define WD2_REG(_x_) *(vulong *)(WD2_BASE_ADD + _x_)
+#define WD3_REG(_x_) *(vulong *)(WD3_BASE_ADD + _x_)
+
+/* WatchDog Timer Register offsets */
+#define WD_CONFIG 0x10 // System Configuration Register
+#define WD_STATUS 0x14 // System Configuration Register
+#define WD_WISR 0x18 // System Configuration Register
+#define WD_WIER 0x1C // System Configuration Register
+#define WD_WCLR 0x24 // System Configuration Register
+#define WD_WCRR 0x28 // System Configuration Register
+#define WD_WLDR 0x2C // System Configuration Register
+#define WD_WTGR 0x30 // System Configuration Register
+#define WD_WWPS 0x34 // System Configuration Register
+#define WD_WSPR 0x48 // System Configuration Register
+
+/*-------------------------------------------------------------------------------------*/
+/* 32KTIMER */
+/*-------------------------------------------------------------------------------------*/
+#define SYNC_32KTIMER_BASE (0x48320000)
+#define S32K_CR (SYNC_32KTIMER_BASE+0x10)
+
+/*-------------------------------------------------------------------------------------*/
+/* System Control Module */
+/*-------------------------------------------------------------------------------------*/
+/* Module Name Base Address Size */
+/*
+ INTERFACE 0x48002000 36 bytes
+ PADCONFS 0x48002030 564 bytes
+ GENERAL 0x48002270 767 bytes
+ MEM_WKUP 0x48002600 1K byte
+ PADCONFS_WKU 0x48002A00 80 bytes
+ GENERAL_WKUP 0x48002A60 31 bytes
+*/
+/*-------------------------------------------------------------------------------------*/
+#define OMAP35XX_CTRL_BASE (OMAP35XX_L4_IO_BASE+0x2000)
+#define SCM_REG(_x_) *(vulong *)(OMAP35XX_CTRL_BASE + _x_)
+
+/* Pad Configuration Registers */
+/* Note: Cogent is only defining the PADCONFS registers that are used in Micromonitor */
+#define PADCONFS_GPMC_NCS3 0xB4 // NCS3[15:0], NCS4[31:16]
+#define PADCONFS_GPMC_NCS5 0xB8 // NCS5[15:0], EXP_INTX[31:16]
+#define PADCONFS_GPMC_NCS7 0xBC // LCD_BKL_X[15:0], LCLK[31:16]
+#define PADCONFS_GPMC_NADV_ALE 0xC0 // NADV_ALE[15:0], NOE[31:16]
+#define PADCONFS_GPMC_NWE 0xC4 // NWE[15:0], NBE0_CLE[31:16]
+#define PADCONFS_DSS_PCLK 0xD4 // LCD_PCLK_X[15:0], LCD_HS_X[31:16]
+#define PADCONFS_DSS_VSYNC 0xD8 // LCD_VS_X[15:0], LCD_OE_X[31:16]
+#define PADCONFS_DSS_DATA0 0xDC // LCD_B0_X[15:0], LCD_B1_X[31:16]
+#define PADCONFS_DSS_DATA2 0xE0 // LCD_B2_X[15:0], LCD_B3_X[31:16]
+#define PADCONFS_DSS_DATA4 0xE4 // LCD_B4_X[15:0], LCD_B5_X[31:16]
+#define PADCONFS_DSS_DATA6 0xE8 // LCD_G0_X[15:0], LCD_G1_X[31:16]
+#define PADCONFS_DSS_DATA8 0xEC // LCD_G2_X[15:0], LCD_G3_X[31:16]
+#define PADCONFS_DSS_DATA10 0xF0 // LCD_G4_X[15:0], LCD_G5_X[31:16]
+#define PADCONFS_DSS_DATA12 0xF4 // LCD_R0_X[15:0], LCD_R1_X[31:16]
+#define PADCONFS_DSS_DATA14 0xF8 // LCD_R2_X[15:0], LCD_R3_X[31:16]
+#define PADCONFS_DSS_DATA16 0xFC // LCD_R4_X[15:0], LCD_R5_X[31:16]
+#define PADCONFS_DSS_DATA18 0x100 // SPI1_CLK_X[15:0], SPI1_MOSI_X[31:16]
+#define PADCONFS_DSS_DATA20 0x104 // SPI1_MISO_X[15:0], *SPI1_CS0_X[31:16]
+#define PADCONFS_DSS_DATA22 0x108 // GPIO7_X[15:0], NC[31:16]
+#define PADCONFS_MMC1_DAT4 0x150 // *I2C_INT_X[15:0], *PIRQ_X[31:16]
+#define PADCONFS_MMC1_DAT6 0x154 // GPIO0_X[15:0], GPIO1_X[31:16]
+#define PADCONFS_MCBSP3_CLKX 0x170 // D_TXD[15:0], D_RXD[31:16]
+#define PADCONFS_SYS_NIRQ 0x1E0 // FIQ[15:0], SYS_CLK2[31:16]
+#define PADCONFS_SYS_OFF_MODE 0xA18 // OFF_MODE_X[15:0], USB_CLK[31:16]
+#define PADCONFS_GPMC_WAIT2 0xD0 // NA[15:0], E_INTX[31:16]
+#define PADCONFS_MMC1_CLK 0x144 // MMC1_CLK[15:0], MMC1_CMD[31:16]
+#define PADCONFS_MMC1_DAT0 0x148 // MMC1_DAT0[15:0], MMC1_DAT1[31:16]
+#define PADCONFS_MMC1_DAT2 0x14C // MMC1_DAT2[15:0], MMC1_DAT3[31:16]
+
+
+#define CM_REV_REG 0x48004800
+#define PRM_REV_REG 0x48306804
+#define CM_REV_MAJ() ((*(volatile unsigned long *)CM_REV_REG & 0xf0)>>4)
+#define CM_REV_MIN() (*(volatile unsigned long *)CM_REV_REG & 0x0f)
+#define PRM_REV_MAJ() ((*(volatile unsigned long *)PRM_REV_REG & 0xf0)>>4)
+#define PRM_REV_MIN() (*(volatile unsigned long *)PRM_REV_REG & 0x0f)
+
+/* MMC registers...
+ */
+#define CM_FCLKEN1_CORE 0x48004a00
+#define CM_ICLKEN1_CORE 0x48004a10
+#define CM_IDLEST1_CORE 0x48004a20
+#define CM_AUTOIDLE1_CORE 0x48004a30
+#define PM_WKEN1_CORE 0x48306aa0
+#define PM_MPUGRPSEL1_CORE 0x48306aa4
+#define PM_IVA2GRPSEL1_CORE 0x48306aa8
+#define PM_WKST1_CORE 0x48306ab0
+#define CONTROL_DEVCONF0 0x48002274
+#define MMC1_BASE_ADD 0x4809c000
+#define MMC2_BASE_ADD 0x480ad000
+#define MMC3_BASE_ADD 0x480b4000
+#define MMC1_REG(_x_) *(vulong *)(MMC1_BASE_ADD + _x_)
+#define MMC2_REG(_x_) *(vulong *)(MMC2_BASE_ADD + _x_)
+#define MMC3_REG(_x_) *(vulong *)(MMC3_BASE_ADD + _x_)
+#define MMCHS_SYSCONFIG 0x10
+#define MMCHS_SYSSTATUS 0x14
+#define MMCHS_CSRE 0x24
+#define MMCHS_SYSTEST 0x28
+#define MMCHS_CON 0x2C
+#define MMCHS_PWCNT 0x30
+#define MMCHS_BLK 0x104
+#define MMCHS_ARG 0x108
+#define MMCHS_CMD 0x10C
+#define MMCHS_RSP10 0x110
+#define MMCHS_RSP32 0x114
+#define MMCHS_RSP54 0x118
+#define MMCHS_RSP76 0x11C
+#define MMCHS_DATA 0x120
+#define MMCHS_PSTATE 0x124
+#define MMCHS_HCTL 0x128
+#define MMCHS_SYSCTL 0x12C
+#define MMCHS_STAT 0x130
+#define MMCHS_IE 0x134
+#define MMCHS_ISE 0x138
+#define MMCHS_AC12 0x13C
+#define MMCHS_CAPA 0x140
+#define MMCHS_CUR_CAPA 0x148
+#define MMCHS_REV 0x1FC
+
+/* Miscellaneous MMC register bits...
+ * (only specified the ones I use)
+ */
+#define EN_MMC1 (1 << 24)
+#define ST_MMC1 (1 << 24)
+#define AUTO_MMC1 (1 << 24)
+#define GRPSEL_MMC1 (1 << 24)
+#define VS18 0x04000000
+#define VS30 0x02000000
+#define VS33 0x01000000
+#define MMCINIT 0x00000002
+#define ODE 0x00000001
+#define SVDS 0x00000e00
+#define SVDS18 (5 << 9)
+#define SVDS30 (6 << 9)
+#define SVDS33 (7 << 9)
+#define SDBP 0x00000100
+#define ICE 0x00000001
+#define ICS 0x00000002
+#define CEN 0x00000004
+#define CLKD(v) ((v & 0x3ff) << 6)
+#define CLKDMSK (0x3ff << 6)
+#define CLKACTIVITYMSK (3 << 8)
+#define CLKACTIVITY(n) ((n & 3) << 8)
+#define SIDLEMODEMSK (3 << 3)
+#define SIDLEMODE(n) ((n & 3) << 3)
+#define ENWAKEUP (1 << 2)
+#define IWE (1 << 24)
+#define AUTOIDLE 1
+#define CLKEXTFREE (1 << 16)
+#define SRESET 0x00000002
+#define CC 0x00000001
+#define RESETDONE 0x00000001
+#define IE_ALL 0x317f8337
+#define CDP (1 << 7)
+#define CMD(v) ((v & 0x3f) << 24)
+#define CMDMSK (0x3f << 24)
+#define CMDI 0x00000001
+#define DEBOUNCE (3 << 16)
+#define CCRC (1 << 17)
+#define DCRC (1 << 21)
+#define CERR (1 << 28)
+#define CTO (1 << 16)
+#define DP (1 << 21)
+#define RSPTYPE_NONE 0x00000000
+#define RSPTYPE_136 0x00010000
+#define RSPTYPE_48 0x00020000
+#define RSPTYPE_48BSY 0x00030000
+#define RSPTYPE 0x00030000
+#define SRD (1 << 26)
+#define SRC (1 << 25)
+#define SRA (1 << 24)
+#define DTOMSK (0xf<<16)
+#define DTO(a) ((a&0xf) << 16)
+#define NBLK(a) ((a&0xffff) << 16)
+#define BLEN(a) (a&0x7ff)
+#define MMCSDIO1ADPCLKISEL (1 << 24)
+
+/* PBIAS...
+ */
+#define CONTROL_PBIAS_LITE 0x48002520
+#define PBIAS_LITE_VMMC1_3V (0x0101)
+#define MMC_PWR_STABLE (0x0202)
+#define PBIAS_LITE_VMMC1_52MHZ (0x0404)
+#define PBIAS_LITE_MMC1_ERROR (0x0808)
+#define PBIAS_LITE_MMC1_HIGH (0x8080)
+
+/* Control status...
+ */
+#define CONTROL_STATUS 0x480022f0
+#define SYSBOOT 0x3f
+#define DEVICETYPE (0x3 << 8)
+
+/* 16 bit access CONTROL */
+#define MUX_VAL(OFFSET,VALUE)\
+ *(unsigned short *) (OMAP35XX_CTRL_BASE + (OFFSET)) = VALUE;
+
+#define CP(x) (CONTROL_PADCONF_##x)
+
+#define CONTROL_PADCONF_DSS_DATA18 0x0100
+#define CONTROL_PADCONF_DSS_DATA19 0x0102
+#define CONTROL_PADCONF_DSS_DATA20 0x0104
+#define CONTROL_PADCONF_DSS_DATA21 0x0106
+
+#define CONTROL_PADCONF_MMC1_CLK 0x0144
+#define CONTROL_PADCONF_MMC1_CMD 0x0146
+#define CONTROL_PADCONF_MMC1_DAT0 0x0148
+#define CONTROL_PADCONF_MMC1_DAT1 0x014A
+#define CONTROL_PADCONF_MMC1_DAT2 0x014C
+#define CONTROL_PADCONF_MMC1_DAT3 0x014E
+
+#define CONTROL_PADCONF_HSUSB0_CLK 0x01A2
+#define CONTROL_PADCONF_HSUSB0_STP 0x01A4
+#define CONTROL_PADCONF_HSUSB0_DIR 0x01A6
+#define CONTROL_PADCONF_HSUSB0_NXT 0x01A8
+#define CONTROL_PADCONF_HSUSB0_DATA0 0x01AA
+#define CONTROL_PADCONF_HSUSB0_DATA1 0x01AC
+#define CONTROL_PADCONF_HSUSB0_DATA2 0x01AE
+#define CONTROL_PADCONF_HSUSB0_DATA3 0x01B0
+#define CONTROL_PADCONF_HSUSB0_DATA4 0x01B2
+#define CONTROL_PADCONF_HSUSB0_DATA5 0x01B4
+#define CONTROL_PADCONF_HSUSB0_DATA6 0x01B6
+#define CONTROL_PADCONF_HSUSB0_DATA7 0x01B8
+#define CONTROL_PADCONF_I2C1_SCL 0x01BA
+#define CONTROL_PADCONF_I2C1_SDA 0x01BC
+#define CONTROL_PADCONF_McBSP3_DX 0x016C
+
+/* bits used in control reg's above
+ * IEN - Input Enable
+ * IDIS - Input Disable
+ * PTD - Pull type Down
+ * PTU - Pull type Up
+ * DIS - Pull type selection is inactive
+ * EN - Pull type selection is active
+ * M0 - Mode 0
+ */
+
+#define IEN (1 << 8)
+
+#define IDIS (0 << 8)
+#define PTU (1 << 4)
+#define PTD (0 << 4)
+#define EN (1 << 3)
+#define DIS (0 << 3)
+
+#define M0 0 /* modes */
+#define M1 1
+#define M2 2
+#define M3 3
+#define M4 4
+#define M5 5
+#define M6 6
+#define M7 7
+
diff --git a/ports/csb740/omap3530_gpio.c b/ports/csb740/omap3530_gpio.c
new file mode 100755
index 0000000..e1e4315
--- /dev/null
+++ b/ports/csb740/omap3530_gpio.c
@@ -0,0 +1,329 @@
+//==========================================================================
+//
+// mx31_gpio.c
+//
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 05/09/2008
+// Description: This file contains code to intialize the MCIMX31 GPIO
+// section as well as functions for manipulating the GPIO
+// bits
+//
+//--------------------------------------------------------------------------
+
+#include "config.h"
+#include "cpuio.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "omap3530.h"
+#include "cpu_gpio.h" // pull in target board specific header
+
+//#define GPIO_DBG
+
+//--------------------------------------------------------
+// GPIO_init()
+//
+// This function sets the startup state for the MCIMX31 GPIO
+// registers as used on the target CPU. Refer to cpu_gpio.h
+// for a description of the default values. Here we just put
+// them into the chip in the following order:
+// 1. Port x DR - Data Register
+// 2. Port x DIR - Direction Register
+// 3. Port x PSTAT - Pad Status Register
+// 4. Port x ICR1 - GPIO Interrupt Configuration Register 1
+// 5. Port x ICR2 - GPIO Interrupt Configuration Register 2
+// 6. Port x IMASK - GPIO Interrupt Mask Register
+// 7. Port x ISTAT - GPIO Interrupt Status Register
+
+void GPIO_init()
+{
+ // Port 1
+ GPIO1_REG(GPIO_OE) = PORT1_OE;
+ GPIO1_REG(GPIO_DATAOUT) = PORT1_DR;
+ //GPIO1_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO1_REG(GPIO_SETDATAOUT) = 0;
+
+ // Port 2
+ //GPIO2_REG(GPIO_OE) = 0xFEFFFFFF;
+ GPIO2_REG(GPIO_OE) = PORT2_OE;
+ GPIO2_REG(GPIO_DATAOUT) = PORT2_DR;
+ //GPIO2_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO2_REG(GPIO_SETDATAOUT) = 0;
+
+ // Port 3
+ GPIO3_REG(GPIO_OE) = PORT3_OE;
+ GPIO3_REG(GPIO_DATAOUT) = PORT3_DR;
+ //GPIO3_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO3_REG(GPIO_SETDATAOUT) = 0;
+
+ // Port 4
+ GPIO4_REG(GPIO_OE) = PORT4_OE;
+ GPIO4_REG(GPIO_DATAOUT) = PORT4_DR;
+ //GPIO4_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO4_REG(GPIO_SETDATAOUT) = 0;
+
+ // Port 5
+ GPIO5_REG(GPIO_OE) = PORT5_OE;
+ GPIO5_REG(GPIO_DATAOUT) = PORT5_DR;
+ //GPIO5_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO5_REG(GPIO_SETDATAOUT) = 0;
+
+ // Port 6
+ GPIO6_REG(GPIO_OE) = PORT6_OE;
+ GPIO6_REG(GPIO_DATAOUT) = PORT6_DR;
+ //GPIO6_REG(GPIO_CLEARDATAOUT) = 0;
+ //GPIO6_REG(GPIO_SETDATAOUT) = 0;
+}
+
+//--------------------------------------------------------
+// GPIO_set()
+//
+// This function sets the desired bit passed in.
+// NOTE: We do not test to see if setting the bit
+// would screw up any alternate functions. Use
+// this function with caution!
+//
+
+int GPIO_set(int gpio_bit)
+{
+ // quick sanity test
+#ifdef GPIO_DBG
+ printf("GPIO_set %d.\n", gpio_bit);
+#endif
+ if (gpio_bit > 191) return -1;
+
+ if (gpio_bit < 32)
+ {
+ // Port 1
+ GPIO1_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 0));
+ }
+ else if (gpio_bit < 64)
+ {
+ // Port 2
+ GPIO2_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 32));
+ }
+ else if (gpio_bit < 96)
+ {
+ // Port 3
+ GPIO3_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 64));
+ }
+ else if (gpio_bit < 128)
+ {
+ // Port 4
+ GPIO4_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 96));
+ }
+ else if (gpio_bit < 160)
+ {
+ // Port 5
+ GPIO5_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 128));
+ }
+ else
+ {
+ // Port 6
+ GPIO6_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 160));
+ }
+ return 0;
+}
+
+//--------------------------------------------------------
+// GPIO_clr()
+//
+// This function clears the desired bit passed in.
+//
+
+int GPIO_clr(int gpio_bit)
+{
+#ifdef GPIO_DBG
+ printf("GPIO_clr %d.\n", gpio_bit);
+#endif
+ // quick sanity test
+ if (gpio_bit > 191) return -1;
+
+ if (gpio_bit < 32)
+ {
+ // Port 1
+ GPIO1_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 0));
+ }
+ else if (gpio_bit < 64)
+ {
+ // Port 2
+ GPIO2_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 32));
+ }
+ else if (gpio_bit < 96)
+ {
+ // Port 3
+ GPIO3_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 64));
+ }
+ else if (gpio_bit < 128)
+ {
+ // Port 4
+ GPIO4_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 96));
+ }
+ else if (gpio_bit < 160)
+ {
+ // Port 5
+ GPIO5_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 128));
+ }
+ else
+ {
+ // Port 6
+ GPIO6_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 160));
+ }
+ return 0;
+}
+//--------------------------------------------------------
+// GPIO_tst()
+//
+// This function returns the state of desired bit passed in.
+// It does not test to see if it's an input or output and thus
+// can be used to verify if an output set/clr has taken place
+// as well as for testing an input state.
+//
+
+int GPIO_tst(int gpio_bit)
+{
+#ifdef GPIO_DBG
+ printf("GPIO_tst %d.\n", gpio_bit);
+#endif
+ // quick sanity test
+ if (gpio_bit > 191) return -1;
+
+ if (gpio_bit < 32)
+ {
+ // Port 1
+ if (GPIO1_REG(GPIO_DATAIN) & (1 << (gpio_bit - 0))) return 1;
+ }
+ else if (gpio_bit < 64)
+ {
+ // Port 2
+ if (GPIO2_REG(GPIO_DATAIN) & (1 << (gpio_bit - 32))) return 1;
+ }
+ else if (gpio_bit < 96)
+ {
+ // Port 3
+ if (GPIO3_REG(GPIO_DATAIN) & (1 << (gpio_bit - 64))) return 1;
+ }
+ else if (gpio_bit < 128)
+ {
+ // Port 4
+ if (GPIO4_REG(GPIO_DATAIN) & (1 << (gpio_bit - 96))) return 1;
+ }
+ else if (gpio_bit < 160)
+ {
+ // Port 5
+ if (GPIO5_REG(GPIO_DATAIN) & (1 << (gpio_bit - 128))) return 1;
+ }
+ else
+ {
+ // Port 6
+ if (GPIO6_REG(GPIO_DATAIN) & (1 << (gpio_bit - 160))) return 1;
+ }
+ return 0; // bit was not set
+}
+
+//--------------------------------------------------------
+// GPIO_out()
+//
+// This function changes the direction of the desired bit
+// to output. NOTE: We do not test to see if changing the
+// direction of the bit would screw up anything. Use this
+// function with caution!
+//
+// This only worlks if the GPIO has been defined as a GPIO
+// during init. It will not override the init setting, only
+// change the direction bit
+
+int GPIO_out(int gpio_bit)
+{
+#ifdef GPIO_DBG
+ printf("GPIO_out %d.\n", gpio_bit);
+#endif
+ // quick sanity test
+ if (gpio_bit > 191) return -1;
+
+ if (gpio_bit < 32)
+ {
+ // Port 1
+ GPIO1_REG(GPIO_OE) &= ~(1 << (gpio_bit - 0));
+ }
+ else if (gpio_bit < 64)
+ {
+ // Port 2
+ GPIO2_REG(GPIO_OE) &= ~(1 << (gpio_bit - 32));
+ }
+ else if (gpio_bit < 96)
+ {
+ // Port 3
+ GPIO3_REG(GPIO_OE) &= ~(1 << (gpio_bit - 64));
+ }
+ else if (gpio_bit < 128)
+ {
+ // Port 4
+ GPIO4_REG(GPIO_OE) &= ~(1 << (gpio_bit - 96));
+ }
+ else if (gpio_bit < 160)
+ {
+ // Port 5
+ GPIO5_REG(GPIO_OE) &= ~(1 << (gpio_bit - 128));
+ }
+ else
+ {
+ // Port 6
+ GPIO6_REG(GPIO_OE) &= ~(1 << (gpio_bit - 160));
+ }
+ return 0;
+}
+
+//--------------------------------------------------------
+// GPIO_in()
+//
+// This function changes the direction of the desired bit
+// to input. NOTE: We do not test to see if changing the
+// direction of the bit would screw up anything. Use this
+// function with caution!
+//
+// This only worlks if the GPIO has been defined as a GPIO
+// during init. It will not override the init setting, only
+// change the direction bit
+int GPIO_in(int gpio_bit)
+{
+#ifdef GPIO_DBG
+ printf("GPIO_in %d.\n", gpio_bit);
+#endif
+ // quick sanity test
+ if (gpio_bit > 191) return -1;
+
+ if (gpio_bit < 32)
+ {
+ // Port 1
+ GPIO1_REG(GPIO_OE) |= (1 << (gpio_bit - 0));
+ }
+ else if (gpio_bit < 64)
+ {
+ // Port 2
+ GPIO2_REG(GPIO_OE) |= (1 << (gpio_bit - 32));
+ }
+ else if (gpio_bit < 96)
+ {
+ // Port 3
+ GPIO3_REG(GPIO_OE) |= (1 << (gpio_bit - 64));
+ }
+ else if (gpio_bit < 128)
+ {
+ // Port 4
+ GPIO4_REG(GPIO_OE) |= (1 << (gpio_bit - 96));
+ }
+ else if (gpio_bit < 160)
+ {
+ // Port 5
+ GPIO5_REG(GPIO_OE) |= (1 << (gpio_bit - 128));
+ }
+ else
+ {
+ // Port 6
+ GPIO6_REG(GPIO_OE) |= (1 << (gpio_bit - 160));
+ }
+ return 0;
+}
+
diff --git a/ports/csb740/omap3530_iomux.c b/ports/csb740/omap3530_iomux.c
new file mode 100755
index 0000000..586ac48
--- /dev/null
+++ b/ports/csb740/omap3530_iomux.c
@@ -0,0 +1,530 @@
+//mx31_iomux.c
+
+#include "config.h"
+#include "cpuio.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "omap3530.h"
+#include "omap3530_iomux.h"
+#include "cpu_gpio.h" // pull in target board specific header
+
+void iomux_init()
+{
+
+// Initialization of GPR for CSB733
+IOMUX_CTL_REG(GENERAL_REGISTER) = WEIM_ON_CS3_EN | CSPI1_ON_UART_EN;
+
+// MX31_PIN_TTM_PAD = can not be written to.
+// cspi_miso = U2_RXD, cspi3_sclk = U2_RTS, cspi3_spi_rdy = U2_CTS, ttm_pad = default
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE))
+ | MX31_PIN_CSPI3_SCLK((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE))
+ | MX31_PIN_CSPI3_SPI_RDY((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE));
+// | MX31_PIN_TTM_PAD();
+
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO(0x20)
+// | MX31_PIN_CSPI3_SCLK(0x20)
+// | MX31_PIN_CSPI3_SPI_RDY(0x20);
+//// | MX31_PIN_TTM_PAD();
+
+// MX31_PIN_CLKSS and MX31_PIN_CE_CONTROL = can not be written to.
+// reset_b = NC, ce_control = default, ctl_clkss = default, cspi3_mosi = U2_RXD
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER2) = MX31_PIN_ATA_RESET_B((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_CE_CONTROL((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+// | MX31_PIN_CLKSS()
+ | MX31_PIN_CSPI3_MOSI((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1));
+
+// ata_cs1 = NC, ata_dior = D_TXD, ata_diow = NC, ata, dmack = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER3) = MX31_PIN_ATA_CS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_ATA_DIOR((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE))
+ | MX31_PIN_ATA_DIOW((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_ATA_DMACK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// sd1_data1 = SD_D1, sd1_data2 = SD_D2, sd1_data3 = SD_D3, ata_cs0 = D_RXD
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER4) = MX31_PIN_SD1_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SD1_DATA2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SD1_DATA3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_ATA_CS0((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1));
+
+// d3_spl = NC, sd1_cmd = SD_CMD, sd1_clk - SD_CLK, sd1_data0 = SD_D0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER5) = MX31_PIN_D3_SPL((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SD1_CMD((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SD1_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_SD1_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// vsync3 = LCD_VSYNC, contrast = NC, d3_rev = NC, d3_cls = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER6) = MX31_PIN_VSYNC3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CONTRAST((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_D3_REV((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_D3_CLS((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// ser_rs = NC, par_rs = NC, write = NC, read = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER7) = MX31_PIN_SER_RS((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_PAR_RS((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_WRITE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_READ((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// sd_d_io = NC, sd_d_clk = NC, lcs0 = NC, lcs1 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER8) = MX31_PIN_SD_D_IO((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SD_D_CLK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_LCS0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_LCS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// hsync = LCD_HSYNC, fpshift = LCD_PCLK, drdy0 = LCD_OE, sd_d_i = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER9) = MX31_PIN_HSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_FPSHIFT((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_DRDY0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SD_D_I((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// ld15 = LCD_R3, ld16 = LCD_R4, ld17 = LCD_R5, sd_d_i = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER10) = MX31_PIN_LD15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD16((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD17((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_VSYNC0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// ld11 = LCD_G5, ld12 = LCD_R0, ld13 = LCD_R1, ld14 = LCD_R2
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER11) = MX31_PIN_LD11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// ld7 = LCD_G1, ld8 = LCD_G2, ld9 = LCD_G3, ld10 = LCD_G4
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER12) = MX31_PIN_LD7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// ld3 = LCD_B3, ld4 = LCD_B4, ld5 = LCD_B5, ld6 = LCD_G0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER13) = MX31_PIN_LD3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usbh2_data1 = UH2_D1, ld0 = LCD_B0, ld1 = LCD_B1, ld2 = LCD_B0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER14) = MX31_PIN_USBH2_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_LD2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usbh2_dir = UH2_DIR, usbh2_stp = UH2_STP, usbh2_nxt = UH2_NXT, usbh2_data0 = UH2_D0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER15) = MX31_PIN_USBH2_DIR((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_USBH2_STP((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBH2_NXT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBH2_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usbotg_data5 = UD_D5, usbotg_data6 = UD_D6, usbotg_data7 = UD_D7, usbh2_clk = UH2_CLK
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER16) = MX31_PIN_USBOTG_DATA5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBH2_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usbotg_data1 = UD_D1, usbotg_data2 = UD_D2, usbotg_data3 = UD_D3, usbotg_data4 = UD_D4
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER17) = MX31_PIN_USBOTG_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usbotg_dir = UD_DIR, usbotg_stp = UD_STP, usbotg_nxt = UD_NXT, usbotg_data0 = UD_D0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER18) = MX31_PIN_USBOTG_DIR((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_STP((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_USBOTG_NXT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_USBOTG_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// usb_pwr = NC, usb_oc = CF_RST, usb_byp = NC, usbotg_clk = UD_CLK
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER19) = MX31_PIN_USB_PWR((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_USB_OC((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_USB_BYP((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_USBOTG_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// MX31_PIN_TDO and MX31_PIN_SJC_MOD = can not be written to
+// tdo = TDO_C, trstb = TRST_C, de_b = TP1, sjc_mod = GND
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TDO()
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TRSTB((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_DE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+// | MX31_PIN_SJC_MOD();
+
+// MX31_PIN_RTCK = can not be written to.
+// rtck = NC, tck = TCK_C, tms = TMS_C, tdi = TDI_C
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_RTCK()
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_TCK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_TMS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_TDI((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// key_col4 = NC, key_col5 = NC, key_col6 = NC, key_col7 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER22) = MX31_PIN_KEY_COL4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_COL5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_COL6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_COL7((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// key_col0 = NC, key_col1 = NC, key_col2 = NC, key_col3 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER23) = MX31_PIN_KEY_COL0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_COL1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_COL2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_COL3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// key_row4 = NC, key_row5 = NC, key_row6 = NC, key_row7 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER24) = MX31_PIN_KEY_ROW4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_ROW5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_ROW6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_KEY_ROW7((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// key_row0 = NC, key_row1 = NC, key_row2 = NC, key_row3 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER25) = MX31_PIN_KEY_ROW0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_ROW1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_ROW2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_KEY_ROW3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// txd2 = U1_TXD, rts2 = U1_RTS, cts2 = U1_CTS, batt_line = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER26) = MX31_PIN_TXD2((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_RTS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CTS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_BATT_LINE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// ri_dte1, dcd_dte1, and dtr_dce2 are set to CSPI1 signals by GPR(2)
+// rxd2 = U1_RXD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RI_DTE1()
+// | MX31_PIN_DCD_DTE1()
+// | MX31_PIN_DTR_DCE2()
+// | MX31_PIN_RXD2(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC);
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RXD2((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC));
+
+// dtr_dte1 and dsr_dte1 are set to CSPI1 signals by GPR(2)
+// ri_dce1 = SPI0_RDY, dcd_dce1 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER28) = MX31_PIN_RI_DCE1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_DCD_DCE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+// | MX31_PIN_DTR_DTE1()
+// | MX31_PIN_DSR_DTE1();
+
+// rts1 = U0_RTS, cts1 = U0_CTS, dtr_dce1 = NC, dsr_dce1 = SPI0_CLK
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER29) = MX31_PIN_RTS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CTS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_DTR_DCE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_DSR_DCE1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1));
+
+// cspi2_sclk = SPI1_CLK, cspi2_spi_rdy = SPI1_RDY, rxd1 = U0_RXD, txd1 = U0_TXD
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER30) = MX31_PIN_CSPI2_SCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSPI2_SPI_RDY((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_RXD1((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC))
+ | MX31_PIN_TXD1((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE));
+
+// cspi2_miso = SPI1_MISO, cspi2_ss0 = SPI1_CS0, cspi2_ss1 = SPI1_CS1, cspi2_ss2 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER31) = MX31_PIN_CSPI2_MISO((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSPI2_SS0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSPI2_SS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSPI2_SS2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// cspi1_ss2 = UH1_RCV, cspi1_sclk = UH1_OE, cspi1_spi_rdy = UH1_FS, cspi2_mosi = SPI1_MOSI
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER32) = MX31_PIN_CSPI1_SS2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_CSPI1_SCLK((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_CSPI1_SPI_RDY((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_CSPI2_MOSI((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// cspi1_mosi = UH1_RXDM, cspi1_miso = UH1_RXDP, cspi1_ss0 = UH1_TXDM, cspi1_ss1 = UH1_TXDP
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER33) = MX31_PIN_CSPI1_MOSI((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1))
+ | MX31_PIN_CSPI1_MISO((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1))
+ | MX31_PIN_CSPI1_SS0((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE))
+ | MX31_PIN_CSPI1_SS1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE));
+
+// stxd6 = AC_SDOUT, srxd6 = AC_SDIN, sck6 = AC_BCLK, sfs6 = AC_SYNC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER34) = MX31_PIN_STXD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SRXD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SCK6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SFS6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// stxd5 = SSI_TXD, srxd5 = SSI_RXD, sck5 = SSI_CLK, sfs5 = SSI_FRM
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER35) = MX31_PIN_STXD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SRXD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SCK5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SFS5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// stxd4 = NC, srxd4 = NC, sck4 = SSI_MCLK, sfs4 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER36) = MX31_PIN_STXD4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SRXD4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SCK4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SFS4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// stxd3 = AC_RST, srxd3 = NC, sck3 = NC, sfs3 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER37) = MX31_PIN_STXD3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_SRXD3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SCK3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_SFS3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// csi_hsync = VIP_HSYNC, csi_pixclk = VIP_PCLK, i2c_clk = I2C_SCL, i2c_dat = I2C_SDA
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER38) = MX31_PIN_CSI_HSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_PIXCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_I2C_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_I2C_DAT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// csi_d14 = VIP_D8, csi_d15 = VIP_D9, csi_mclk = VIP_MCLK, csi_vsync = VIP_VSYNC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER39) = MX31_PIN_CSI_D14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_MCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE))
+ | MX31_PIN_CSI_VSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// csi_d10 = VIP_D4, csi_d11 = VIP_D5, csi_D12 = VIP_D6, csi_D13 = VIP_D7
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER40) = MX31_PIN_CSI_D10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// csi_d6 = VIP_D0, csi_d7 = VIP_D1, csi_D8 = VIP_D2, csi_D9 = VIP_D3
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER41) = MX31_PIN_CSI_D6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// m_request = NC, m_grant = NC, csi_d4 = NC, csi_d5 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER42) = MX31_PIN_M_REQUEST((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_M_GRANT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CSI_D4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_CSI_D5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// pc_rst = UH2_D5, isis16 = UH2_D6, pc_rw_b = UH2_D7, pc_poe = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER43) = MX31_PIN_PC_RST((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_IOIS16((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_PC_RW_B((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_PC_POE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// pc_vs1 = NC, pc_vs2 = UH2_D2, pc_bvd1 = UH2_D3, pc_bvd2 = UH2_D4
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER44) = MX31_PIN_PC_VS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_PC_VS2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_PC_BVD1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1))
+ | MX31_PIN_PC_BVD2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1));
+
+// pc_cd2_b = CF_CD, pc_wait_b = CF_WAIT, pc_ready = CF_RDY, pc_pwron = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER45) = MX31_PIN_PC_CD2_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_PC_WAIT_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_PC_READY((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_PC_PWRON((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// d2, d1, and d0 are not writable, reset values are correct.
+// d2 = LD2, d1 = LD1, d0 = LD0, pc_cd1_b = CF_CD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER46) = MX31_PIN_D2()
+// | MX31_PIN_D1()
+// | MX31_PIN_D0()
+// | MX31_PIN_PC_CD1_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+
+// d6, d5, d4 and d3 are not writable, reset values are correct.
+// d6 = LD6, d5 = LD5, d4 = LD4, d3 = LD3
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER47) = MX31_PIN_D6()
+// | MX31_PIN_D5()
+// | MX31_PIN_D4()
+// | MX31_PIN_D3();
+
+// d10, d9, d8 and d7 are not writable, reset values are correct.
+// d10 = LD10, d9 = LD9, d8 = LD8, d7 = LD7
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER48) = MX31_PIN_D10()
+// | MX31_PIN_D9()
+// | MX31_PIN_D8()
+// | MX31_PIN_D7();
+
+// d14, d13, d12 and d11 are not writable, reset values are correct.
+// d14 = LD14, d13 = LD13, d12 = LD12, d11 = L11
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER49) = MX31_PIN_D14()
+// | MX31_PIN_D13()
+// | MX31_PIN_D12()
+// | MX31_PIN_D11();
+
+// d15 is not writable, reset value is correct.
+// nfwp_b = *N_WP, nfce_b = *N_CE, nfrb = N_RDY, d15 = LD15
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER50) = MX31_PIN_NFWP_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_NFCE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_NFRB((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+// | MX31_PIN_D15();
+
+// nfwe_b = *N_WE, nfre_b = *N_RE, nfale = N_ALE, nfcle = N_CLE
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER51) = MX31_PIN_NFWE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_NFRE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_NFALE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_NFCLE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// sdqs0, sdqs1, sdqs2, and sdqs3 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER52) = MX31_PIN_SDQS0()
+// | MX31_PIN_SDQS1()
+// | MX31_PIN_SDQS2()
+// | MX31_PIN_SDQS3();
+
+// sdclk_b is not writable, reset value is correct.
+// sdcke0 = SDCKE, sdcke1 = NC, sdclk = SDCLK, sdclk_b = *SDCLK
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER53) = MX31_PIN_SDCKE0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SDCKE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC))
+ | MX31_PIN_SDCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+// | MX31_PIN_SDCLK_B();
+
+// rw = *WE, ras = *SDRAS, cas = *SDCAS, sdwe = *SDWE
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER54) = MX31_PIN_RW((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_RAS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CAS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SDWE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// ecb is not writable, reset value is correct.
+// cs5 = *CS5, ecb = ECB, lba = LBA, bclk = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER55) = MX31_PIN_CS5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+// | MX31_PIN_ECB()
+ | MX31_PIN_LBA((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_BCLK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// cs1 = *CS1, cs2 = *SDCS, cs3 = NC, cs4 = *DTACK
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER56) = MX31_PIN_CS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CS3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_CS4((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1));
+
+// eb0 = *BE0, eb1 = *BE1, oe = *OE, cs0 = *CS0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER57) = MX31_PIN_EB0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_EB1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_OE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_CS0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// dqm0 = DQM0, dqm1 = DQM1, dqm2 = DQM2, dqm3 = DQM3
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER58) = MX31_PIN_DQM0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_DQM1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_DQM2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_DQM3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// sd28, sd29, sd30 and sd31 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER59) = MX31_PIN_SD28()
+// | MX31_PIN_SD29()
+// | MX31_PIN_SD30()
+// | MX31_PIN_SD31();
+
+// sd24, sd25, sd26 and sd27 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER60) = MX31_PIN_SD24()
+// | MX31_PIN_SD25()
+// | MX31_PIN_SD26()
+// | MX31_PIN_SD27();
+
+// sd20, sd21, sd22 and sd23 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER61) = MX31_PIN_SD20()
+// | MX31_PIN_SD21()
+// | MX31_PIN_SD22()
+// | MX31_PIN_SD23();
+
+// sd16, sd17, sd18 and sd19 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER62) = MX31_PIN_SD16()
+// | MX31_PIN_SD17()
+// | MX31_PIN_SD18()
+// | MX31_PIN_SD19();
+
+// sd12, sd13, sd14 and sd15 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER63) = MX31_PIN_SD12()
+// | MX31_PIN_SD13()
+// | MX31_PIN_SD14()
+// | MX31_PIN_SD15();
+
+// sd8, sd9, sd10 and sd11 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER64) = MX31_PIN_SD8()
+// | MX31_PIN_SD9()
+// | MX31_PIN_SD10()
+// | MX31_PIN_SD11();
+
+// sd4, sd5, sd6 and sd7 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER65) = MX31_PIN_SD4()
+// | MX31_PIN_SD5()
+// | MX31_PIN_SD6()
+// | MX31_PIN_SD7();
+
+// sd0, sd1, sd2 and sd3 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER66) = MX31_PIN_SD0()
+// | MX31_PIN_SD1()
+// | MX31_PIN_SD2()
+// | MX31_PIN_SD3();
+
+// a24 = A24, a25 = A25, sdba1 = SDBA1, sdba0 = SDBA0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER67) = MX31_PIN_A24((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A25((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SDBA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_SDBA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER68) = MX31_PIN_A20((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A21((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A22((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A23((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER69) = MX31_PIN_A16((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A17((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A18((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A19((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER70) = MX31_PIN_A12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER71) = MX31_PIN_A9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_MA10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER72) = MX31_PIN_A5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// address lines are one to one.
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER73) = MX31_PIN_A1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC))
+ | MX31_PIN_A4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// dvfs1 = NC, vpg0 = NC, vpg1 = NC, a0 = A0
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER74) = MX31_PIN_DVFS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_VPG0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_VPG1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_A0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+
+// ckil and power_fail are not writable, reset values are correct.
+//ckil = 32K, power_fail = PWR_FAIL, vstby = VSTBY, dvfs0 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER75) = MX31_PIN_CKIL()
+// | MX31_PIN_POWER_FAIL()
+// | MX31_PIN_VSTBY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DVFS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+
+// boot_mode1, boot_mode2, boot_mode3, and boot_mode4 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER76) = MX31_PIN_BOOT_MODE1()
+// | MX31_PIN_BOOT_MODE2()
+// | MX31_PIN_BOOT_MODE3()
+// | MX31_PIN_BOOT_MODE4();
+
+// por_b, clko, and boot_mode0 are not writable, reset values are correct.
+// reset_in_b = *RST_IN (this is set in the GPR)
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER77) = MX31_PIN_RESET_IN_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC));
+// | MX31_PIN_POR_B()
+// | MX31_PIN_CLKO()
+// | MX31_PIN_BOOT_MODE0();
+
+// ckih is not writable, reset value is correct.
+// stx0 = GPIO1, srx0 = GPIO4, simpd0 = GPIO5
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER78) = MX31_PIN_STX0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SRX0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SIMPD0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+// | MX31_PIN_CKIH();
+
+// gpio3_1 = VF_EN, sclk0 = GPIO8, srst0 = GPIO9, sven0 = GPIO0 (USR_LED)
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER79) = MX31_PIN_GPIO3_1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE))
+ | MX31_PIN_SCLK0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SRST0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_SVEN0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+
+// gpio1_4 = UH1_SUSP, gpio1_5 = PWR_RDY, gpio1_6 = UH1_MODE, gpio3_0 = NC
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER80) = MX31_PIN_GPIO1_4((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE))
+ | MX31_PIN_GPIO1_5((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC))
+ | MX31_PIN_GPIO1_6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_GPIO3_0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// gpio1_0 = *PIRQ, gpio1_1 = *E_INT, gpio1_2 = *EXP_INT, gpio1_3 = *I2C_INT
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER81) = MX31_PIN_GPIO1_0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_GPIO1_1((OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO))
+ | MX31_PIN_GPIO1_2((OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO))
+ | MX31_PIN_GPIO1_3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO));
+
+// capture = GPIO2, compare = GPIO3, watchdog_rst = NC, pwm0 = LCD_BKL
+IOMUX_CTL_REG(SW_MUX_CTL_REGISTER82) = MX31_PIN_CAPTURE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_COMPARE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_WATCHDOG_RST((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO))
+ | MX31_PIN_PWMO((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE));
+}
diff --git a/ports/csb740/omap3530_iomux.h b/ports/csb740/omap3530_iomux.h
new file mode 100755
index 0000000..f424664
--- /dev/null
+++ b/ports/csb740/omap3530_iomux.h
@@ -0,0 +1,1077 @@
+//==========================================================================
+//
+// mx31_gpio.h
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 05/02/2008
+// Description: This file contains offsets and bit defines
+// for the MCIMX31 Software Multiplexor Control Register
+//
+
+#include "omap3530.h"
+#include "bits.h"
+
+// Base address for Software Multiplexor Control Register (SW_MUX_CTL).
+// The SW_MUX_CTL has 82 seperate registers each of which contains 4
+// seperate Control Signals. So we have to write to a total of 328
+// different signals in order to set-up the MX31 to run on the Cogent platform.
+#define IOMUXC_BASE_ADDR 0x43FAC000
+#define IOMUX_CTL_REG(_x_) *(vulong *)(IOMUXC_BASE_ADDR + _x_)
+
+#define GENERAL_REGISTER 0x008
+#define SW_MUX_CTL_REGISTER1 0x00C // Contains cspi3_miso, cspi3_sclk, sspi3_spi_rdy, and ttm_pad
+#define SW_MUX_CTL_REGISTER2 0x010 // Contains ata_reset_b, ce_control, clkss, and cspi3_mosi
+#define SW_MUX_CTL_REGISTER3 0x014 // Contains ata_cs1, ata_dior, ata_diow, and ata_dmack
+#define SW_MUX_CTL_REGISTER4 0x018 // Contains sd1_data1, sd1_data2, sd1_data3, and ata_cs0
+#define SW_MUX_CTL_REGISTER5 0x01C // Contains d3_spl, sd1_cmd, sd1_clk, and sd1_data0
+#define SW_MUX_CTL_REGISTER6 0x020 // Contains vsync3, contrast, d3_rev, and d3_cls
+#define SW_MUX_CTL_REGISTER7 0x024 // Contains ser_rs, par_rs, write, and read
+#define SW_MUX_CTL_REGISTER8 0x028 // Contains sd_d_io, sd_d_clk, lcs0, and lcs1
+#define SW_MUX_CTL_REGISTER9 0x02C // Contains hsync, fpshift, drdy0, and sd_d_i
+#define SW_MUX_CTL_REGISTER10 0x030 // Contains ld15, ld16, ld17, and vsync0
+#define SW_MUX_CTL_REGISTER11 0x034
+#define SW_MUX_CTL_REGISTER12 0x038
+#define SW_MUX_CTL_REGISTER13 0x03C
+#define SW_MUX_CTL_REGISTER14 0x040
+#define SW_MUX_CTL_REGISTER15 0x044
+#define SW_MUX_CTL_REGISTER16 0x048
+#define SW_MUX_CTL_REGISTER17 0x04C
+#define SW_MUX_CTL_REGISTER18 0x050
+#define SW_MUX_CTL_REGISTER19 0x054
+#define SW_MUX_CTL_REGISTER20 0x058
+#define SW_MUX_CTL_REGISTER21 0x05C
+#define SW_MUX_CTL_REGISTER22 0x060
+#define SW_MUX_CTL_REGISTER23 0x064
+#define SW_MUX_CTL_REGISTER24 0x068
+#define SW_MUX_CTL_REGISTER25 0x06C
+#define SW_MUX_CTL_REGISTER26 0x070
+#define SW_MUX_CTL_REGISTER27 0x074
+#define SW_MUX_CTL_REGISTER28 0x078
+#define SW_MUX_CTL_REGISTER29 0x07C
+#define SW_MUX_CTL_REGISTER30 0x080
+#define SW_MUX_CTL_REGISTER31 0x084
+#define SW_MUX_CTL_REGISTER32 0x088
+#define SW_MUX_CTL_REGISTER33 0x08C
+#define SW_MUX_CTL_REGISTER34 0x090
+#define SW_MUX_CTL_REGISTER35 0x094
+#define SW_MUX_CTL_REGISTER36 0x098
+#define SW_MUX_CTL_REGISTER37 0x09C
+#define SW_MUX_CTL_REGISTER38 0x0A0
+#define SW_MUX_CTL_REGISTER39 0x0A4
+#define SW_MUX_CTL_REGISTER40 0x0A8
+#define SW_MUX_CTL_REGISTER41 0x0AC
+#define SW_MUX_CTL_REGISTER42 0x0B0
+#define SW_MUX_CTL_REGISTER43 0x0B4
+#define SW_MUX_CTL_REGISTER44 0x0B8
+#define SW_MUX_CTL_REGISTER45 0x0BC
+#define SW_MUX_CTL_REGISTER46 0x0C0
+#define SW_MUX_CTL_REGISTER47 0x0C4
+#define SW_MUX_CTL_REGISTER48 0x0C8
+#define SW_MUX_CTL_REGISTER49 0x0CC
+#define SW_MUX_CTL_REGISTER50 0x0D0
+#define SW_MUX_CTL_REGISTER51 0x0D4
+#define SW_MUX_CTL_REGISTER52 0x0D8
+#define SW_MUX_CTL_REGISTER53 0x0DC
+#define SW_MUX_CTL_REGISTER54 0x0E0
+#define SW_MUX_CTL_REGISTER55 0x0E4
+#define SW_MUX_CTL_REGISTER56 0x0E8
+#define SW_MUX_CTL_REGISTER57 0x0EC
+#define SW_MUX_CTL_REGISTER58 0x0F0
+#define SW_MUX_CTL_REGISTER59 0x0F4
+#define SW_MUX_CTL_REGISTER60 0x0F8
+#define SW_MUX_CTL_REGISTER61 0x0FC
+#define SW_MUX_CTL_REGISTER62 0x100
+#define SW_MUX_CTL_REGISTER63 0x104
+#define SW_MUX_CTL_REGISTER64 0x108
+#define SW_MUX_CTL_REGISTER65 0x10C
+#define SW_MUX_CTL_REGISTER66 0x110
+#define SW_MUX_CTL_REGISTER67 0x114
+#define SW_MUX_CTL_REGISTER68 0x118
+#define SW_MUX_CTL_REGISTER69 0x11C
+#define SW_MUX_CTL_REGISTER70 0x120
+#define SW_MUX_CTL_REGISTER71 0x124
+#define SW_MUX_CTL_REGISTER72 0x128
+#define SW_MUX_CTL_REGISTER73 0x12C
+#define SW_MUX_CTL_REGISTER74 0x130
+#define SW_MUX_CTL_REGISTER75 0x134
+#define SW_MUX_CTL_REGISTER76 0x138
+#define SW_MUX_CTL_REGISTER77 0x13C
+#define SW_MUX_CTL_REGISTER78 0x140
+#define SW_MUX_CTL_REGISTER79 0x144
+#define SW_MUX_CTL_REGISTER80 0x148
+#define SW_MUX_CTL_REGISTER81 0x14C
+#define SW_MUX_CTL_REGISTER82 0x150
+
+// General Purpose Register Bit Defines
+#define DDR_MODE_ON_CLK0_EN BIT31 // 1 = Enable DDR mode on CLK0 contact
+#define USBH2_LOOPBACK_EN BIT30 // 1 = Turn on sw_input_on (loopback) on some USBH2 contacts
+#define USBH1_LOOPBACK_EN BIT29 // 1 = Turn on sw_input_on (loopback) on some USBH1 contacts
+#define USBOTG_LOOPBACK_EN BIT28 // 1 = Turn on sw_input_on (loopback) on some USBOTG contacts
+#define USBH1_SUS_ON_SFS6_EN BIT27 // 1 = Enable USBH1_SUSPEND signal on SFS6 contact
+#define ATA_ON_KEYPAD_EN BIT26 // 1 = Enable ATA signals on Keypad Group contacts
+#define UART5_DMA_REQ_EN BIT25 // Selects either CSPI3 or UART5 DMA requests for events 10 and 11, 1 = UART5, 0 = CSPI1
+#define SLEW_RATE_SEL BIT24 // 1 = Fast Slew Rate, 0 = Slow Slew Rate
+#define DRIVE_STRENGTH_SEL BIT23 // 1 = Maximum drive strength, 0 = standard or high drive strength
+#define UPLL_ON_GPIO3_1_EN BIT22 // 1 = Enable UPLL clock bypass through GPIO3_1 contact
+#define SPLL_ON_GPIO3_0_EN BIT21 // 1 = Enable SPLL clock bypass through GPIO3_0 contact
+#define MSHC2_DMA_REQ_EN BIT20 // Selects either SDHC2 or MSHC2 DMA requests, 1 = MSCHC2, 0 = SDHC2
+#define MSHC1_DMA_REQ_EN BIT19 // Selects either SDHC1 or MSHC1 DMA requests, 1 = MSCHC1, 0 = SDHC1
+#define OTG_DATA_ON_UART_EN BIT18 // 1 = Enable USBOTG_DATA[5:3] on Full UART Group contacts
+#define OTG_D4_ON_DSR_DCE1_EN BIT17 // 1 = Enable USBOTG_DATA4 on DSR_DCE1 contact
+#define TAMPER_DETECT_EN BIT16 // 1 = Enable Tamper detect logic
+#define MBX_DMA_REQ_EN BIT15 // Selects either External or MBX DMA requests, 1 = MDX, 0 = External
+#define UART_DMA_REQ_EN BIT14 // Selects either CSPI1 or UART3 DMA requests, 1 = UART3, 0 = CSPI1
+#define WEIM_ON_CS3_EN BIT13 // Selects either CSD1 or WEIM on EMI CS3 contact, 1 = CSD1, 0 = WEIM
+#define WEIM_ON_CS2_EN BIT12 // Selects either CSD0 or WEIM on EMI CS2 contact, 1 = CSD0, 0 = WEIM
+#define USBH2_ON_AUDIO_EN BIT11 // 1 = Enable USBH2 signals on AudioPort 3 and AudioPort6
+#define ATA_SIG_ON_CSPI1_EN BIT10 // 1 = Enable ATA signals on CSPI1 Group contacts
+#define ATA_DATA_ON_CSPI1_EN BIT9 // 1 = Enable ATA DATA14-15 on Timer Group contacts and DATA0-6 on CSPI1 Group contacts
+#define ATA_DATA_ON_AUDIO_EN BIT8 // 1 = Enable DATA7-10 signals of ATA on AudioPort3 and DATA11-13 on AudioPort6
+#define ATA_DATA_ON_IPU_EN BIT7 // 1 = Enable DATA0-13 signals of ATA on IPU (CSI) and DATA14-15 on I2C
+#define ATA_SIG_ON_NANDF_EN BIT6 // 1 = Enable ATA signals on NANF contacts
+#define ATA_DATA_ON_NANDF_EN BIT5 // 1 = Enable ATA DATA7-13 on NANDF contacts
+#define ATA_ON_USBH2_EN BIT4 // 1 = Enable ATA signals on USBH2 contacts
+#define PWMO_ON_ATA_IORDY_EN BIT3 // 1 = Enable ATA IORDY signal on PWMO contact
+#define CSPI1_ON_UART_EN BIT2 // 1 = Replaces Full UART Group with CSPI1 signals
+#define DDR_MODE_EN BIT1 // 1 = Forces DDR type I/O contacts to DDR mode
+#define FIR_DMA_REQ_EN BIT0 // Selects FIR or UART2 SDMA events, 1 = FIR, 0 = UART2
+
+// Initialization of GPR for CSB733
+//IOMUX_CTL_REG(GENERAL_REGISTER) = WEIM_ON_CS3_EN | CSPI1_ON_UART_EN;
+
+// various IOMUX output functions
+#define OUTPUTCONFIG_GPIO 0x00 // used as GPIO
+#define OUTPUTCONFIG_FUNC 0x10 // output used as function
+#define OUTPUTCONFIG_ALT1 0x20 // output used as alternate function 1
+#define OUTPUTCONFIG_ALT2 0x30 // output used as alternate function 2
+#define OUTPUTCONFIG_ALT3 0x40 // output used as alternate function 3
+#define OUTPUTCONFIG_ALT4 0x50 // output used as alternate function 4
+#define OUTPUTCONFIG_ALT5 0x60 // output used as alternate function 5
+#define OUTPUTCONFIG_ALT6 0x70 // output used as alternate function 6
+
+// various IOMUX input functions
+#define INPUTCONFIG_NONE 0x00 // not configured for input
+#define INPUTCONFIG_GPIO 0x01 // input used as GPIO
+#define INPUTCONFIG_FUNC 0x02 // input used as function
+#define INPUTCONFIG_ALT1 0x04 // input used as alternate function 1
+#define INPUTCONFIG_ALT2 0x08 // input used as alternate function 2
+
+// Software Mux Control Signal Defines (SW_MUX_CTL_SIGNAL 1-4)
+#define MX31_PIN_CSPI3_MISO(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSPI3_SCLK(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSPI3_SPI_RDY(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_TTM_PAD(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_ATA_RESET_B(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CE_CONTROL(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CLKSS(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSPI3_MOSI(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_ATA_CS1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_ATA_DIOR(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_ATA_DIOW(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_ATA_DMACK(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD1_DATA1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD1_DATA2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD1_DATA3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_ATA_CS0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_D3_SPL(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD1_CMD(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD1_CLK(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD1_DATA0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_VSYNC3(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CONTRAST(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_D3_REV(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_D3_CLS(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SER_RS(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_PAR_RS(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_WRITE(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_READ(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD_D_IO(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD_D_CLK(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LCS0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_LCS1(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_HSYNC(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_FPSHIFT(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DRDY0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD_D_I(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_LD15(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_LD16(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LD17(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_VSYNC0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_LD11(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_LD12(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LD13(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_LD14(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_LD7(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_LD8(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LD9(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_LD10(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_LD3(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_LD4(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LD5(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_LD6(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USBH2_DATA1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_LD0(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LD1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_LD2(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USBH2_DIR(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_USBH2_STP(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_USBH2_NXT(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_USBH2_DATA0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USBOTG_DATA5(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_USBOTG_DATA6(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_USBOTG_DATA7(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_USBH2_CLK(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USBOTG_DATA1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_USBOTG_DATA2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_USBOTG_DATA3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_USBOTG_DATA4(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USBOTG_DIR(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_USBOTG_STP(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_USBOTG_NXT(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_USBOTG_DATA0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_USB_PWR(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_USB_OC(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_USB_BYP(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_USBOTG_CLK(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_TDO(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_TRSTB(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DE_B(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SJC_MOD(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RTCK(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_TCK(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_TMS(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_TDI(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_KEY_COL4(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_KEY_COL5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_KEY_COL6(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_KEY_COL7(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_KEY_COL0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_KEY_COL1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_KEY_COL2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_KEY_COL3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_KEY_ROW4(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_KEY_ROW5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_KEY_ROW6(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_KEY_ROW7(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_KEY_ROW0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_KEY_ROW1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_KEY_ROW2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_KEY_ROW3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_TXD2(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_RTS2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CTS2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_BATT_LINE(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RI_DTE1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_DCD_DTE1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DTR_DCE2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_RXD2(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RI_DCE1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_DCD_DCE1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DTR_DTE1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_DSR_DTE1(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RTS1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CTS1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DTR_DCE1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_DSR_DCE1(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSPI2_SCLK(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSPI2_SPI_RDY(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_RXD1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_TXD1(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSPI2_MISO(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSPI2_SS0(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSPI2_SS1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSPI2_SS2(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSPI1_SS2(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSPI1_SCLK(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSPI1_SPI_RDY(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSPI2_MOSI(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSPI1_MOSI(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSPI1_MISO(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSPI1_SS0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSPI1_SS1(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_STXD6(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SRXD6(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SCK6(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SFS6(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_STXD5(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SRXD5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SCK5(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SFS5(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_STXD4(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SRXD4(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SCK4(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SFS4(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_STXD3(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SRXD3(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SCK3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SFS3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSI_HSYNC(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSI_PIXCLK(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_I2C_CLK(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_I2C_DAT(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSI_D14(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSI_D15(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSI_MCLK(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSI_VSYNC(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSI_D10(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSI_D11(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSI_D12(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSI_D13(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CSI_D6(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CSI_D7(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSI_D8(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSI_D9(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_M_REQUEST(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_M_GRANT(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CSI_D4(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CSI_D5(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_PC_RST(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_IOIS16(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_PC_RW_B(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_PC_POE(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_PC_VS1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_PC_VS2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_PC_BVD1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_PC_BVD2(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_PC_CD2_B(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_PC_WAIT_B(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_PC_READY(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_PC_PWRON(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_D2(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_D1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_D0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_PC_CD1_B(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_D6(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_D5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_D4(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_D3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_D10(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_D9(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_D8(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_D7(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_D14(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_D13(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_D12(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_D11(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_NFWP_B(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_NFCE_B(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_NFRB(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_D15(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_NFWE_B(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_NFRE_B(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_NFALE(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_NFCLE(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SDQS0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SDQS1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SDQS2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SDQS3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SDCKE0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SDCKE1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SDCLK(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SDCLK_B(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RW(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_RAS(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CAS(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SDWE(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CS5(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_ECB(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_LBA(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_BCLK(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CS1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_CS2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CS3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CS4(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_EB0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_EB1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_OE(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CS0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_DQM0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_DQM1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_DQM2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_DQM3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD28(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD29(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD30(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD31(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD24(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD25(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD26(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD27(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD20(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD21(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD22(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD23(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD16(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD17(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD18(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD19(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD12(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD13(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD14(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD15(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD8(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD9(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD10(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD11(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD4(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD6(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD7(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_SD0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SD1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SD2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SD3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A24(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A25(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SDBA1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SDBA0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A20(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A21(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_A22(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A23(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A16(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A17(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_A18(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A19(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A12(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A13(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_A14(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A15(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A9(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A10(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_MA10(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A11(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A5(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A6(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_A7(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A8(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_A1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_A2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_A3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A4(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_DVFS1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_VPG0(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_VPG1(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_A0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CKIL(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_POWER_FAIL(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_VSTBY(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_DVFS0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_BOOT_MODE1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_BOOT_MODE2(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_BOOT_MODE3(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_BOOT_MODE4(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_RESET_IN_B(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_POR_B(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_CLKO(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_BOOT_MODE0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_STX0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SRX0(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SIMPD0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_CKIH(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_GPIO3_1(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_SCLK0(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_SRST0(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_SVEN0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_GPIO1_4(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_GPIO1_5(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_GPIO1_6(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_GPIO3_0(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_GPIO1_0(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_GPIO1_1(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_GPIO1_2(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_GPIO1_3(_x_) ((_x_ & 0xff) << 0)
+
+#define MX31_PIN_CAPTURE(_x_) ((_x_ & 0xff) << 24)
+#define MX31_PIN_COMPARE(_x_) ((_x_ & 0xff) << 16)
+#define MX31_PIN_WATCHDOG_RST(_x_) ((_x_ & 0xff) << 8)
+#define MX31_PIN_PWMO(_x_) ((_x_ & 0xff) << 0)
+
+//// MX31_PIN_TTM_PAD = can not be written to.
+//// cspi_miso = U2_RXD, cspi3_sclk = U2_RTS, cspi3_spi_rdy = U2_CTS, ttm_pad = default
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_CSPI3_SCLK(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_CSPI3_SPI_RDY(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_TTM_PAD();
+//
+//// MX31_PIN_CLKSS and MX31_PIN_CE_CONTROL = can not be written to.
+//// reset_b = NC, ce_control = default, ctl_clkss = default, cspi3_mosi = U2_RXD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER2) = MX31_PIN_ATA_RESET_B(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_CE_CONTROL(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CLKSS()
+// | MX31_PIN_CSPI3_MOSI(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT2);
+//
+//// ata_cs1 = NC, ata_dior = D_TXD, ata_diow = NC, ata, dmack = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER3) = MX31_PIN_ATA_CS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_ATA_DIOR(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_ATA_DIOW(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_ATA_DMACK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// sd1_data1 = SD_D1, sd1_data2 = SD_D2, sd1_data3 = SD_D3, ata_cs0 = D_RXD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER4) = MX31_PIN_SD1_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SD1_DATA2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SD1_DATA3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_ATA_CS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1);
+//
+//// d3_spl = NC, sd1_cmd = SD_CMD, sd1_clk - SD_CLK, sd1_data0 = SD_D0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER5) = MX31_PIN_D3_SPL(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SD1_CMD(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SD1_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_SD1_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// vsync3 = LCD_VSYNC, contrast = NC, d3_rev = NC, d3_cls = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER6) = MX31_PIN_VSYNC3(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_CONTRAST(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_D3_REV(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_D3_CLS(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
+//
+//// ser_rs = NC, par_rs = NC, write = NC, read = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER7) = MX31_PIN_SER_RS(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_PAR_RS(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_WRITE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_READ(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// sd_d_io = NC, sd_d_clk = NC, lcs0 = NC, lcs1 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER8) = MX31_PIN_SD_D_IO(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SD_D_CLK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_LCS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_LCS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// hsync = LCD_HSYNC, fpshift = LCD_PCLK, drdy0 = LCD_OE, sd_d_i = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER9) = MX31_PIN_HSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_FPSHIFT(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_DRDY0(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_SD_D_I(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// ld15 = LCD_R3, ld16 = LCD_R4, ld17 = LCD_R5, sd_d_i = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER10) = MX31_PIN_LD15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD16(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD17(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_VSYNC0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// ld11 = LCD_G5, ld12 = LCD_R0, ld13 = LCD_R1, ld14 = LCD_R2
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER11) = MX31_PIN_LD11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// ld7 = LCD_G1, ld8 = LCD_G2, ld9 = LCD_G3, ld10 = LCD_G4
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER12) = MX31_PIN_LD7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// ld3 = LCD_B3, ld4 = LCD_B4, ld5 = LCD_B5, ld6 = LCD_G0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER13) = MX31_PIN_LD3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usbh2_data1 = UH2_D1, ld0 = LCD_B0, ld1 = LCD_B1, ld2 = LCD_B0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER14) = MX31_PIN_USBH2_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_LD2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usbh2_dir = UH2_DIR, usbh2_stp = UH2_STP, usbh2_nxt = UH2_NXT, usbh2_data0 = UH2_D0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER15) = MX31_PIN_USBH2_DIR(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_USBH2_STP(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBH2_NXT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBH2_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usbotg_data5 = UD_D5, usbotg_data6 = UD_D6, usbotg_data7 = UD_D7, usbh2_clk = UH2_CLK
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER16) = MX31_PIN_USBOTG_DATA5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBH2_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usbotg_data1 = UD_D1, usbotg_data2 = UD_D2, usbotg_data3 = UD_D3, usbotg_data4 = UD_D4
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER17) = MX31_PIN_USBOTG_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usbotg_dir = UD_DIR, usbotg_stp = UD_STP, usbotg_nxt = UD_NXT, usbotg_data0 = UD_D0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER18) = MX31_PIN_USBOTG_DIR(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_STP(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_USBOTG_NXT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_USBOTG_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// usb_pwr = NC, usb_oc = CF_RST, usb_byp = NC, usbotg_clk = UD_CLK
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER19) = MX31_PIN_USB_PWR(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_USB_OC(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_USB_BYP(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_USBOTG_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// MX31_PIN_TDO and MX31_PIN_SJC_MOD = can not be written to
+//// tdo = TDO_C, trstb = TRST_C, de_b = TP1, sjc_mod = GND
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TDO()
+// | MX31_PIN_TRSTB(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SJC_MOD();
+//
+//// MX31_PIN_RTCK = can not be written to.
+//// rtck = NC, tck = TCK_C, tms = TMS_C, tdi = TDI_C
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_RTCK()
+// | MX31_PIN_TCK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_TMS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_TDI(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// key_col4 = NC, key_col5 = NC, key_col6 = NC, key_col7 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER22) = MX31_PIN_KEY_COL4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_COL5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_COL6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_COL7(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// key_col0 = NC, key_col1 = NC, key_col2 = NC, key_col3 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER23) = MX31_PIN_KEY_COL0(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_COL1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_COL2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_COL3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
+//
+//// key_row4 = NC, key_row5 = NC, key_row6 = NC, key_row7 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER24) = MX31_PIN_KEY_ROW4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_ROW5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_ROW6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_KEY_ROW7(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// key_row0 = NC, key_row1 = NC, key_row2 = NC, key_row3 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER25) = MX31_PIN_KEY_ROW0(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_ROW1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_ROW2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_KEY_ROW3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
+//
+//// txd2 = U1_TXD, rts2 = U1_RTS, cts2 = U1_CTS, batt_line = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER26) = MX31_PIN_TXD2(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_RTS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CTS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_BATT_LINE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// ri_dte1, dcd_dte1, and dtr_dce2 are set to CSPI1 signals by GPR(2)
+//// rxd2 = U1_RXD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RI_DTE1()
+// | MX31_PIN_DCD_DTE1()
+// | MX31_PIN_DTR_DCE2()
+// | MX31_PIN_RXD2(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC);
+//
+//// dtr_dte1 and dsr_dte1 are set to CSPI1 signals by GPR(2)
+//// ri_dce1 = SPI0_RDY, dcd_dce1 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER28) = MX31_PIN_RI_DCE1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_DCD_DCE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_DTR_DTE1()
+// | MX31_PIN_DSR_DTE1();
+//
+//// rts1 = U0_RTS, cts1 = U0_CTS, dtr_dce1 = NC, dsr_dce1 = SPI0_CLK
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER29) = MX31_PIN_RTS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CTS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_DTR_DCE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_DSR_DCE1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1);
+//
+//// cspi2_sclk = SPI1_CLK, cspi2_spi_rdy = SPI1_RDY, rxd1 = U0_RXD, txd1 = U0_TXD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER30) = MX31_PIN_CSPI2_SCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSPI2_SPI_RDY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_RXD1(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)
+// | MX31_PIN_TXD1(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE);
+//
+//// cspi2_miso = SPI1_MISO, cspi2_ss0 = SPI1_CS0, cspi2_ss1 = SPI1_CS1, cspi2_ss2 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER31) = MX31_PIN_CSPI2_MISO(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSPI2_SS0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSPI2_SS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSPI2_SS2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
+//
+//// cspi1_ss2 = UH1_RCV, cspi1_sclk = UH1_OE, cspi1_spi_rdy = UH1_FS, cspi2_mosi = SPI1_MOSI
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER32) = MX31_PIN_CSPI1_SS2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_CSPI1_SCLK(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_CSPI1_SPI_RDY(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_CSPI2_MOSI(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// cspi1_mosi = UH1_RXDM, cspi1_miso = UH1_RXDP, cspi1_ss0 = UH1_TXDM, cspi1_ss1 = UH1_TXDP
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER33) = MX31_PIN_CSPI1_MOSI(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)
+// | MX31_PIN_CSPI1_MISO(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)
+// | MX31_PIN_CSPI1_SS0(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_CSPI1_SS1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE);
+//
+//// stxd6 = AC_SDOUT, srxd6 = AC_SDIN, sck6 = AC_BCLK, sfs6 = AC_SYNC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER34) = MX31_PIN_STXD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SRXD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SCK6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SFS6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// stxd5 = SSI_TXD, srxd5 = SSI_RXD, sck5 = SSI_CLK, sfs5 = SSI_FRM
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER35) = MX31_PIN_STXD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SRXD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SCK5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SFS5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// stxd4 = NC, srxd4 = NC, sck4 = SSI_MCLK, sfs4 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER36) = MX31_PIN_STXD4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SRXD4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SCK4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SFS4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// stxd3 = AC_RST, srxd3 = NC, sck3 = NC, sfs3 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER37) = MX31_PIN_STXD3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_SRXD3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SCK3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_SFS3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
+//
+//// csi_hsync = VIP_HSYNC, csi_pixclk = VIP_PCLK, i2c_clk = I2C_SCL, i2c_dat = I2C_SDA
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER38) = MX31_PIN_CSI_HSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_PIXCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_I2C_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_I2C_DAT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// csi_d14 = VIP_D8, csi_d15 = VIP_D9, csi_mclk = VIP_MCLK, csi_vsync = VIP_VSYNC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER39) = MX31_PIN_CSI_D14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_MCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)
+// | MX31_PIN_CSI_VSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// csi_d10 = VIP_D4, csi_d11 = VIP_D5, csi_D12 = VIP_D6, csi_D13 = VIP_D7
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER40) = MX31_PIN_CSI_D10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// csi_d6 = VIP_D0, csi_d7 = VIP_D1, csi_D8 = VIP_D2, csi_D9 = VIP_D3
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER41) = MX31_PIN_CSI_D6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// m_request = NC, m_grant = NC, csi_d4 = NC, csi_d5 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER42) = MX31_PIN_M_REQUEST(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_M_GRANT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CSI_D4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_CSI_D5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// pc_rst = UH2_D5, isis16 = UH2_D6, pc_rw_b = UH2_D7, pc_poe = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER43) = MX31_PIN_PC_RST(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_IOIS16(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_PC_RW_B(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_PC_POE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// pc_vs1 = NC, pc_vs2 = UH2_D2, pc_bvd1 = UH2_D3, pc_bvd2 = UH2_D4
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER44) = MX31_PIN_PC_VS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_PC_VS2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_PC_BVD1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)
+// | MX31_PIN_PC_BVD2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1);
+//
+//// pc_cd2_b = CF_CD, pc_wait_b = CF_WAIT, pc_ready = CF_RDY, pc_pwron = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER45) = MX31_PIN_PC_CD2_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_PC_WAIT_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_PC_READY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_PC_PWRON(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// d2, d1, and d0 are not writable, reset values are correct.
+//// d2 = LD2, d1 = LD1, d0 = LD0, pc_cd1_b = CF_CD
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER46) = MX31_PIN_D2()
+// | MX31_PIN_D1()
+// | MX31_PIN_D0()
+// | MX31_PIN_PC_CD1_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// d6, d5, d4 and d3 are not writable, reset values are correct.
+//// d6 = LD6, d5 = LD5, d4 = LD4, d3 = LD3
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER47) = MX31_PIN_D6()
+// | MX31_PIN_D5()
+// | MX31_PIN_D4()
+// | MX31_PIN_D3();
+//
+//// d10, d9, d8 and d7 are not writable, reset values are correct.
+//// d10 = LD10, d9 = LD9, d8 = LD8, d7 = LD7
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER48) = MX31_PIN_D10()
+// | MX31_PIN_D9()
+// | MX31_PIN_D8()
+// | MX31_PIN_D7();
+//
+//// d14, d13, d12 and d11 are not writable, reset values are correct.
+//// d14 = LD14, d13 = LD13, d12 = LD12, d11 = L11
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER49) = MX31_PIN_D14()
+// | MX31_PIN_D13()
+// | MX31_PIN_D12()
+// | MX31_PIN_D11();
+//
+//// d15 is not writable, reset value is correct.
+//// nfwp_b = *N_WP, nfce_b = *N_CE, nfrb = N_RDY, d15 = LD15
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER50) = MX31_PIN_NFWP_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_NFCE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_NFRB(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_D15();
+//
+//// nfwe_b = *N_WE, nfre_b = *N_RE, nfale = N_ALE, nfcle = N_CLE
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER51) = MX31_PIN_NFWE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_NFRE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_NFALE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_NFCLE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// sdqs0, sdqs1, sdqs2, and sdqs3 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER52) = MX31_PIN_SDQS0()
+// | MX31_PIN_SDQS1()
+// | MX31_PIN_SDQS2()
+// | MX31_PIN_SDQS3();
+//
+//// sdclk_b is not writable, reset value is correct.
+//// sdcke0 = SDCKE, sdcke1 = NC, sdclk = SDCLK, sdclk_b = *SDCLK
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER53) = MX31_PIN_SDCKE0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDCKE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDCLK_B();
+//
+//// rw = *WE, ras = *SDRAS, cas = *SDCAS, sdwe = *SDWE
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER54) = MX31_PIN_RW(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_RAS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CAS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDWE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// ecb is not writable, reset value is correct.
+//// cs5 = *CS5, ecb = ECB, lba = LBA, bclk = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER55) = MX31_PIN_CS5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_ECB()
+// | MX31_PIN_LBA(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_BCLK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// cs1 = *CS1, cs2 = *SDCS, cs3 = NC, cs4 = *DTACK
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER56) = MX31_PIN_CS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CS3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_CS4(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1);
+//
+//// eb0 = *BE0, eb1 = *BE1, oe = *OE, cs0 = *CS0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER57) = MX31_PIN_EB0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_EB1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_OE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_CS0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// dqm0 = DQM0, dqm1 = DQM1, dqm2 = DQM2, dqm3 = DQM3
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER58) = MX31_PIN_DQM0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DQM1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DQM2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DQM3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// sd28, sd29, sd30 and sd31 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER59) = MX31_PIN_SD28()
+// | MX31_PIN_SD29()
+// | MX31_PIN_SD30()
+// | MX31_PIN_SD31();
+//
+//// sd24, sd25, sd26 and sd27 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER60) = MX31_PIN_SD24()
+// | MX31_PIN_SD25()
+// | MX31_PIN_SD26()
+// | MX31_PIN_SD27();
+//
+//// sd20, sd21, sd22 and sd23 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER61) = MX31_PIN_SD20()
+// | MX31_PIN_SD21()
+// | MX31_PIN_SD22()
+// | MX31_PIN_SD23();
+//
+//// sd16, sd17, sd18 and sd19 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER62) = MX31_PIN_SD16()
+// | MX31_PIN_SD17()
+// | MX31_PIN_SD18()
+// | MX31_PIN_SD19();
+//
+//// sd12, sd13, sd14 and sd15 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER63) = MX31_PIN_SD12()
+// | MX31_PIN_SD13()
+// | MX31_PIN_SD14()
+// | MX31_PIN_SD15();
+//
+//// sd8, sd9, sd10 and sd11 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER64) = MX31_PIN_SD8()
+// | MX31_PIN_SD9()
+// | MX31_PIN_SD10()
+// | MX31_PIN_SD11();
+//
+//// sd4, sd5, sd6 and sd7 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER65) = MX31_PIN_SD4()
+// | MX31_PIN_SD5()
+// | MX31_PIN_SD6()
+// | MX31_PIN_SD7();
+//
+//// sd0, sd1, sd2 and sd3 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER66) = MX31_PIN_SD0()
+// | MX31_PIN_SD1()
+// | MX31_PIN_SD2()
+// | MX31_PIN_SD3();
+//
+//// a24 = A24, a25 = A25, sdba1 = SDBA1, sdba0 = SDBA0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER67) = MX31_PIN_A24(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A25(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDBA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_SDBA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER68) = MX31_PIN_A20(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A21(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A22(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A23(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER69) = MX31_PIN_A16(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A17(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A18(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A19(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER70) = MX31_PIN_A12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER71) = MX31_PIN_A9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_MA10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER72) = MX31_PIN_A5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// address lines are one to one.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER73) = MX31_PIN_A1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_A4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// dvfs1 = NC, vpg0 = NC, vpg1 = NC, a0 = A0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER74) = MX31_PIN_DVFS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_VPG0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_VPG1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_A0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC);
+//
+//// ckil and power_fail are not writable, reset values are correct.
+////ckil = 32K, power_fail = PWR_FAIL, vstby = VSTBY, dvfs0 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER75) = MX31_PIN_CKIL()
+// | MX31_PIN_POWER_FAIL()
+// | MX31_PIN_VSTBY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_DVFS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// boot_mode1, boot_mode2, boot_mode3, and boot_mode4 are not writable, reset values are correct.
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER76) = MX31_PIN_BOOT_MODE1()
+// | MX31_PIN_BOOT_MODE2()
+// | MX31_PIN_BOOT_MODE3()
+// | MX31_PIN_BOOT_MODE4();
+//
+//// por_b, clko, and boot_mode0 are not writable, reset values are correct.
+//// reset_in_b = *RST_IN (this is set in the GPR)
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER77) = MX31_PIN_RESET_IN_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)
+// | MX31_PIN_POR_B()
+// | MX31_PIN_CLKO()
+// | MX31_PIN_BOOT_MODE0();
+//
+//// ckih is not writable, reset value is correct.
+//// stx0 = GPIO1, srx0 = GPIO4, simpd0 = GPIO5
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER78) = MX31_PIN_STX0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SRX0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SIMPD0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_CKIH();
+//
+//// gpio3_1 = VF_EN, sclk0 = GPIO8, srst0 = GPIO9, sven0 = GPIO0
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER79) = MX31_PIN_GPIO3_1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)
+// | MX31_PIN_SCLK0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SRST0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_SVEN0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// gpio1_4 = UH1_SUSP, gpio1_5 = PWR_RDY, gpio1_6 = UH1_MODE, gpio3_0 = NC
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER80) = MX31_PIN_GPIO1_4(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)
+// | MX31_PIN_GPIO1_5(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)
+// | MX31_PIN_GPIO1_6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_GPIO3_0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// gpio1_0 = *PIRQ, gpio1_1 = *E_INT, gpio1_2 = *EXP_INT, gpio1_3 = *I2C_INT
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER81) = MX31_PIN_GPIO1_0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_GPIO1_1(OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO)
+// | MX31_PIN_GPIO1_2(OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO)
+// | MX31_PIN_GPIO1_3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO);
+//
+//// capture = GPIO2, compare = GPIO3, watchdog_rst = NC, pwm0 = LCD_BKL
+//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER82) = MX31_PIN_CAPTURE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_COMPARE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_WATCHDOG_RST(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)
+// | MX31_PIN_PWMO(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE);
diff --git a/ports/csb740/omap3530_lcd.c b/ports/csb740/omap3530_lcd.c
new file mode 100755
index 0000000..13a2c37
--- /dev/null
+++ b/ports/csb740/omap3530_lcd.c
@@ -0,0 +1,342 @@
+//==========================================================================
+//
+// omap3530_lcd.c
+//
+// Author(s): Luis Torrico - Cogent Computer Systems, Inc.
+// Date: 12-10-2008
+// Description: Init Code for TI OMAP3530 LCD Controller
+// NOTE Only 16-bit mode has been tested!
+//
+//==========================================================================
+
+#include "config.h"
+#include "cpuio.h"
+#include "stddefs.h"
+#include "genlib.h"
+#include "omap3530.h"
+#include "omap3530_lcd.h"
+#include "cpu_gpio.h"
+#include "vga_lookup.h"
+#include "font8x16.h"
+#include "fb_draw.h"
+#include "warmstart.h"
+
+#if INCLUDE_LCD
+
+//--------------------------------------------------------------------------
+// function prototypes and externs
+//
+void fbdev_init(void);
+
+extern void udelay(int);
+extern int GPIO_clr(int);
+extern int GPIO_set(int);
+extern int GPIO_tst(int);
+extern int GPIO_out(int);
+extern int GPIO_in(int);
+
+// ADDED FOR WRITING CHARACTERS TO THE DISPLAY
+void lcd_putchar(char c);
+void lcd_writechar(uchar c);
+void lcd_clr_row(int char_row);
+void lcd_clr_scr(void);
+void lcd_switch_buffer(void);
+
+// globals to keep track of foreground, background colors and x,y position
+int lcd_color_depth; // 4, 8 or 16
+int lcd_fg_color; // 0 to 15, used as lookup into VGA color table
+int lcd_bg_color; // 0 to 15, used as lookup into VGA color table
+int lcd_col; // current column, 0 to COLS_PER_SCREEN - 1
+int lcd_row; // current row, 0 to (ROWS_PER_SCREEN * 2) - 1
+int lcd_tst_mode = 0;
+ulong lcd_fb_offset; // current offset into frame buffer for lcd_putchar
+
+//#define LCD_DBG
+//--------------------------------------------------------------------------
+// fbdev_init
+//
+// This function sets up the OMAP3530 LCD Controller, to be used
+// as uMon's frame buffer device.
+//
+void
+fbdev_init(void)
+{
+ //ushort temp16;
+
+ if (StateOfMonitor != INITIALIZE)
+ return;
+
+ lcd_color_depth = 16;
+ lcd_fg_color = vga_lookup[LCD_FG_DEF];
+ lcd_bg_color = vga_lookup[LCD_BG_DEF];
+
+ // Select DSS1_ALWON_FCLK (96MHz) as source for DSI and DISPC
+ DSS_REG(DSS_CONTROL) = 0x30;
+
+ // apply a soft reset to the display subsystem
+ DISPC_REG(DISPC_SYSCONFIG) = 0x02;
+
+ udelay(1000);
+
+ // Set interface and functional clock to on during wakeup
+ // and no standby or idle
+ DISPC_REG(DISPC_SYSCONFIG) |= 0x2015;
+
+ // Set up the DMA base address
+ DISPC_REG(DISPC_GFX_BA) = 0x80200000;
+
+ // Set up RGB 16 and disable the DMA for now
+ DISPC_REG(DISPC_GFX_ATTR) = 0x0000000C;
+
+ // Set preload based on equation in section 15.5.3.2 in RM
+ //DISPC_REG(DISPC_GFX_PRELOAD) = 0x60;
+
+ // Set number of bytes to increment at end of row to 1 (default value)
+ DISPC_REG(DISPC_GFX_ROW_INC) = 0x0001;
+
+ // Set number of bytes to increment between two pixels to 1 (default value)
+ DISPC_REG(DISPC_GFX_PIX_INC) = 0x0001;
+
+ // Set FIFO thresholds to defaults (hi = 1023, lo = 960)
+ //DISPC_REG(DISPC_GFX_FIFO_TH) = 0x03FF03C0;
+ DISPC_REG(DISPC_GFX_FIFO_TH) = 0x03FC03BC;
+
+ // Set start position to 0 (frame buffer and active display area are the same)
+ DISPC_REG(DISPC_GFX_POS) = 0x00000000;
+
+ // Set frame buffer size, Y = PIXELS_PER_COL, X = PIXELS_PER_ROW
+ DISPC_REG(DISPC_GFX_SIZE) = (((PIXELS_PER_COL -1) << 16) | (PIXELS_PER_ROW - 1));
+
+ // Set the control register keep bit 5 (GOLCD) and bit 28 (LCDENABLESIGNAL) low
+ // until shadow registers have all been written
+ DISPC_REG(DISPC_CONTROL) = 0x38019209;
+
+ // Disable all gating, pixel clock always toggles, frame data only
+ // loaded every frame (palette/gamma table off)
+ DISPC_REG(DISPC_CONFIG) = 0x00000004;
+ //DISPC_REG(DISPC_CONFIG) = 0x00000000;
+
+ // Disable all capabilities not used for LCD
+ DISPC_REG(DISPC_CAPABLE) = 0x00000000;
+
+ // Set horizontal timing
+ DISPC_REG(DISPC_TIMING_H) = ((LCD_H_BACK << 20) | (LCD_H_FRONT << 8) | LCD_H_WIDTH);
+
+ // Set vertical timing
+ DISPC_REG(DISPC_TIMING_V) = ((LCD_V_BACK << 20) | (LCD_V_FRONT << 8) | LCD_V_WIDTH);
+
+ // Set syncs low true and DE to hi true
+ DISPC_REG(DISPC_POL_FREQ) = 0x00003000;
+
+ // Set logic divisor to 1 and pixel divisor to 2
+ DISPC_REG(DISPC_DIVISOR) = 0x00020001;
+
+ // Set LCD size, lines per panel is , pixels per line is
+ DISPC_REG(DISPC_SIZE_LCD) = (((PIXELS_PER_COL -1) << 16) | (PIXELS_PER_ROW - 1));
+
+ // Enable the DMA
+ DISPC_REG(DISPC_GFX_ATTR) |= 0x00000001;
+
+ // Set bit 5 (GOLCD) to enable LCD
+ DISPC_REG(DISPC_CONTROL) |= 0x00000020;
+
+ printf("OMAP3530 LCD Initialization Complete.\n");
+
+ return;
+}
+
+/* fbdev_setstart():
+ * Used by uMon's FBI interface to establish the starting address of
+ * the frame buffer memory.
+ */
+void
+fbdev_setstart(long offset)
+{
+ // Select DSS1_ALWON_FCLK (96MHz) as source for DSI and DISPC
+ DSS_REG(DSS_CONTROL) = 0x30;
+
+ // Set up the DMA base address
+ DISPC_REG(DISPC_GFX_BA) = offset;
+
+ // Enable the DMA
+ DISPC_REG(DISPC_GFX_ATTR) |= 0x00000001;
+
+ // Set bit 5 (GOLCD) to enable LCD
+ DISPC_REG(DISPC_CONTROL) |= 0x00000020;
+
+ return;
+}
+
+char *lcd_tstHelp[] = {
+ "OMAP3530 LCD controller test",
+ "-[n,x,d[4,8,16]]",
+ "The user may set color depth to run the test at.",
+ "The frame buffer R/W test will test all of the frame ",
+ "buffer regardless of depth.",
+ "Options...",
+ " -n run test without keycheck - CAUTION: RESET SYSTEM TO STOP!",
+ " -d4 run test, force a depth of 4-bits/pixel",
+ " -d8 run test, force a depth of 8-bits/pixel",
+ " -d16 run test, force a depth of 16-bits/pixel",
+ " -x init only, do not run frame buffer tests",
+ "",
+ " No options, default to current mode and depth.",
+ 0
+};
+
+int lcd_tst(int argc,char *argv[])
+{
+ volatile ushort wr16, rd16;
+ int i, x, opt;
+ int no_wait = 0;
+ int init_only = 0;
+ char c;
+
+ lcd_tst_mode = 1;
+
+ while ((opt=getopt(argc,argv,"clnsxd:4,8,16")) != -1) {
+ switch(opt) {
+ case 'd': // set the color depth
+ switch(*optarg) {
+ case '4':
+ lcd_color_depth = 4;
+ printf("Forcing 4bpp Mode!\n");
+ break;
+ case '8':
+ lcd_color_depth = 8;
+ printf("Forcing 8bpp Mode!\n");
+ break;
+ default: // test with 16bpp
+ lcd_color_depth = 16;
+ printf("Forcing 16bpp Mode!\n");
+ break;
+ }
+ break;
+ case 'n': // no waiting for keypress - fastest operation
+ no_wait = 1;
+ printf("No Keypress Mode, Must Reset System to Stop!\n");
+ break;
+ case 'x': // init only
+ no_wait = 1;
+ printf("Initializing LCD, Skipping testsp!\n");
+ init_only = 1;
+ break;
+ default: // test with current mode
+ break;
+ }
+ }
+
+ // get the new parameters into the LCD controller
+ fbdev_init();
+
+ if (init_only) return 0;
+
+ printf("Frame Buffer R/W...");
+ // do an address=data read/write test on the frame buffer
+ // PIXELS_PER_COL * PIXELS_PER_ROW is the highest pixel.
+ // Multiply by bits_per_pixel (sed_color_depth), then
+ // divide by 8 to get the actual byte count.
+ for (i = 0; i < LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth); i += 2){
+ LCD_BUF(i) = i & 0xffff;
+ rd16 = LCD_BUF(i);
+ if(rd16 != (i & 0xffff)){
+ printf("Fail at 0x%08x, WR 0x%08x, RD 0x%04lx!\n",LCD_BUF_ADD + i, i, (ulong)rd16);
+ return -1;
+ }
+ }
+
+ printf("OK!, Press key to continue.\n");
+
+ c = getchar();
+
+ printf("Frame Buffer Start: 0x%08x, End 0x%08x\n",LCD_BUF_ADD,
+ LCD_BUF_ADD + LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth));
+ if (no_wait)
+ {
+ printf("Begin Full Screen Color Test.\n");
+ while(1){
+ // fill the frame buffer with incrementing color values
+ for (x = 0; x < 16; x++){
+ switch (lcd_color_depth){
+ case 4: wr16 = x | x << 4 | x << 8 | x << 12; break;
+ case 8: wr16 = x | x << 8; break;
+ default: wr16 = vga_lookup[x]; break; // 16-bits bypasses the lookup table
+ }
+ for (i = 0; i < LCD_FB_SIZE(lcd_color_depth); i += 2){
+ LCD_BUF(i) = wr16;
+ }
+ } // for x
+ } // while
+ } // no_wait
+ else
+ {
+ printf("Begin Full Screen Color Test, Press any key to go to next color, \'x\' to end.\n");
+ while(1){
+ // fill the frame buffer with incrementing color values
+ for (x = 0; x < 16; x++){
+ switch (lcd_color_depth){
+ case 4: wr16 = x | x << 4 | x << 8 | x << 12; break;
+ case 8: wr16 = x | x << 8; break;
+ default: wr16 = vga_lookup[x]; break; // 16-bits bypasses the lookup table
+ }
+ for (i = 0; i < LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth); i += 2){
+ LCD_BUF(i) = wr16;
+ }
+ c = getchar();
+ if (c == 'x') goto lcd_tst_next;
+ } // for x
+ } // while
+ } // else no keycheck test
+
+ lcd_tst_next:
+
+ // write a one pixel border around the screen
+ lcd_fg_color = 15; // VGA Bright White
+ fb_draw_line2(LEFT, TOP, RIGHT, TOP, lcd_fg_color);
+ fb_draw_line2(LEFT, TOP, LEFT, BOTTOM, lcd_fg_color);
+ fb_draw_line2(LEFT, BOTTOM, RIGHT, BOTTOM, lcd_fg_color); // bottom left to bottom right
+ fb_draw_line2(RIGHT, TOP, RIGHT, BOTTOM, lcd_fg_color); // bottom right to top right
+ // draw an x
+ fb_draw_line2(LEFT, TOP, RIGHT, BOTTOM, lcd_fg_color);
+ fb_draw_line2(LEFT, BOTTOM, RIGHT, TOP, lcd_fg_color);
+ // draw 3 circles at the center of the screen, one inside the other
+ lcd_fg_color = 12; // VGA Bright Red
+ fb_draw_circle2(CENTER_X, CENTER_Y, 100, lcd_fg_color);
+ lcd_fg_color = 10; // VGA Bright Green
+ fb_draw_circle2(CENTER_X, CENTER_Y, 66, lcd_fg_color);
+ lcd_fg_color = 9; // VGA Bright Blue
+ fb_draw_circle2(CENTER_X, CENTER_Y, 33, lcd_fg_color);
+
+ return 0;
+}
+
+// fb_set_pixel sets a pixel to the specified color.
+// This is target specific and is called from the generic
+// fb_draw.c functions
+void fb_set_pixel(ulong X, ulong Y, uchar color)
+{
+ // Make sure the specified pixel is valid.
+#if 0
+ if((X < 0) || (X >= PIXELS_PER_ROW) || (Y < 0) || (Y >= PIXELS_PER_COL))
+ {
+ printf("fb_set_pixel() bad X (%ld) or Y (%ld)!\n", X, Y);
+ return;
+ }
+#else
+ if (X < 0)
+ X = 0;
+ else {
+ if (X >= PIXELS_PER_ROW)
+ X = PIXELS_PER_ROW - 1;
+ }
+ if (Y < 0)
+ Y = 0;
+ else {
+ if (Y >= PIXELS_PER_COL)
+ Y = PIXELS_PER_COL - 1;
+ }
+#endif
+
+ LCD_BUF(LCD_GET_PIXEL_ADD(X, Y)) = vga_lookup[color];
+}
+#endif
diff --git a/ports/csb740/omap3530_lcd.h b/ports/csb740/omap3530_lcd.h
new file mode 100755
index 0000000..0457548
--- /dev/null
+++ b/ports/csb740/omap3530_lcd.h
@@ -0,0 +1,75 @@
+//==========================================================================
+//
+// omap3530_lcd.h
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 12/10/2008
+// Description: This file contains register offsets and bit defines
+// for the OMAP3530 Cortex-A8 LCD Controller
+//
+
+#include "bits.h"
+
+/* The DSS is designed to support video and graphics processing functions and to */
+/* interface with video/still image sensors and displays. */
+
+/*-------------------------------------------------------------------------------------*/
+/* Display Interface Subsystem */
+/*-------------------------------------------------------------------------------------*/
+/* Module Name Base Address Size */
+/*
+ DSI Protocol Engine 0x4804FC00 512 bytes
+ DSI Complex I/O 0x4804FE00 64 bytes
+ DSI PLL Controller 0x4804FF00 32 bytes
+ DISS 0x48050000 512 byte
+ DISPC 0x48050400 1K byte
+ RFBI 0x48050800 256 bytes
+ VENC 0x48050C00 256 bytes
+*/
+/*-------------------------------------------------------------------------------------*/
+#define DSS_BASE_ADD 0x48050000 // Display Subsystem Base Address
+#define DISPC_BASE_ADD 0x48050400 // Display Controller Base Address
+#define DSS_REG(_x_) *(vulong *)(DSS_BASE_ADD + _x_)
+#define DISPC_REG(_x_) *(vulong *)(DISPC_BASE_ADD + _x_)
+
+// Display Subsystem Registers
+#define DSS_SYSCONFIG 0x10 //
+#define DSS_SYSSTATUS 0x14 //
+#define DSS_IRQSTATUS 0x18 //
+#define DSS_CONTROL 0x40 //
+#define DSS_SDI_CONTROL 0x44 //
+#define DSS_PLL_CONTROL 0x48 //
+#define DSS_SDI_STATUS 0x5C //
+
+// Display Controller Registers
+#define DISPC_SYSCONFIG 0x10 //
+#define DISPC_SYSSTATUS 0x14 //
+#define DISPC_IRQSTATUS 0x18 //
+#define DISPC_IRQENABLE 0x1C //
+#define DISPC_CONTROL 0x40 //
+#define DISPC_CONFIG 0x44 //
+#define DISPC_CAPABLE 0x48 //
+#define DISPC_DEFAULT_COLOR 0x4C //
+#define DISPC_TRANS_COLOR 0x54 //
+#define DISPC_LINE_STATUS 0x5C //
+#define DISPC_LINE_NUMBER 0x60 //
+#define DISPC_TIMING_H 0x64 //
+#define DISPC_TIMING_V 0x68 //
+#define DISPC_POL_FREQ 0x6C //
+#define DISPC_DIVISOR 0x70 //
+#define DISPC_GLOBAL_ALPHA 0x74 //
+#define DISPC_SIZE_DIG 0x78 //
+#define DISPC_SIZE_LCD 0x7C //
+#define DISPC_GFX_BA 0x80 //
+#define DISPC_GFX_POS 0x88 //
+#define DISPC_GFX_SIZE 0x8C //
+#define DISPC_GFX_ATTR 0xA0 //
+#define DISPC_GFX_FIFO_TH 0xA4 //
+#define DISPC_GFX_FIFO_SS 0xA8 //
+#define DISPC_GFX_ROW_INC 0xAC //
+#define DISPC_GFX_PIX_INC 0xB0 //
+#define DISPC_GFX_WIN_SKIP 0xB4 //
+#define DISPC_GFX_TABLE_BA 0xB8 //
+#define DISPC_GFX_PRELOAD 0x62C //
+
diff --git a/ports/csb740/omap3530_mem.h b/ports/csb740/omap3530_mem.h
new file mode 100755
index 0000000..820873c
--- /dev/null
+++ b/ports/csb740/omap3530_mem.h
@@ -0,0 +1,184 @@
+//==========================================================================
+//
+// omap3530_mem.h
+//
+// Author(s): Luis Torrico, Cogent Computer Systems, Inc.
+// Contributors:
+// Date: 12/09/2008
+// Description: This file contains register base addresses and offsets
+// and access macros for the OMAP3530 Cortex-A8 memory controller
+//
+
+#include "bits.h"
+
+// The GPMC supports up to eight chip-select regions of programmable size, and programmable base
+// addresses in a total address space of 1 Gbyte.
+// Chip Select mapping for CSB740
+// CS0 = NOR = 0x08000000
+// CS1 = N/A
+// CS2 = N/A
+// CS3 = NAND = 0x18000000
+// CS4 = Ethernet = 0x2C000000
+// CS5 = Expansion = 0x28000000
+// CS6 = N/A
+// CS7 = N/A
+
+//#define OMAP35XX_GPMC_BASE 0x6E000000
+#define GPMC_REG(_x_) *(vulong *)(OMAP35XX_GPMC_BASE + _x_)
+#define MYGPMC_REG(_x_) (vulong *)(OMAP35XX_GPMC_BASE + _x_)
+
+// GPMC - General Purpose Memory Controller
+#define GPMC_SYS_CONFIG 0x10 // Chip Select 0 Upper Control Register
+#define GPMC_SYS_STATUS 0x14 // Chip Select 0 Lower Control Register
+#define GPMC_IRQ_STATUS 0x18 // Chip Select 0 Additional Control Register
+#define GPMC_IRQ_EN 0x1C // Chip Select 1 Upper Control Register
+#define GPMC_TIMEOUT 0x40 // Chip Select 1 Lower Control Register
+#define GPMC_ERR_ADD 0x44 // Chip Select 1 Additional Control Register
+#define GPMC_ERR_TYPE 0x48 // Chip Select 2 Upper Control Register
+#define GPMC_CONFIG 0x50 // Chip Select 2 Lower Control Register
+#define GPMC_STATUS 0x54 // Chip Select 2 Additional Control Register
+
+#define GPMC_CS0_CONFIG1 0x60 // Chip Select 3 Upper Control Register
+#define GPMC_CS0_CONFIG2 0x64 // Chip Select 3 Lower Control Register
+#define GPMC_CS0_CONFIG3 0x68 // Chip Select 3 Additional Control Register
+#define GPMC_CS0_CONFIG4 0x6C // Chip Select 4 Upper Control Register
+#define GPMC_CS0_CONFIG5 0x70 // Chip Select 4 Lower Control Register
+#define GPMC_CS0_CONFIG6 0x74 // Chip Select 4 Additional Control Register
+#define GPMC_CS0_CONFIG7 0x78 // Chip Select 5 Upper Control Register
+
+#define GPMC_CS1_CONFIG1 0x90 // Chip Select 5 Lower Control Register
+#define GPMC_CS1_CONFIG2 0x94 // Chip Select 5 Additional Control Register
+#define GPMC_CS1_CONFIG3 0x98 // Configuration Register
+#define GPMC_CS1_CONFIG4 0x9C // Chip Select 5 Lower Control Register
+#define GPMC_CS1_CONFIG5 0xA0 // Chip Select 5 Additional Control Register
+#define GPMC_CS1_CONFIG6 0xA4 // Configuration Register
+#define GPMC_CS1_CONFIG7 0xA8 // Configuration Register
+
+#define GPMC_CS2_CONFIG1 0xC0 // Chip Select 5 Lower Control Register
+#define GPMC_CS2_CONFIG2 0xC4 // Chip Select 5 Additional Control Register
+#define GPMC_CS2_CONFIG3 0xC8 // Configuration Register
+#define GPMC_CS2_CONFIG4 0xCC // Chip Select 5 Lower Control Register
+#define GPMC_CS2_CONFIG5 0xD0 // Chip Select 5 Additional Control Register
+#define GPMC_CS2_CONFIG6 0xD4 // Configuration Register
+#define GPMC_CS2_CONFIG7 0xD8 // Configuration Register
+
+#define GPMC_CS3_CONFIG1 0xF0 // Chip Select 5 Lower Control Register
+#define GPMC_CS3_CONFIG2 0xF4 // Chip Select 5 Additional Control Register
+#define GPMC_CS3_CONFIG3 0xF8 // Configuration Register
+#define GPMC_CS3_CONFIG4 0xFC // Chip Select 5 Lower Control Register
+#define GPMC_CS3_CONFIG5 0x100 // Chip Select 5 Additional Control Register
+#define GPMC_CS3_CONFIG6 0x104 // Configuration Register
+#define GPMC_CS3_CONFIG7 0x108 // Configuration Register
+
+#define GPMC_CS4_CONFIG1 0x120 // Chip Select 5 Lower Control Register
+#define GPMC_CS4_CONFIG2 0x124 // Chip Select 5 Additional Control Register
+#define GPMC_CS4_CONFIG3 0x128 // Configuration Register
+#define GPMC_CS4_CONFIG4 0x12C // Chip Select 5 Lower Control Register
+#define GPMC_CS4_CONFIG5 0x130 // Chip Select 5 Additional Control Register
+#define GPMC_CS4_CONFIG6 0x134 // Configuration Register
+#define GPMC_CS4_CONFIG7 0x138 // Configuration Register
+
+#define GPMC_CS5_CONFIG1 0x150 // Chip Select 5 Lower Control Register
+#define GPMC_CS5_CONFIG2 0x154 // Chip Select 5 Additional Control Register
+#define GPMC_CS5_CONFIG3 0x158 // Configuration Register
+#define GPMC_CS5_CONFIG4 0x15C // Chip Select 5 Lower Control Register
+#define GPMC_CS5_CONFIG5 0x160 // Chip Select 5 Additional Control Register
+#define GPMC_CS5_CONFIG6 0x164 // Configuration Register
+#define GPMC_CS5_CONFIG7 0x168 // Configuration Register
+
+#define GPMC_CS6_CONFIG1 0x180 // Chip Select 5 Lower Control Register
+#define GPMC_CS6_CONFIG2 0x184 // Chip Select 5 Additional Control Register
+#define GPMC_CS6_CONFIG3 0x188 // Configuration Register
+#define GPMC_CS6_CONFIG4 0x18C // Chip Select 5 Lower Control Register
+#define GPMC_CS6_CONFIG5 0x190 // Chip Select 5 Additional Control Register
+#define GPMC_CS6_CONFIG6 0x194 // Configuration Register
+#define GPMC_CS6_CONFIG7 0x198 // Configuration Register
+
+#define GPMC_CS7_CONFIG1 0x1B0 // Chip Select 5 Lower Control Register
+#define GPMC_CS7_CONFIG2 0x1B4 // Chip Select 5 Additional Control Register
+#define GPMC_CS7_CONFIG3 0x1B8 // Configuration Register
+#define GPMC_CS7_CONFIG4 0x1BC // Chip Select 5 Lower Control Register
+#define GPMC_CS7_CONFIG5 0x1C0 // Chip Select 5 Additional Control Register
+#define GPMC_CS7_CONFIG6 0x1C4 // Configuration Register
+#define GPMC_CS7_CONFIG7 0x1C8 // Configuration Register
+
+#define GPMC_PREFETCH_CONFIG1 0x1E0
+#define GPMC_PREFETCH_CONFIG2 0x1E4
+#define GPMC_PREFETCH_CONTROL 0x1EC
+#define GPMC_PREFETCH_STATUS 0x1F0
+
+// Bit Defines for OMAP3530 GPMC
+// WEIM_CS0U to WEIM_CS5U - Chip Select Upper Control Register
+#define WEIM_CSU_SP BIT31 // Supervisor Protect, 0 = User mode accesses allowed, 1 = User mode accesses prohibited
+#define WEIM_CSU_WP BIT30 // Write Protect, 0 = Writes allowed, 1 = Writes prohibited
+#define WEIM_CSU_BCD(_x_) ((_x_ & 0x03) << 28) // Burst Clock Divisor, when EIM_CFG_BCM = 0
+#define WEIM_CSU_BCS(_x_) ((_x_ & 0x03) << 24) // Burst Clock Start, # of 1/2 cycles from LBA to BCLK high
+#define WEIM_CSU_PSZ_4 (0 << 22) // page size = 4 words
+#define WEIM_CSU_PSZ_8 (1 << 22) // page size = 8 words
+#define WEIM_CSU_PSZ_16 (2 << 22) // page size = 16 words
+#define WEIM_CSU_PSZ_32 (3 << 22) // page size = 32 words
+#define WEIM_CSU_PME BIT21 // 1 = Enables page mode emulation
+#define WEIM_CSU_SYNC BIT20 // 1 = Enables synchronous burst mode
+#define WEIM_CSU_DOL(_x_) ((_x_ & 0x0f) << 16) // # of clocks -1 before latching read data when SYNC = 1
+#define WEIM_CSU_CNC_0 (0 << 14) // Hold CS negated after end of cycle for 0 clocks
+#define WEIM_CSU_CNC_1 (1 << 14) // Hold CS negated after end of cycle for 1 clock
+#define WEIM_CSU_CNC_2 (2 << 14) // Hold CS negated after end of cycle for 2 clocks
+#define WEIM_CSU_CNC_3 (3 << 14) // Hold CS negated after end of cycle for 3 clocks
+#define WEIM_CSU_WSC(_x_) ((_x_ & 0x3f) << 8) // Wait States, 0 = 2, 1 = 2, 2-62 = +1, 63 = dtack
+#define WEIM_CSU_WSC_DTACK (0x3f << 8) // Wait States, 0 = 2, 1 = 2, 2-62 = +1, 63 = dtack
+#define WEIM_CSU_EW BIT7 // Determines how WEIM supports the ECB input
+#define WEIM_CSU_WWS(_x_) ((_x_ & 0x07) << 4) // Additional wait states for write cycles
+#define WEIM_CSU_EDC(_x_) ((_x_ & 0x0f) << 0) // Dead Cycles after reads for bus turn around
+
+// Bit Defines for MCIMX31
+// WEIM_CS0L to WEIM_CS5L - Chip Select Lower Control Register
+#define WEIM_CSL_OEA(_x_) ((_x_ & 0x0f) << 28) // # of 1/2 cycles after CS asserts before OE asserts
+#define WEIM_CSL_OEN(_x_) ((_x_ & 0x0f) << 24) // # of 1/2 cycles OE negates before CS negates
+#define WEIM_CSL_WEA(_x_) ((_x_ & 0x0f) << 20) // # of 1/2 cycles EB0-3 assert before WE asserts
+#define WEIM_CSL_WEN(_x_) ((_x_ & 0x0f) << 16) // # of 1/2 cycles EB0-3 negate before WE negates
+#define WEIM_CSL_CSA(_x_) ((_x_ & 0x0f) << 12) // # of clocks address is asserted before CS and held after CS
+#define WEIM_CSL_EBC BIT11 // 0 = assert EB0-3 for Reads & Writes, 1 = Writes only
+#define WEIM_CSL_DSZ_BYTE_3 (0 << 8) // device is 8-bits wide, located on byte 3 (D31-24)
+#define WEIM_CSL_DSZ_BYTE_2 (1 << 8) // device is 8-bits wide, located on byte 2 (D23-16)
+#define WEIM_CSL_DSZ_BYTE_1 (2 << 8) // device is 8-bits wide, located on byte 1 (D15-8)
+#define WEIM_CSL_DSZ_BYTE_0 (3 << 8) // device is 8-bits wide, located on byte 0 (D7-0)
+#define WEIM_CSL_DSZ_HALF_1 (4 << 8) // device is 16-bits wide, located on half word 1 (D31-16)
+#define WEIM_CSL_DSZ_HALF_0 (5 << 8) // device is 16-bits wide, located on half word 1 (D15-0)
+#define WEIM_CSL_DSZ_WORD (6 << 8) // device is 32-bits wide, located on half word 1 (D15-0)
+#define WEIM_CSL_CSN(_x_) ((_x_ & 0x0f) << 4) // Chip Select Negate
+#define WEIM_CSL_PSR BIT3 // PSRAM Enable, 0 = disabled, 1 = enabled
+#define WEIM_CSL_CRE BIT2 // Control Register Enable
+#define WEIM_CSL_WRAP BIT1 // 0 = Memory in linear mode, 1 = Memory in wrap mode
+#define WEIM_CSL_CSEN BIT0 // 1 = Enable Chip Select
+
+// Bit Defines for MCIMX31
+// WEIM_CS0A to WEIM_CS5A - Chip Select Additional Control Register
+#define WEIM_CSA_EBRA(_x_) ((_x_ & 0x0f) << 28) // # of half AHB clock cycles before EB asserted.
+#define WEIM_CSA_EBRN(_x_) ((_x_ & 0x0f) << 24) // # of half AHB clock cycles between EB negation and end of access.
+#define WEIM_CSA_RWA(_x_) ((_x_ & 0x0f) << 20) // # of half AHB clock cycles RW delay
+#define WEIM_CSA_RWN(_x_) ((_x_ & 0x0f) << 16) // # of half AHB clock cycles between EB negation and end of access
+#define WEIM_CSA_MUM BIT15 // 1 = Muxed Mode
+#define WEIM_CSA_LAH_0 (0 << 13) // 0 AHB half clock cycles between LBA negation and address invalid
+#define WEIM_CSA_LAH_1 (1 << 13) // 1 AHB half clock cycles between LBA negation and address invalid
+#define WEIM_CSA_LAH_2 (2 << 13) // 2 AHB half clock cycles between LBA negation and address invalid
+#define WEIM_CSA_LAH_3 (3 << 13) // 3 AHB half clock cycles between LBA negation and address invalid
+#define WEIM_CSA_LBN(_x_) ((_x_ & 0x07) << 10) // This bit field determines when LBA is negated
+#define WEIM_CSA_LBA_0 (0 << 8) // 0 AHB half clock cycles between beginning of access and LBA assertion.
+#define WEIM_CSA_LBA_1 (1 << 8) // 1 AHB half clock cycles between beginning of access and LBA assertion.
+#define WEIM_CSA_LBA_2 (2 << 8) // 2 AHB half clock cycles between beginning of access and LBA assertion.
+#define WEIM_CSA_LBA_3 (3 << 8) // 3 AHB half clock cycles between beginning of access and LBA assertion.
+#define WEIM_CSA_DWW(_x_) ((_x_ & 0x03) << 6) // Decrease Write Wait State
+#define WEIM_CSA_DCT_0 (0 << 4) // 0 AHB clock cycles between CS assertion and first DTACK check.
+#define WEIM_CSA_DCT_1 (1 << 4) // 1 AHB clock cycles between CS assertion and first DTACK check.
+#define WEIM_CSA_DCT_2 (2 << 4) // 2 AHB clock cycles between CS assertion and first DTACK check.
+#define WEIM_CSA_DCT_3 (3 << 4) // 3 AHB clock cycles between CS assertion and first DTACK check.
+#define WEIM_CSA_WWU BIT3 // 1 = Allow wrap on write
+#define WEIM_CSA_AGE BIT2 // 1 = Enable glue logic
+#define WEIM_CSA_CNC2 BIT1 // Chip Select Negation Clock Cycles
+#define WEIM_CSA_FCE BIT0 // 1 = Data captured using BCLK_FB
+
+// WEIM_CFG - Configuration Register
+#define WEIM_CFG_BCM BIT2 // 1 = Burst Clock always on, 0 = when CS with SYNC = 1 is accessed
+#define WEIM_CFG_MAS BIT0 // 1 = Merged address space
+
+
diff --git a/ports/csb740/omap3530_sdmmc.c b/ports/csb740/omap3530_sdmmc.c
new file mode 100755
index 0000000..b542d4e
--- /dev/null
+++ b/ports/csb740/omap3530_sdmmc.c
@@ -0,0 +1,505 @@
+/* NOTE:
+ * THIS CODE IS NOT READY FOR USE YET!!!
+ */
+#include "config.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "timer.h"
+#include "omap3530.h"
+#include "sd.h"
+
+
+#define MMCTMOUT 2000
+
+/* This code is included here just for simulating the SD
+ * interface (temporarily if a real one isn't ready. In a real system,
+ * the INCLUDE_SD_DUMMY_FUNCS definition would be off.
+ */
+int
+xsdCmd(unsigned long cmd, unsigned short argh, unsigned short argl)
+{
+ vulong stat, rsp;
+ struct elapsed_tmr tmr;
+
+ printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24);
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use
+ while(MMC1_REG(MMCHS_PSTATE) & CMDI) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: CMDI timeout\n");
+ return(-1);
+ }
+ }
+
+ MMC1_REG(MMCHS_ARG) = ((argh << 16) | argl);
+ MMC1_REG(MMCHS_IE) = 0xfffffeff;
+ MMC1_REG(MMCHS_CMD) = cmd;
+
+again:
+ stat = MMC1_REG(MMCHS_STAT);
+ if (stat & CTO) {
+ if (stat & CCRC)
+ printf("cmdline in use\n");
+ else
+ printf("CTO1 CCRC0\n");
+ MMC1_REG(MMCHS_SYSCTL) |= SRC;
+ startElapsedTimer(&tmr,MMCTMOUT);
+ while(MMC1_REG(MMCHS_SYSCTL) & SRC) {
+ if(msecElapsed(&tmr))
+ printf("sdInit: SRC timeout\n");
+ }
+ return(-1);
+ }
+ if ((stat & CC) == 0)
+ goto again;
+
+ cmd = MMC1_REG(MMCHS_CMD);
+ if ((cmd & RSPTYPE) == RSPTYPE_NONE) {
+ printf("Success!\n");
+ return(0);
+ }
+
+ if ((cmd & RSPTYPE) == RSPTYPE_136) {
+ rsp = MMC1_REG(MMCHS_RSP10);
+ printf("RSP0: %04x, RSP1: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ rsp = MMC1_REG(MMCHS_RSP32);
+ printf("RSP2: %04x, RSP3: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ rsp = MMC1_REG(MMCHS_RSP54);
+ printf("RSP4: %04x, RSP5: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ rsp = MMC1_REG(MMCHS_RSP76);
+ printf("RSP6: %04x, RSP7: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ }
+ if ((cmd & RSPTYPE) == RSPTYPE_48) {
+ rsp = MMC1_REG(MMCHS_RSP10);
+ printf("RSP0: %04x, RSP1: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ rsp = MMC1_REG(MMCHS_RSP32);
+ printf("RSP2: %04x, RSP3: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ }
+ if ((cmd & RSPTYPE) == RSPTYPE_48BSY) {
+ rsp = MMC1_REG(MMCHS_RSP10);
+ printf("RSP0: %04x, RSP1: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ rsp = MMC1_REG(MMCHS_RSP32);
+ printf("RSP2: %04x, RSP3: %04x\n",
+ rsp & 0xffff,(rsp & 0xffff0000) >> 16);
+ }
+
+ return(0);
+}
+
+int
+sdCmd(unsigned long cmd, unsigned short argh, unsigned short argl)
+{
+ vulong stat, arg;
+ struct elapsed_tmr tmr;
+
+ printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24);
+
+ MMC1_REG(MMCHS_STAT) = 0xffffffff;
+ MMC1_REG(MMCHS_BLK) = NBLK(1) | BLEN(512);
+ MMC1_REG(MMCHS_SYSCTL) &= ~DTOMSK;
+ MMC1_REG(MMCHS_SYSCTL) |= DTO(14);
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use
+ while(MMC1_REG(MMCHS_PSTATE) & CMDI) {
+ if(msecElapsed(&tmr)) {
+ printf("sdCmd: CMDI timeout\n");
+ return(-1);
+ }
+ monDelay(1);
+ }
+
+ arg = argh;
+ arg <<= 16;
+ arg |= argl;
+ MMC1_REG(MMCHS_ARG) = arg;
+ MMC1_REG(MMCHS_IE) = 0xfffffeff;
+ MMC1_REG(MMCHS_CMD) = cmd;
+
+ startElapsedTimer(&tmr,MMCTMOUT);
+ do {
+ stat = MMC1_REG(MMCHS_STAT);
+ if (stat & CTO) {
+ if (stat & CCRC)
+ printf("CCRC1\n");
+ else
+ printf("CTO1 CCRC0\n");
+ MMC1_REG(MMCHS_SYSCTL) |= SRC;
+ startElapsedTimer(&tmr,MMCTMOUT);
+ while(MMC1_REG(MMCHS_SYSCTL) & SRC) {
+ if(msecElapsed(&tmr))
+ printf("sdCmd: SRC timeout\n");
+ }
+ return(-1);
+ }
+ if(msecElapsed(&tmr)) {
+ printf("sdCmd: CC timeout\n");
+ return(-1);
+ }
+ monDelay(1);
+ } while ((stat & CC) == 0);
+
+ stat = MMC1_REG(MMCHS_STAT);
+ if (stat & CCRC)
+ printf("Cmd crc\n");
+ if (stat & DCRC)
+ printf("Data crc\n");
+ if (stat & CERR) {
+ printf("Card error 0x%lx\n",stat);
+ return(-1);
+ }
+ if (stat & CTO) {
+ printf("CTO set!\n");
+ return(-1);
+ }
+ if (stat & CC) {
+ printf("Success!\n");
+ return(0);
+ }
+ else {
+ printf("Didn't complete!\n");
+ return(-1);
+ }
+}
+
+int
+sdClkSet(int clkval)
+{
+ vulong reg;
+ struct elapsed_tmr tmr;
+
+ MMC1_REG(MMCHS_SYSCTL) &= ~CEN;
+ reg = MMC1_REG(MMCHS_SYSCTL);
+ reg &= ~CLKDMSK;
+ reg |= CLKD(96000/clkval);
+ MMC1_REG(MMCHS_SYSCTL) = reg;
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable
+ while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) {
+ if(msecElapsed(&tmr)) {
+ printf("sdClkSet: ICS timeout\n");
+ return(-1);
+ }
+ monDelay(1);
+ }
+ MMC1_REG(MMCHS_SYSCTL) |= CEN;
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable
+ while((MMC1_REG(MMCHS_SYSCTL) & CEN) == 0) {
+ if(msecElapsed(&tmr)) {
+ printf("sdClkSet: ICS timeout\n");
+ return(-1);
+ }
+ monDelay(1);
+ }
+ return(0);
+}
+
+/* sdInit():
+ * This function is called by the "sd init" command on the command line.
+ * Where applicable, the text refers to the section in the Sept 2008
+ * Technical Reference Manual (TRM) from which I got the code/functionality.
+ */
+int
+sdInit(int interface, int verbose)
+{
+ int i, pbiasretry = 0;
+ vulong reg;
+ struct elapsed_tmr tmr;
+
+ /* There's only one interface on the CSB740, so reject anything
+ * other than interface 0...
+ */
+ if (interface != 0)
+ return(-1);
+
+ /*******************************
+ *
+ * Clock configuration:
+ * (TRM 22.5.1.1)
+ */
+ *(vulong *)CM_ICLKEN1_CORE |= EN_MMC1; // Configure interface and
+ *(vulong *)CM_FCLKEN1_CORE |= EN_MMC1; // functional clocks.
+
+ /*******************************
+ *
+ * Not really sure what this is... apparently some kind of clock steering.
+ * I tried both setting the bit and clearing it. Made no difference.
+ * In both cases the clock was present on the CLK pin.
+ */
+ *(vulong *)CONTROL_DEVCONF0 |= MMCSDIO1ADPCLKISEL;
+
+ /********************************
+ *
+ * Set up BIAS (this allows the pins to run at 1.8 or 3.0 volts I think).
+ * This is configured as 0606 in rom_reset.S (i don't think thats right).
+ * Note: The CSB703 ties this interface to 3.3 volts.
+ * TRM 22.5.3
+ * TRM 7.5.2 and flowchart in figure 7-24...
+ */
+pbias_retry:
+ *(vulong *)CONTROL_PBIAS_LITE = PBIAS_LITE_VMMC1_52MHZ;
+ monDelay(100);
+ *(vulong *)CONTROL_PBIAS_LITE |= MMC_PWR_STABLE;
+ monDelay(100);
+ if (*(vulong *)CONTROL_PBIAS_LITE & PBIAS_LITE_MMC1_ERROR) {
+ *(vulong *)CONTROL_PBIAS_LITE &= (~MMC_PWR_STABLE);
+ monDelay(100);
+ if (pbiasretry++ < 3) {
+ goto pbias_retry;
+ }
+ else {
+ printf("sdInit: PBIAS timeout\n");
+ return(-1);
+ }
+ }
+
+#if 0
+ /*******************************
+ *
+ * These registers are things I found when scouring the TRM for "MMC".
+ * I don't think they have any affect on basic startup of the interface
+ * so they are removed for now...
+ */
+ *(vulong *)CM_AUTOIDLE1_CORE &= ~AUTO_MMC1; // Disable auto clock enable
+ *(vulong *)PM_WKEN1_CORE &= ~EN_MMC1; // Disable wakeup event
+ *(vulong *)PM_MPUGRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable mpu-group wakeup
+ *(vulong *)PM_IVA2GRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable iva2-group wakeup
+ *(vulong *)PM_WKST1_CORE &= ~EN_MMC1; // Clear wakeup status
+#endif
+
+ /*******************************
+ *
+ * Issue soft reset and wait for completion...
+ * (TRM 22.5.1.2)
+ */
+ MMC1_REG(MMCHS_SYSCONFIG) |= SRESET; // Software reset
+ if ((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0)
+ printf("Good, RESETDONE is low here\n");
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for completion
+ while((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: SRST failed\n");
+ return(-1);
+ }
+ }
+ /********************************
+ *
+ * Set SRA bit, then wait for it to clear.
+ */
+ MMC1_REG(MMCHS_SYSCTL) |= SRA;
+ startElapsedTimer(&tmr,MMCTMOUT);
+ while((MMC1_REG(MMCHS_SYSCTL) & SRA)) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: SRA timeout\n");
+ return(-1);
+ }
+ }
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for debounce stable.
+ while((MMC1_REG(MMCHS_PSTATE) & DEBOUNCE) != DEBOUNCE) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: DEBOUNCE timeout\n");
+ return(-1);
+ }
+ }
+
+ /*******************************
+ *
+ * Establish hardware capabilities:
+ * TRM 22.5.1.3
+ */
+ reg = MMC1_REG(MMCHS_CAPA);
+ reg &= ~(VS18 | VS30 | VS33);
+ reg |= VS18;
+ MMC1_REG(MMCHS_CAPA) = reg;
+
+#if 0
+ /********************************
+ *
+ * Enable wakeup mode (don't think I need this, tried both ways)
+ * TRM 22.5.1.4
+ */
+ MMC1_REG(MMCHS_SYSCONFIG) |= ENWAKEUP;
+ MMC1_REG(MMCHS_HCTL) |= IWE;
+#endif
+
+ /********************************
+ *
+ * MMC Host and Bus Configuration
+ * TRM 22.5.1.5
+ */
+ //MMC1_REG(MMCHS_CON) =
+ MMC1_REG(MMCHS_HCTL) &= ~SVDS;
+ MMC1_REG(MMCHS_HCTL) |= SVDS18;
+ monDelay(10);
+ MMC1_REG(MMCHS_HCTL) |= SDBP;
+ monDelay(100);
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for SVDS verification
+ while((MMC1_REG(MMCHS_HCTL) & SDBP) == 0) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: SDBP timeout\n");
+ return(-1);
+ }
+ }
+
+ MMC1_REG(MMCHS_SYSCTL) |= ICE; // Enable internal clock
+
+ MMC1_REG(MMCHS_SYSCTL) &= ~CLKDMSK; // Set clock divisor:
+ MMC1_REG(MMCHS_SYSCTL) |= CLKD(960); // (should be <= 80Khz initially)
+
+ startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable
+ while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: ICS timeout\n");
+ return(-1);
+ }
+ }
+
+ /* I set these two bits with the hope that the clock will be
+ * active even if there is no card installed (so I atleast can
+ * see *some* activity).
+ */
+ MMC1_REG(MMCHS_SYSCTL) |= CEN; // External clock enable
+#if 0
+ MMC1_REG(MMCHS_CON) |= CLKEXTFREE;
+
+ reg = MMC1_REG(MMCHS_SYSCONFIG);
+ reg &= ~SIDLEMODEMSK;
+ reg &= ~CLKACTIVITYMSK;
+ reg &= ~AUTOIDLE;
+ reg |= (SIDLEMODE(1) | CLKACTIVITY(3));
+ MMC1_REG(MMCHS_SYSCONFIG) = reg;
+#endif
+
+ /********************************
+ *
+ * Set the INIT bit to send an initialization stream to the card...
+ * (top of left flowchart in TRM section 22.5.2.1)
+ */
+ MMC1_REG(MMCHS_CON) |= MMCINIT;
+ for(i=0;i<10;i++) {
+ sdCmd(CMD(0) | RSPTYPE_NONE,0,0);
+ monDelay(2);
+ }
+ MMC1_REG(MMCHS_CON) &= ~MMCINIT;
+ MMC1_REG(MMCHS_STAT) = 0xffffffff;
+
+ if (sdClkSet(400) != 0)
+ return(-1);
+
+ /* this is the get_card_type() function in the code from TI...
+ */
+ if (sdCmd(CMD(55) | RSPTYPE_48,0,0) < 0) {
+ printf("Card type = MMC\n");
+ MMC1_REG(MMCHS_CON) |= ODE;
+ }
+ else {
+ if ((MMC1_REG(MMCHS_RSP10) & 0xffff) == 0x0120) {
+ printf("Card type = SD\n");
+ }
+ else {
+ printf("Card type = MMC_CARD\n");
+ MMC1_REG(MMCHS_CON) |= ODE;
+ }
+ }
+
+
+#if 0
+ /********************************
+ *
+ * Send Command 5
+ * (top of right flowchart in TRM section 22.5.2.1)
+ */
+ sdCmd(CMD(5) | RSPTYPE_NONE,0,0);
+
+ startElapsedTimer(&tmr,MMCTMOUT);
+ do {
+ reg = MMC1_REG(MMCHS_STAT);
+ if (reg & CC) {
+ /* For now we assume only SD cards... */
+ printf("SDIO detected!!! Shouldn't be here!\n");
+ return(-1);
+ }
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: CTO timeout1\n");
+ return(-1);
+ }
+
+ } while((reg & CTO) == 0);
+
+ /********************************
+ *
+ * Set SRC bit, then wait for it to clear.
+ * (midway down right flowchart in TRM section 22.5.2.1)
+ */
+ MMC1_REG(MMCHS_SYSCTL) |= SRC;
+ startElapsedTimer(&tmr,MMCTMOUT);
+ while((MMC1_REG(MMCHS_SYSCTL) & SRC)) {
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: SRC timeout\n");
+ return(-1);
+ }
+ }
+
+ sdCmd(CMD(8) | RSPTYPE_NONE,0,0);
+
+ startElapsedTimer(&tmr,MMCTMOUT);
+ do {
+ reg = MMC1_REG(MMCHS_STAT);
+ if (reg & CC) {
+ /* For now we assume only SD cards... */
+ printf("SD BINGO!!! This is where we want to be!\n");
+ return(0);
+ }
+ if(msecElapsed(&tmr)) {
+ printf("sdInit: CTO timeout2\n");
+ return(-1);
+ }
+
+ } while((reg & CTO) == 0);
+
+ /* For now we assume only SD cards... */
+ printf("MMC detected!!! Shouldn't be here!\n");
+#endif
+ return(-1);
+}
+
+int
+sdRead(int interface, char *buf, int blk, int blkcnt)
+{
+ char *from;
+ int size;
+
+ if (interface != 0)
+ return(-1);
+
+ from = (char *)(blk * SD_BLKSIZE);
+ size = blkcnt * SD_BLKSIZE;
+ memcpy(buf,from,size);
+ return(0);
+}
+
+int
+sdWrite(int interface, char *buf, int blk, int blkcnt)
+{
+ char *to;
+ int size;
+
+ if (interface != 0)
+ return(-1);
+
+ to = (char *)(blk * SD_BLKSIZE);
+ size = blkcnt * SD_BLKSIZE;
+ memcpy(to,buf,size);
+ return(0);
+}
+
diff --git a/ports/csb740/ram_reset.S b/ports/csb740/ram_reset.S
new file mode 100755
index 0000000..f801b19
--- /dev/null
+++ b/ports/csb740/ram_reset.S
@@ -0,0 +1,211 @@
+ .file "ram_reset.s"
+
+/*
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Author: Ed Sutter
+ * email: esutter@lucent.com
+ * phone: 908-582-2351
+ *
+ *
+ * Modified for the CSB740 - OMAP3530 Single Board
+ *
+ * ram_reset.s:
+ */
+
+#include "warmstart.h"
+#include "omap3530.h"
+#include "config.h"
+
+ /*
+ * Have a separate stack for each processor mode.
+ */
+
+ /* define sizes for each mode's stack */
+ .equ FiqStackSz, 4096
+ .equ IrqStackSz, 4096
+ .equ AbtStackSz, 4096
+ .equ UndStackSz, 4096
+ .equ SysStackSz, 4096
+
+ /* declare the stacks */
+ .extern MonStack
+ .global FiqStack
+ .global IrqStack
+ .global AbtStack
+ .global UndStack
+ .global SysStack
+
+ /* allocate the stacks */
+ .comm FiqStack, FiqStackSz /* for the FIQ mode */
+ .comm IrqStack, IrqStackSz /* for the IRQ mode */
+ .comm AbtStack, AbtStackSz /* for the Abort mode */
+ .comm UndStack, UndStackSz /* for the Undef mode */
+ .comm SysStack, SysStackSz /* for the System mode */
+ /* User mode has the same stack as system mode. */
+
+/*********************************************************************/
+
+ .extern start
+
+ .global reset
+ .global coldstart
+ .global lukewarmstart
+ .global warmstart
+ .global ipaddr
+ .global etheraddr
+ .global moncomptr
+
+ .text
+
+ /*
+ * Exception table at address 0
+ */
+reset:
+ b coldstart
+ b undefined_instruction
+ b software_interrupt
+ b abort_prefetch
+ b abort_data
+ b not_assigned
+ b interrupt_request
+ b fast_interrupt_request
+
+#include "etheraddr.S"
+#include "moncomptr.S"
+
+/*********************************************************************/
+
+ /*
+ * At the end of the reset sequence, MMU, Icache, Dcache,
+ * and write buffer are all disabled.
+ * Also IRQs and FIQs are disabled in the processor's CPSR
+ * The operating mode is SVC (supervisory mode), and the
+ * PC is vectored at 0x00000000. A branch in 0x00000000
+ * brings us directly here.
+ *
+ */
+
+coldstart:
+// ldr r0, =0x2001 /* allow access to all coprocessors */
+// mcr p15,0,r0,c15,c1,0
+// nop
+// nop
+// nop
+
+// ldr r0, =0x00000078
+// mcr p15,0,r0,c1,c0,0 /* Disable MMU, caches, write buffer */
+// nop
+// nop
+// nop
+
+// ldr r0, =0x00000000
+// mcr p15,0,r0,c8,c7,0 /* flush TLB's */
+// mcr p15,0,r0,c7,c7,0 /* flush Caches */
+// mcr p15,0,r0,c7,c10,4 /* Flush Write Buffer */
+// nop
+// nop
+// nop
+
+// mvn r0, #0 /* grant manager access to all domains */
+// mcr p15,0,r0,c3,c0,0
+
+/********************************************************************/
+
+midstart:
+ ldr r0, =INITIALIZE
+
+ /* fall-through to 'lukewarmstart' */
+
+/********************************************************************/
+
+lukewarmstart:
+ /* Save the argument to r11 */
+ mov r11, r0
+
+ /*
+ * *** DO NOT TOUCH R11 ***
+ */
+
+ /*
+ * Set-up the stack-pointers for all operating modes
+ */
+
+ /* FIQ mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x11 /* set FIQ mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */
+ /* IRQ mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x12 /* set IRQ mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */
+ /* Abort mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x17 /* set Abort mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */
+ /* Undef mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x1b /* set Undef mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */
+ /* System mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x1f /* set System mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */
+ /* 'warmstart' will take us back to SVC mode
+ stack for SVC mode will also be setup in warmstart */
+
+ mov r0, r11 /* get argument back from r11 */
+
+ b warmstart
+
+
+/********************************************************************/
+
+warmstart:
+ /* Save the argument to r11 */
+ mov r11, r0
+
+ /*
+ * *** DO NOT TOUCH R11 ***
+ */
+
+
+ /* Change (back) to SVC mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x13 /* set System mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ /* Reset the stack pointer for the SVC mode (our current mode) */
+ ldr sp, =(MonStack + MONSTACKSIZE - 4)
+
+ /*
+ * Restore argument which was saved to r11 and jump to
+ * the C function start().
+ */
+
+ mov r0, r11
+jump_to_c:
+ bl start
+
+ /* the C code should never return */
+ b reset
+
+.align 4
+
diff --git a/ports/csb740/regnames.c b/ports/csb740/regnames.c
new file mode 100755
index 0000000..9c4747e
--- /dev/null
+++ b/ports/csb740/regnames.c
@@ -0,0 +1 @@
+#include "regs_arm.c"
diff --git a/ports/csb740/rom_reset.S b/ports/csb740/rom_reset.S
new file mode 100755
index 0000000..d2c9cfb
--- /dev/null
+++ b/ports/csb740/rom_reset.S
@@ -0,0 +1,418 @@
+ .file "rom_reset.S"
+
+/*
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Author: Ed Sutter
+ * email: esutter@lucent.com
+ * phone: 908-582-2351
+ *
+ *
+ * Modified for the CSB740 - OMAP3530 Single Board
+ *
+ * rom_reset.s:
+ */
+
+#include "warmstart.h"
+#include "omap3530.h"
+#include "config.h"
+
+ /*
+ * Have a separate stack for each processor mode.
+ */
+
+ /* define sizes for each mode's stack */
+ .equ FiqStackSz, 4096
+ .equ IrqStackSz, 4096
+ .equ AbtStackSz, 4096
+ .equ UndStackSz, 4096
+ .equ SysStackSz, 4096
+
+ /* declare the stacks */
+ .extern MonStack
+ .global FiqStack
+ .global IrqStack
+ .global AbtStack
+ .global UndStack
+ .global SysStack
+ .global raise
+ .global cache_init
+
+ /* allocate the stacks */
+ .comm FiqStack, FiqStackSz /* for the FIQ mode */
+ .comm IrqStack, IrqStackSz /* for the IRQ mode */
+ .comm AbtStack, AbtStackSz /* for the Abort mode */
+ .comm UndStack, UndStackSz /* for the Undef mode */
+ .comm SysStack, SysStackSz /* for the System mode */
+ /* User mode has the same stack as system mode. */
+
+/*********************************************************************/
+
+ .extern start
+
+ .global reset
+ .global coldstart
+ .global lukewarmstart
+ .global warmstart
+
+ .text
+
+ /*
+ * Exception table at address 0
+ */
+reset:
+ b coldstart
+ b undefined_instruction
+ b software_interrupt
+ b abort_prefetch
+ b abort_data
+ b not_assigned
+ b interrupt_request
+ b fast_interrupt_request
+
+#include "etheraddr.S"
+#include "moncomptr.S"
+#include "alttfsdevtbl.S"
+
+coldstart:
+ ldr pc, =coldstart_1 // jump to actual ROM location
+ nop
+
+coldstart_1:
+ /* Make sure interrupts are off, and we're in supervisor mode...
+ */
+ mrs r0,cpsr // Retreive current program status register
+ bic r0,r0,#0x1f // Clear all mode bits.
+ orr r0,r0,#0xd3 // Set mode to supervisor, IRQ FIQ disabled.
+ msr cpsr,r0
+
+// bl cache_init
+
+//----------------------------------------------------------
+// Start of Cogent Setup for CSB740 OMAP3530
+//----------------------------------------------------------
+
+init_pbias:
+ ldr r2, =0x00000000 // set bias for sdio1
+ ldr r1, =0x48002520
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000606 // set bias for sdio1
+ ldr r1, =0x48002520
+ str r2, [r1]
+
+ bl delay_200
+init_clocks:
+ ldr r2, =0x00000037 // Enable DPLL1 in lock mode
+ ldr r1, =0x48004904
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x000A7115 // Set DPLL1 (MPU) M = 625, (N +1)= 21 + 1, MPU_CLK = ~545MHz
+ ldr r1, =0x48004940
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x099F1700 // Set DPLL3 (CORE) M = 415, (N +1)= 23 + 1, CORE_CLK = ~332MHz
+ ldr r1, =0x48004D40
+ str r2, [r1]
+
+ bl delay_200
+
+ //ldr r2, =0x00000080 // Enable SYS_CLKOUT2 for debug purposes
+ //ldr r1, =0x48004D70
+ //str r2, [r1]
+
+ //bl delay_200
+
+ ldr r2, =0x43fffe00 // Turn on all available module clocks
+ ldr r1, =0x48004a00
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x7ffffedb // Turn on all available peripheral clocks
+ ldr r1, =0x48004a10
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00006000 // enable auto clock for UART1 and UART2
+ ldr r1, =0x48004a30
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000028 // enable WDT2 and GPIO 1 functional clock
+ ldr r1, =0x48004c00
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x0000002c // enable WDT2, GPIO 1 interface and 32Ksync (for Linux) clock
+ ldr r1, =0x48004c10
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x0003E000 // enable GPIO 2-6 functional clocks
+ ldr r1, =0x48005000
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x0003E000 // enable GPIO 2-6 interface clocks
+ ldr r1, =0x48005010
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000003 // enable DSS1_ALWON_FCLK
+ ldr r1, =0x48004e00
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000001 // enable DSS interface clock
+ ldr r1, =0x48004e10
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x0000100A // Set CLKSEL_DSS1 to divide by 1
+ ldr r1, =0x48004e40
+ str r2, [r1]
+
+ bl delay_200
+
+init_ddr:
+ ldr r2, =0x0000001A // reset DDR
+ ldr r1, =0x6D000010
+ str r2, [r1]
+
+ ldr r1, =0x6D000014 // SDRC_SYSSTATUS
+wait_reset:
+ ldr r2, [r1]
+ tst r2, #1 // test RESETDONE
+ beq wait_reset
+
+ ldr r2, =0x00000018 // release DDR reset
+ ldr r1, =0x6D000010
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000100 // 32-bit SDRAM on data lane [31:0] - CS0
+ ldr r1, =0x6D000044
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x02584099 // SDRC_MCFG0 register
+ ldr r1, =0x6D000080
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00054601 // SDRC_RFR_CTRL0 register
+ ldr r1, =0x6D0000a4
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0xA29DB4C6 // SDRC_ACTIM_CTRLA0 register
+ ldr r1, =0x6D00009c
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00012214 // SDRC_ACTIM_CTRLB0 register
+ ldr r1, =0x6D0000A0
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000081 // Disble Power Down of CKE due to 1 CKE on combo part
+ ldr r1, =0x6D000070
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000000 // NOP command
+ ldr r1, =0x6D0000A8
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000001 // Precharge command
+ ldr r1, =0x6D0000A8
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000002 // Auto-refresh command
+ ldr r1, =0x6D0000A8
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000002 // Auto-refresh command
+ ldr r1, =0x6D0000A8
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x00000032 // SDRC MR0 register Burst length=4
+ ldr r1, =0x6D000084
+ str r2, [r1]
+
+ bl delay_200
+
+ ldr r2, =0x0000000A // SDRC DLLA control register
+ ldr r1, =0x6D000060
+ str r2, [r1]
+
+ bl delay_200
+
+/********************************************************************/
+
+midstart:
+ ldr r0, =INITIALIZE
+
+ /* fall-through to 'lukewarmstart' */
+
+/********************************************************************/
+
+lukewarmstart:
+ /* Save the argument to r11 */
+ mov r11, r0
+
+ /*
+ * *** DO NOT TOUCH R11 ***
+ */
+
+ /*
+ * Set-up the stack-pointers for all operating modes
+ */
+
+ /* FIQ mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x11 /* set FIQ mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */
+ /* IRQ mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x12 /* set IRQ mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */
+ /* Abort mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x17 /* set Abort mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */
+ /* Undef mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x1b /* set Undef mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */
+ /* System mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x1f /* set System mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */
+ /* 'warmstart' will take us back to SVC mode
+ stack for SVC mode will also be setup in warmstart */
+
+ mov r0, r11 /* get argument back from r11 */
+ b warmstart
+
+
+/********************************************************************/
+
+warmstart:
+ /* Save the argument to r11 */
+ mov r11, r0
+
+ /*
+ * *** DO NOT TOUCH R11 ***
+ */
+
+
+ /* Change (back) to SVC mode */
+ mrs r0, cpsr /* move CPSR to r0 */
+ bic r0, r0, #0x1f /* clear all mode bits */
+ orr r0, r0, #0x13 /* set System mode bits */
+ msr CPSR_c, r0 /* move back to CPSR */
+ /* Reset the stack pointer for the SVC mode (our current mode) */
+ ldr sp, =(MonStack + MONSTACKSIZE - 4)
+
+ /*
+ * Restore argument which was saved to r11 and jump to
+ * the C function start().
+ */
+
+ mov r0, r11
+jump_to_c:
+ bl start
+
+ /* the C code should never return */
+ b reset
+
+.align 4
+
+
+/*********************************************************************
+ * simple delay loop
+ */
+delay_200:
+ ldr r3, =200 /* loop count */
+delay_loop:
+ subs r3,r3,#1
+ bne delay_loop
+ nop
+
+ mov pc, lr
+
+raise: mov pc, lr /* to make linker happy */
+
+/*********************************************************************
+ * Cache initialization:
+ * Turn everything down and invalidate...
+ */
+cache_init:
+ /* Make sure caches are turned down...
+ */
+ mrc p15, 0, r3, cr1, cr0, 0 // turn off I/D-cache
+ bic r3, r3, #4096 // I
+ bic r3, r3, #4 // D
+ mcr p15, 0, r3, cr1, cr0, 0
+
+ mov r0, #0
+// mcr p15, 0, r0, cr7, cr7, 0 // arm_cache_invalidate
+ mcr p15, 0, r0, cr7, cr6, 0 // arm_dcache_invalidate
+ mcr p15, 0, r0, cr7, cr5, 0 // arm_icache_invalidate
+
+ mrc p15, 0, r0, cr1, cr0, 1 // l2cache_disable
+ bic r0, r0, #2
+ mcr p15, 0, r0, cr1, cr0, 1
+
+ mov r0, #1
+ mrc p15, 1, r0, cr0, cr0, 1 // emu_ext_boot_l2_inv
+ mov pc, lr
+
diff --git a/ports/csb740/target_version.h b/ports/csb740/target_version.h
new file mode 100755
index 0000000..4abd503
--- /dev/null
+++ b/ports/csb740/target_version.h
@@ -0,0 +1,17 @@
+/* target_version.h:
+ * Initial version for all ports is zero. As the TARGET_VERSION incrments
+ * as a result of changes made to the target-specific code, this file should
+ * be used as an informal log of those changes for easy reference by others.
+ *
+ * 0: UART/DRAM/FLASH/TFS working through BDI2000
+ * 0->1: Boots from flash (without bdi2000), sleep delay adjusted.
+ * 1->2: Ethernet added.
+ * 2->3: LCD interface added.
+ * 3->4: Flash driver fix, enabled INCLUDE_HWTMR, and added show_version(),
+ * and the splash screen is loaded from TFS.
+ * 4->5: Added support for the FBI (frame buffer) interface, and hard-reset.
+ * 5->6: Speedup (clock configuration) provided by Luis; also changed
+ * cpuio.c so that SPI-mode of the touch-screen interface now works.
+ */
+
+#define TARGET_VERSION 6
diff --git a/ports/csb740/tfsdev.h b/ports/csb740/tfsdev.h
new file mode 100755
index 0000000..4331851
--- /dev/null
+++ b/ports/csb740/tfsdev.h
@@ -0,0 +1,31 @@
+/* tfsdev.h:
+ This file is ONLY included by tfs.c. It is seperate from tfs.h because
+ it is target-specific. It is not part of config.h because it includes
+ the declaration of the tfsdevtbl[].
+ A prefix in the name of the file determines what device is used to store
+ that file. If no prefix is found the the first device in the table is
+ used as a default. The syntax of the prefix is "//STRING/" where STRING
+ is user-definable, but the initial // and final / are required by tfs
+ code.
+*/
+
+struct tfsdev tfsdevtbl[] = {
+ { "//FLASH/",
+ TFSSTART,
+ TFSEND,
+ TFSSPARE,
+ TFSSPARESIZE,
+ TFSSECTORCOUNT,
+ TFS_DEVTYPE_FLASH, },
+
+#ifdef FLASHRAM_BASE
+ { "//RAM/",
+ FLASHRAM_BASE,
+ FLASHRAM_END-FLASHRAM_SECTORSIZE,
+ FLASHRAM_END-FLASHRAM_SECTORSIZE+1,
+ FLASHRAM_SECTORSIZE,
+ FLASHRAM_SECTORCOUNT-1,
+ TFS_DEVTYPE_RAM | TFS_DEVINFO_AUTOINIT, },
+#endif
+ { 0, TFSEOT,0,0,0,0,0 }
+};
diff --git a/ports/csb740/xcmddcl.h b/ports/csb740/xcmddcl.h
new file mode 100755
index 0000000..13552a3
--- /dev/null
+++ b/ports/csb740/xcmddcl.h
@@ -0,0 +1,34 @@
+
+/* extcmddcl.h: */
+/* This file must exist even if it is empty because it is #included in the */
+/* common file cmdtbl.c. The purpose is to keep the common comand table */
+/* file (common/cmdtbl.c) from being corrupted with non-generic commands */
+/* that may be target specific. */
+/* It is the declaration portion of the code that must be at the top of */
+/* the cmdtbl[] array. */
+/* For example:
+
+extern int dummycmd(); Function declaration.
+extern char *dummyHelp[]; Command help array declaration.
+
+*/
+
+extern int date();
+extern char *dateHelp[];
+
+#if INCLUDE_LCD
+extern int lcd_tst();
+extern char *lcd_tstHelp[];
+#endif
+
+//extern int i2c();
+//extern char *i2cHelp[];
+
+extern int nandCmd();
+extern char *nandHelp[];
+
+extern int ads();
+extern char *adsHelp[];
+
+extern int ldatags();
+extern char *ldatagsHelp[];
diff --git a/ports/csb740/xcmdtbl.h b/ports/csb740/xcmdtbl.h
new file mode 100755
index 0000000..334218c
--- /dev/null
+++ b/ports/csb740/xcmdtbl.h
@@ -0,0 +1,19 @@
+/* extcmdtbl.h: */
+/* This file must exist even if it is empty because it is #included in the */
+/* common file cmdtbl.c. The purpose is to keep the common comand table */
+/* file (common/cmdtbl.c) from being corrupted with non-generic commands */
+/* that may be target specific. */
+/* It is the entry in the command table representing the new command being */
+/* added to the cmdtbl[] array. */
+/* For example:
+ "dummy", dummycmd, dummyHelp,
+*/
+{"ads", ads, adsHelp,},
+//{"i2c", i2c, i2cHelp,},
+#if INCLUDE_LCD
+{"lcd_tst", lcd_tst, lcd_tstHelp,},
+#endif
+{"ldatags", ldatags, ldatagsHelp,},
+#if INCLUDE_NANDCMD
+{"nand", nandCmd, nandHelp,},
+#endif
diff --git a/ports/template/OLD_TO_NEW.txt b/ports/template/OLD_TO_NEW.txt
new file mode 100644
index 0000000..e0ce7e3
--- /dev/null
+++ b/ports/template/OLD_TO_NEW.txt
@@ -0,0 +1,100 @@
+##################################################################
+#
+# Converting an old-style (pre uMon1.0) monitor port over to the new
+# uMon1.0 structure...
+#
+1. Copy old to new, remove vssver.scc and make all files writeable.
+2. Run d2u on all files and change all .s files to .S.
+3. Using a bashrc file from another port directory as a reference,
+ convert the old file over to the new format. Also, if necessary,
+ change the name from ".bashrc" to "bashrc".
+4. Remove the obj directory.
+5. Move makefile to omakefile.
+6. Create a new target_version.h file... Copy from some other target
+ and start with version 1.
+7. Create new makefile...
+
+ TOPDIR = $(UMONTOP)
+ PLATFORM = copy from omakefile
+ TGTDIR = copy from omakefile
+ FILETYPE = elf | coff | aout
+ CPUTYPE = arm | m68k | mips | ppc | sh
+ CUSTOM_CFLAGS = -mcpu=XXX (at least)
+ CUSTOM_AFLAGS = -mcpu=XXX (at least)
+
+8. Establish the memory map. For each hard-coded address in the
+ .lnk files... create a variable name and set up the variable
+ to equal the hard-coded value in the makefile. In the .lnk file
+ replace the hard-coded address with the variable name. For example,
+ replace the following lines in the .lnk file...
+
+ flash : ORIGIN = 0xFF800000, LENGTH = 0x0007FFFF
+ ram : ORIGIN = 0x00000400, LENGTH = 0x0001FBFF
+
+ with:
+
+ flash : ORIGIN = FLASHBASE, LENGTH = FLASHLEN
+ ram : ORIGIN = RAMBASE, LENGTH = RANLEN
+
+ and then add these variable initializations to the makefile:
+
+ FLASHBASE = 0xFF800000
+ FLASHLEN = 0x0007FFFF
+ RAMBASE = 0x00000400
+ RANLEN = 0x0001FBFF
+
+ then change the name of the .lnk file from *.lnk to *.ldt. This
+ file will be used as the loader template (.ldt) file and the actual
+ linker map file (*.ld) will be created at build time by the vsub
+ tool.
+ Also, if there are any references to object files in the .lnk file,
+ remove the "obj/" directory path prefix. That isn't used anymore.
+ Finally, the filenames should be "PLATFORM_rule.ldt", where "PLATFORM"
+ is the value assigned to the PLATFORM variable in the makefile and "rule"
+ is the rule in the makefile that uses that map file. So, if "boot" is
+ the rule and its for the CSB337, then the filename would be
+ CSB337_boot.ldt. This naming convention must be followed for the
+ makefile to use the pre-defined variables and rules provided by the
+ xxx.make files that come with the main tree.
+
+9. Include the common.make file...
+
+ include $(TOPDIR)/target/make/common.make
+
+10. Establish the directory that is the base location of the flash
+ device driver source. In most cases this will be $(COMBASE)/flash/devices
+ for the newer device driver model; however, the directories under
+ $(COMBASE)/flash/boards does have valid drivers as well.
+
+ FLASHDIR = $(COMBASE)/flash/devices
+
+11. Now convert the OBJS list to several smaller lists as follows
+ (refer to some similar target makefile for reference). Note
+ that there are a few new files as of uMon1.0, so also refer to
+ the list in this template makefile:
+
+ LOCSSRC: local assembler source (.S files)
+ LOCCSRC: local C source code.
+ CPUSSRC: CPU-specific assembler source which is found under the
+ directory specified by the $(CPUTYPE) variable above.
+ COMSRC: all of the source that is to be pulled in from the core
+ code directory.
+ CPUCSRC: CPU-specific C source code.
+ IODEVSRC:Device driver code found under $(COMBASE)/iodev
+ COMCSRC: Common C code found under $(COMBASE)/core
+ FLASHSRC: Flash driver C source files in the FLASHDIR.
+
+12. Include the common objects.make file...
+
+include $(TOPDIR)/target/make/objects.make
+
+13. Build the objects list...
+
+OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \
+ $(FLASHOBJ) $(IODEVOBJ)
+
+14. Use the new cpuio.c and config.h files in this directory as an
+ example of the rework needed to the current files.
+
+15. Make sure that the stack uses the MonStack array and the MONSTACKSIZE
+ specified in config.h.
diff --git a/ports/template/README.txt b/ports/template/README.txt
new file mode 100644
index 0000000..977e99b
--- /dev/null
+++ b/ports/template/README.txt
@@ -0,0 +1,10 @@
+This is a template directory (or starting point) for a MicroMonitor
+port. If you are transitioning from a pre-1.0 version of MicroMonitor
+then you can refer to the OLD_TO_NEW.txt file for steps on how to
+convert the makefile.
+
+Refer to the text in the makefile for detailed information on the
+structure of the makefile.
+
+Refer to reset.s for basic bootup (assembler) initialization.
+Refer to cpuio.c for port-specific 'C' level startup functions.
diff --git a/ports/template/TEMPLATE_boot.ldt b/ports/template/TEMPLATE_boot.ldt
new file mode 100644
index 0000000..cda955f
--- /dev/null
+++ b/ports/template/TEMPLATE_boot.ldt
@@ -0,0 +1,69 @@
+/* Linker file for building monitor using GNU toolset on PC...
+
+ General notice:
+ This code is part of a boot-monitor package developed as a generic base
+ platform for embedded system designs. As such, it is likely to be
+ distributed to various projects beyond the control of the original
+ author. Please notify the author of any enhancements made or bugs found
+ so that all may benefit from the changes. In addition, notification back
+ to the author will allow the new user to pick up changes that may have
+ been made by other users after this version of the code was distributed.
+
+ Author: Ed Sutter
+ email: esutter@lucent.com
+ phone: 908-582-2351
+
+*/
+
+MEMORY
+{
+ ram (RWX): org = BOOTRAMBASE, len = BOOTRAMLEN
+ rom (RWX): org = BOOTROMBASE, len = BOOTROMLEN
+ resetv (RWX): org = 0xfffffff0, len = 0x10
+}
+
+SECTIONS
+{
+ .bss :
+ {
+ bss_start = .;
+ *(.bss) *(COMMON)
+ } >ram
+
+ .sbss :
+ {
+ *(.sbss)
+ bss_end = .;
+ } >ram
+
+ .text :
+ {
+ boot_base = .;
+ reset.o(.text)
+ } >rom
+
+ .data :
+ {
+ *(.data)
+ } >rom
+
+ .sdata :
+ {
+ *(.sdata)
+ } >rom
+
+ .sdata2 :
+ {
+ *(.sdata2)
+ } >rom
+
+ .rodata :
+ {
+ *(.rodata)
+ } >rom
+
+ .got :
+ {
+ *(.got)
+ } >rom
+}
diff --git a/ports/template/TEMPLATE_ramtst.ldt b/ports/template/TEMPLATE_ramtst.ldt
new file mode 100644
index 0000000..34d4203
--- /dev/null
+++ b/ports/template/TEMPLATE_ramtst.ldt
@@ -0,0 +1,69 @@
+/* Linker file for building monitor using GNU toolset on PC...
+
+ General notice:
+ This code is part of a boot-monitor package developed as a generic base
+ platform for embedded system designs. As such, it is likely to be
+ distributed to various projects beyond the control of the original
+ author. Please notify the author of any enhancements made or bugs found
+ so that all may benefit from the changes. In addition, notification back
+ to the author will allow the new user to pick up changes that may have
+ been made by other users after this version of the code was distributed.
+
+ Author: Ed Sutter
+ email: esutter@lucent.com
+ phone: 908-582-2351
+
+*/
+etheraddr = MACADDRBASE;
+alt_tfsdevtbl_base = ALTTFSDEVTBLBASE;
+
+MEMORY
+{
+ ram (RWX): org = RAMTSTBASE, len = RAMTSTLEN
+}
+
+SECTIONS
+{
+ .text :
+ {
+ boot_base = .;
+ reset.o(.text)
+ } >ram
+
+ .data :
+ {
+ *(.data)
+ } >ram
+
+ .sdata :
+ {
+ *(.sdata)
+ } >ram
+
+ .sdata2 :
+ {
+ *(.sdata2)
+ } >ram
+
+ .rodata :
+ {
+ *(.rodata)
+ } >ram
+
+ .got :
+ {
+ *(.got)
+ } >ram
+
+ .bss :
+ {
+ bss_start = .;
+ *(.bss) *(COMMON)
+ } >ram
+
+ .sbss :
+ {
+ *(.sbss)
+ bss_end = .;
+ } >ram
+}
diff --git a/ports/template/_vimrc b/ports/template/_vimrc
new file mode 100644
index 0000000..2a127e5
--- /dev/null
+++ b/ports/template/_vimrc
@@ -0,0 +1,13 @@
+" Very basic VIM startup file
+"
+" Set tab stop to 4 characters:
+set ts=4
+
+" Turn off syntax-sensitive coloring:
+" syntax off
+
+" Enable C-style indentation:
+" set cindent
+
+" Disable the highlighting of search items:
+set nohlsearch
diff --git a/ports/template/bashrc b/ports/template/bashrc
new file mode 100644
index 0000000..16ded27
--- /dev/null
+++ b/ports/template/bashrc
@@ -0,0 +1,16 @@
+# Set prompt to reflect the target:
+PS1=TEMPLATE:
+
+# TITLE may be used by the 'title' tool in umon_setup
+export TITLE="TEMPLATE Monitor Development"
+
+# If UMONTOP is not set, then set it to the default:
+if [ "$UMONTOP" == "" ]
+then
+ export UMONTOP=../../umon_main
+fi
+
+# The umon_setup script looks for the presence of the EXT_UMON_SETUP
+# as a shell variable. If it is present it assumes it is the fullpath
+# of a user-defined script that will be run as part of the umon setup.
+. $UMONTOP/host/bin/umon_setup
diff --git a/ports/template/config.h b/ports/template/config.h
new file mode 100644
index 0000000..6e61dd5
--- /dev/null
+++ b/ports/template/config.h
@@ -0,0 +1,199 @@
+/* Template MicroMonitor configuration file.
+ */
+#define CPU_BE
+
+/* PLATFORM_NAME:
+ * Some string that briefly describes your target.
+ */
+#define PLATFORM_NAME "Name of your Board here"
+
+/* CPU_NAME:
+ * The name of your CPU (i.e. "PowerPC 405", "Coldfire 5272" ,etc...).
+ */
+#define CPU_NAME "CPU_NAME_HERE"
+
+/* LOOPS_PER_SECOND:
+ * Approximately the size of a loop that will cause a 1-second delay.
+ * This value can be adjusted by using the "sleep -c" command.
+ */
+#define LOOPS_PER_SECOND 23000
+
+/* PRE_TFSAUTOBOOT_HOOK():
+ * This is a port-specific function that will be called just prior to
+ * uMon running any/each autobootable file (not including monrc).
+#define PRE_TFSAUTOBOOT_HOOK() func()
+ */
+
+/* PRE_COMMANDLOOP_HOOK():
+ * This is a port-specific function that will be called just before
+ * MicroMonitor turns over control to the endless command processing
+ * loop in start() (start.c).
+#define PRE_COMMANDLOOP_HOOK() func()
+ */
+
+/* If a watchdog macro is needed, this is how you do it
+ * (using target specific code in the macro of course)...
+ * The remoteWatchDog() call is only needed if your appliation
+ * will override the monitor's watchdog macro. If that isn't
+ * needed, then that logic can be omitted from the macro.
+
+#define WATCHDOG_MACRO \
+ { \
+ extern void (*remoteWatchDog)(void); \
+ if (remoteWatchDog) { \
+ remoteWatchdog() \
+ } \
+ else { \
+ *(unsigned long *)0xff000000 |= 0x00100000; \
+ *(unsigned long *)0xff000000 &= ~0x00100000; \
+ }
+ }
+ *
+ */
+
+/* If the ENET_LINK_IS_UP macro is defined as some function, then
+ * that function will be called every half second for some number of
+ * ticks. The default tick count is set by the definition of
+ * LINKUP_TICK_MAX also defined in that file. This can be overridden
+ * here if necessary. Refer to the function EthernetWaitforLinkup() in
+ * ethernet.c (umon_main/target/common/ethernet.c) for complete details.
+ *
+ * The function defined by ENET_LINK_IS_UP (shown below as phy_linkup())
+ * is assumed to return 1 if the link is up; else 0.
+ *
+#define ENET_LINK_IS_UP phy_linkup
+#define LINKUP_TICK_MAX 10
+ *
+ * The purpose of this is to provide a common way to wait for the up-state
+ * of the link prior to allowing other commands to execute from uMon at
+ * startup.
+ */
+
+
+/* Flash bank configuration:
+ * Basic information needed to configure the flash driver.
+ * Fill in port specific values here.
+ */
+#define SINGLE_FLASH_DEVICE 1
+#define FLASH_COPY_TO_RAM 1
+#define FLASH_BANK0_BASE_ADDR 0xFF800000
+#define FLASH_PROTECT_RANGE "0-2"
+#define FLASH_BANK0_WIDTH 2
+#define FLASH_LARGEST_SECTOR 0x20000
+
+/* If there is a need to have the range of protected sectors locked (and
+ * the flash device driver supports it), then enable this macro...
+#define LOCK_FLASH_PROTECT_RANGE
+ */
+
+/* TFS definitions:
+ * Values that configure the flash space that is allocated to TFS.
+ * Fill in port specific values here.
+ */
+#define TFSSPARESIZE FLASH_LARGEST_SECTOR
+#define TFSSTART (FLASH_BANK0_BASE_ADDR+0x80000)
+#define TFSEND 0xFFFDFFFF
+#define TFSSPARE (TFSEND+1)
+#define TFSSECTORCOUNT ((TFSSPARE-TFSSTART)/0x20000)
+#define TFS_EBIN_ELF 1
+#define TFS_VERBOSE_STARTUP 1
+#define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base
+
+/* FLASHRAM Parameters (not required):
+ * Primarily used for configuring TFS on battery-backed RAM.
+ * For a simple (volatile) RAM-based TFS device, use the
+ * "tfs ramdev" command.
+ *
+ * Define a block of RAM space to be used as a TFS-device.
+ * This is a block of RAM that TFS is fooled into treating like flash.
+ * It essentially provides a RAM-based file-storage area.
+ */
+#define FLASHRAM_BASE 0x380000
+
+#ifdef FLASHRAM_BASE
+# define FLASHRAM_END 0x3fffff
+# define FLASHRAM_SECTORSIZE 0x010000
+# define FLASHRAM_SPARESIZE FLASHRAM_SECTORSIZE
+# define FLASHRAM_SECTORCOUNT 8
+# define FLASHRAM_BANKNUM 1
+# define FLASHBANKS 2
+#else
+# define FLASHBANKS 1
+#endif
+
+/* ALLOCSIZE:
+ * Specify the size of the memory block (in monitor space) that
+ * is to be allocated to malloc in the monitor. Note that this
+ * size can be dynamically increased using the heap command at
+ * runtime.
+ */
+#define ALLOCSIZE (64*1024)
+
+/* MONSTACKSIZE:
+ * The amount of space allocated to the monitor's stack.
+ */
+#define MONSTACKSIZE (8*1024)
+
+/* INCLUDE_XXX Macros:
+ * Set/clear the appropriate macros depending on what you want
+ * to configure in your system. The sanity of this list is tested
+ * through the inclusion of "inc_check.h" at the bottom of this list...
+ * When starting a port, set all but INCLUDE_MALLOC, INCLUDE_SHELLVARS,
+ * INCLUDE_MEMCMDS and INCLUDE_XMODEM to zero. Then in small steps
+ * enable the following major features in the following order:
+ *
+ * INCLUDE_FLASH to test the flash device drivers.
+ * INCLUDE_TFS* to overlay TFS onto the flash.
+ * INCLUDE_ETHERNET, INCLUDE_TFTP to turn the ethernet interface.
+ *
+ * All other INCLUDE_XXX macros can be enabled as needed and for the
+ * most part, they're hardware independent.
+ * Note that for building a very small footprint, INCLUDE_MALLOC and
+ * INCLUDE_SHELLVARS can be disabled.
+ */
+
+#define INCLUDE_MALLOC 1
+#define INCLUDE_MEMCMDS 1
+#define INCLUDE_SHELLVARS 1
+#define INCLUDE_XMODEM 1
+#define INCLUDE_EDIT 0
+#define INCLUDE_DISASSEMBLER 0
+#define INCLUDE_UNZIP 0
+#define INCLUDE_ETHERNET 0
+#define INCLUDE_ICMP 0
+#define INCLUDE_TFTP 0
+#define INCLUDE_TFS 0
+#define INCLUDE_FLASH 0
+#define INCLUDE_LINEEDIT 0
+#define INCLUDE_DHCPBOOT 0
+#define INCLUDE_TFSAPI 0
+#define INCLUDE_TFSSYMTBL 0
+#define INCLUDE_TFSSCRIPT 0
+#define INCLUDE_TFSCLI 0
+#define INCLUDE_EE 0
+#define INCLUDE_GDB 0
+#define INCLUDE_STRACE 0
+#define INCLUDE_CAST 0
+#define INCLUDE_STRUCT 0
+#define INCLUDE_REDIRECT 0
+#define INCLUDE_QUICKMEMCPY 0
+#define INCLUDE_PROFILER 0
+#define INCLUDE_BBC 0
+#define INCLUDE_MEMTRACE 0
+#define INCLUDE_STOREMAC 0
+#define INCLUDE_VERBOSEHELP 0
+#define INCLUDE_HWTMR 0
+#define INCLUDE_PORTCMD 0
+#define INCLUDE_USRLVL 0
+
+/* Some fine tuning (if needed)...
+ * If these #defines are not in config.h, they default to '1' in
+ * various other include files within uMon source; hence, they're
+ * really only useful if you need to turn off ('0') the specific
+ * facility or block of code.
+ */
+#define INCLUDE_TFTPSRVR 0
+#define INCLUDE_ETHERVERBOSE 0
+#define INCLUDE_MONCMD 0
+
+#include "inc_check.h"
diff --git a/ports/template/cpu.h b/ports/template/cpu.h
new file mode 100644
index 0000000..9d17721
--- /dev/null
+++ b/ports/template/cpu.h
@@ -0,0 +1,3 @@
+/* cpu.h:
+ */
+#define MONARGV0 "umon"
diff --git a/ports/template/cpuio.c b/ports/template/cpuio.c
new file mode 100644
index 0000000..0ce553b
--- /dev/null
+++ b/ports/template/cpuio.c
@@ -0,0 +1,192 @@
+#include "config.h"
+#include "stddefs.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "cache.h"
+#include "warmstart.h"
+#include "timer.h"
+
+/* devInit():
+ * As a bare minimum, initialize the console UART here using the
+ * incoming 'baud' value as the baud rate.
+ */
+void
+devInit(int baud)
+{
+ /* ADD_CODE_HERE */
+}
+
+/* ConsoleBaudSet():
+ * Provide a means to change the baud rate of the running
+ * console interface. If the incoming value is not a valid
+ * baud rate, then default to 9600.
+ * In the early stages of a new port this can be left empty.
+ * Return 0 if successful; else -1.
+ */
+int
+ConsoleBaudSet(int baud)
+{
+ /* ADD_CODE_HERE */
+ return(0);
+}
+
+/* target_console_empty():
+ * Target-specific portion of flush_console() in chario.c.
+ * This function returns 1 if there are no characters waiting to
+ * be put out on the UART; else return 0 indicating that the UART
+ * is still busy outputting characters from its FIFO.
+ * In the early stages of a new port this can simply return 1.
+ */
+int
+target_console_empty(void)
+{
+ /* if (UART_OUTPUT_BUFFER_IS_EMPTY()) <- FIX CODE HERE */
+ return(0);
+ return(1);
+}
+
+/* target_putchar():
+ * When buffer has space available, load the incoming character
+ * into the UART.
+ */
+int
+target_putchar(char c)
+{
+ /* Wait for transmit ready bit */
+ while(1) {
+ /* if (UART_IS_READY_FOR_CHARACTER()) <- FIX CODE HERE */
+ break;
+ }
+
+ /* ADD_CODE_HERE
+ * Put character into UART buffer here
+ */
+
+ return((int)c);
+}
+
+/* target_gotachar():
+ * Return 0 if no char is avaialable at UART rcv fifo; else 1.
+ * Do NOT pull character out of fifo, just return status.
+ *
+ * Define INCLUDE_BLINKLED in config.h and add STATLED_ON()
+ * and STATLED_OFF() macros (or functions) so that uMon will
+ * run and blink a target LED at a configured (or default 500msec)
+ * interval...
+ */
+int
+target_gotachar(void)
+{
+#if INCLUDE_BLINKLED
+ static uint8_t ledstate;
+ static struct elapsed_tmr tmr;
+
+#ifndef BLINKON_MSEC
+#define BLINKON_MSEC 500
+#define BLINKOFF_MSEC 500
+#endif
+
+ switch(ledstate) {
+ case 0:
+ startElapsedTimer(&tmr,BLINKON_MSEC);
+ ledstate = 1;
+ STATLED_ON();
+ break;
+ case 1:
+ if(msecElapsed(&tmr)) {
+ STATLED_OFF();
+ ledstate = 2;
+ startElapsedTimer(&tmr,BLINKOFF_MSEC);
+ }
+ break;
+ case 2:
+ if(msecElapsed(&tmr)) {
+ STATLED_ON();
+ ledstate = 1;
+ startElapsedTimer(&tmr,BLINKON_MSEC);
+ }
+ break;
+ }
+#endif
+ /* if (UART_INPUT_BUFFER_IS_NOT_EMPTY()) <- FIX CODE HERE */
+ return(1);
+ return(0);
+}
+
+/* target_getchar():
+ * Assume there is a character in the UART's input buffer and just
+ * pull it out and return it.
+ */
+int
+target_getchar(void)
+{
+ char c;
+
+ /* c = GET_CHARACTER_FROM_UART(); <- FIX CODE HERE */
+ return((int)c);
+}
+
+/* intsoff():
+ * Disable all system interrupts here and return a value that can
+ * be used by intsrestore() (later) to restore the interrupt state.
+ */
+ulong
+intsoff(void)
+{
+ ulong status;
+
+ /* ADD_CODE_HERE */
+ return(status);
+}
+
+/* intsrestore():
+ * Re-establish system interrupts here by using the status value
+ * that was returned by an earlier call to intsoff().
+ */
+void
+intsrestore(ulong status)
+{
+ /* ADD_CODE_HERE */
+}
+
+/* cacheInitForTarget():
+ * Establish target specific function pointers and
+ * enable i-cache...
+ * Refer to $core/cache.c for a description of the function pointers.
+ * NOTE:
+ * If cache (either I or D or both) is enabled, then it is important
+ * that the appropriate cacheflush/invalidate function be established.
+ * This is very important because programs (i.e. cpu instructions) are
+ * transferred to memory using data memory accesses and could
+ * potentially result in cache coherency problems.
+ */
+void
+cacheInitForTarget(void)
+{
+ /* ADD_CODE_HERE */
+}
+
+/* target_reset():
+ * The default (absolute minimum) action to be taken by this function
+ * is to call monrestart(INITIALIZE). It would be better if there was
+ * some target-specific function that would really cause the target
+ * to reset...
+ */
+void
+target_reset(void)
+{
+ flushDcache(0,0);
+ disableDcache();
+ invalidateIcache(0,0);
+ disableIcache();
+ monrestart(INITIALIZE);
+}
+
+/* If any CPU IO wasn't initialized in reset.S, do it here...
+ * This just provides a "C-level" IO init opportunity.
+ */
+void
+initCPUio(void)
+{
+ /* ADD_CODE_HERE */
+}
diff --git a/ports/template/cpuio.h b/ports/template/cpuio.h
new file mode 100644
index 0000000..2021851
--- /dev/null
+++ b/ports/template/cpuio.h
@@ -0,0 +1,3 @@
+#define DEFAULT_BAUD_RATE 38400
+
+#define MONARGV0 "umon"
diff --git a/ports/template/etherdev.c b/ports/template/etherdev.c
new file mode 100644
index 0000000..1271ecd
--- /dev/null
+++ b/ports/template/etherdev.c
@@ -0,0 +1,247 @@
+/* template_etherdev.c:
+ * This is a "starter" file for the ethernet driver interface used by
+ * the monitor. The functions are described, but empty.
+ * At a minimum, code must be added in all places marked ADD_CODE_HERE.
+ * Additional OPT_ADD_CODE_HERE tags indicate locations that can be
+ * omitted, but would be nice to have additional facilities.
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Author: Ed Sutter
+ * email: esutter@lucent.com
+ * phone: 908-582-2351
+ */
+
+#include "config.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "ether.h"
+
+#if INCLUDE_ETHERNET
+
+ulong tx_buff[400];
+
+/*
+ * enreset():
+ * Reset the PHY and MAC.
+ */
+void
+enreset(void)
+{
+ /* ADD_CODE_HERE */
+}
+
+/*
+ * eninit():
+ * Initialize the PHY and MAC.
+ * This would include establishing buffer descriptor tables and
+ * all the support code that will be used by the ethernet device.
+ *
+ * It can be assumed at this point that the array uchar BinEnetAddr[6]
+ * contains the 6-byte MAC address.
+ *
+ * Return 0 if successful; else -1.
+ */
+int
+eninit(void)
+{
+ /* Initialize the Phy */
+ /* ADD_CODE_HERE */
+
+ /* Query the PHY to determine if the link is up.
+ * If not just default to a 10Base-T, half-duplex interface config.
+ * If link is up, then attempt auto-negotiation.
+ */
+ /* ADD_CODE_HERE */
+
+ /* Initialize the MAC */
+ /* ADD_CODE_HERE */
+
+ return (0);
+}
+
+int
+EtherdevStartup(int verbose)
+{
+ /* Initialize local device error counts (if any) here. */
+ /* OPT_ADD_CODE_HERE */
+
+ /* Put ethernet controller in reset: */
+ enreset();
+
+ /* Initialize controller and return the value returned by
+ * eninit().
+ */
+ return(eninit());
+}
+
+/* disablePromiscuousReception():
+ * Provide the code that disables promiscuous reception.
+ */
+void
+disablePromiscuousReception(void)
+{
+ /* OPT_ADD_CODE_HERE */
+}
+
+/* enablePromiscuousReception():
+ * Provide the code that enables promiscuous reception.
+ */
+void
+enablePromiscuousReception(void)
+{
+ /* OPT_ADD_CODE_HERE */
+}
+
+/* disableBroadcastReception():
+ * Provide the code that disables broadcast reception.
+ */
+void
+disableBroadcastReception(void)
+{
+ /* ADD_CODE_HERE */
+}
+
+/* enableBroadcastReception():
+ * Provide the code that enables broadcast reception.
+ */
+void
+enableBroadcastReception(void)
+{
+ /* ADD_CODE_HERE */
+}
+
+/*
+ * enselftest():
+ * Run a self test of the ethernet device(s). This can be stubbed
+ * with a return(1).
+ * Return 1 if success; else -1 if failure.
+ */
+int
+enselftest(int verbose)
+{
+ return(1);
+}
+
+/* ShowEtherdevStats():
+ * This function is used to display device-specific stats (error counts
+ * usually).
+ */
+void
+ShowEtherdevStats(void)
+{
+ /* OPT_ADD_CODE_HERE */
+}
+
+/* getXmitBuffer():
+ * Return a pointer to the buffer that is to be used for transmission of
+ * the next packet. Since the monitor's driver is EXTREMELY basic,
+ * there will only be one packet ever being transmitted. No need to queue
+ * up transmit packets.
+ */
+uchar *
+getXmitBuffer(void)
+{
+ /* ADD_CODE_HERE */
+ return((uchar *)tx_buff);
+}
+
+/* sendBuffer():
+ * Send out the packet assumed to be built in the buffer returned by the
+ * previous call to getXmitBuffer() above.
+ */
+int
+sendBuffer(int length)
+{
+#if INCLUDE_ETHERVERBOSE
+ if (EtherVerbose & SHOW_OUTGOING)
+ printPkt((struct ether_header *)tx_buff,length,ETHER_OUTGOING);
+#endif
+
+ /* Bump up the packet length to a minimum of 64 bytes.
+ */
+ if (length < 64)
+ length = 64;
+
+ /* Add the code that will tickle the device into sending out the
+ * buffer that was previously returned by getXmitBuffer() above...
+ */
+ /* ADD_CODE_HERE */
+
+ EtherXFRAMECnt++;
+ return(0);
+}
+
+/* DisableEtherdev():
+ * Fine as it is...
+ */
+void
+DisableEtherdev(void)
+{
+ enreset();
+}
+
+/* extGetIpAdd():
+ * If there was some external mechanism (other than just using the
+ * IPADD shell variable established in the monrc file) for retrieval of
+ * the board's IP address, then do it here...
+ */
+char *
+extGetIpAdd(void)
+{
+ return((char *)0);
+}
+
+/* extGetEtherAdd():
+ * If there was some external mechanism (other than just using the
+ * ETHERADD shell variable established in the monrc file) for retrieval of
+ * the board's MAC address, then do it here...
+ */
+char *
+extGetEtherAdd(void)
+{
+ return((char *)0);
+}
+
+/*
+ * polletherdev():
+ * Called continuously by the monitor (ethernet.c) to determine if there
+ * is any incoming ethernet packets.
+ *
+ * NOTES:
+ * 1. This function must be reentrant, because there are a few cases in
+ * processPACKET() where pollethernet() may be called.
+ * 2. It should only process one packet per call. This is important
+ * because if allowed to stay here to flush all available packets,
+ * it may starve the rest of the system (especially in cases of heavy
+ * network traffic).
+ * 3. There are cases in the monitor's execution that may cause the
+ * polling polletherdev() to cease for several seconds. Depending on
+ * network traffic, this may cause the input buffering mechanism on
+ * the ethernet device to overflow. A robust polletherdev() function
+ * should support this gracefully (i.e. when the error is detected,
+ * attempt to pass all queued packets to processPACKET(), then do what
+ * is necessary to clear the error).
+ */
+int
+polletherdev(void)
+{
+ uchar *pktbuf = (char *)0;
+ int pktlen = 0, pktcnt = 0;
+
+ if (PACKET_AVAILABLE()) {
+ GET_PACKET_FROM_DEVICE();
+ processPACKET((struct ether_header *)pktbuf, pktlen);
+ pktcnt++;
+ }
+ return(pktcnt);
+}
+
+#endif
diff --git a/ports/template/except_template.c b/ports/template/except_template.c
new file mode 100644
index 0000000..7e74ba8
--- /dev/null
+++ b/ports/template/except_template.c
@@ -0,0 +1,78 @@
+/* except_template.c:
+ * This code handles exceptions that are caught by the exception vectors
+ * that have been installed by the monitor through vinit(). It is likely
+ * that there is already a version of this function available for the CPU
+ * being ported to, so check the cpu directory prior to porting this to a
+ * new target.
+ *
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Author: Ed Sutter
+ * email: esutter@lucent.com
+ * phone: 908-582-2351
+ */
+#include "config.h"
+#include "cpu.h"
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "warmstart.h"
+
+ulong ExceptionAddr;
+int ExceptionType;
+
+/* exception():
+ * This is the first 'C' function called out of a monitor-installed
+ * exception handler.
+ */
+void
+exception(void)
+{
+ /* ADD_CODE_HERE */
+
+ /* Populating these two values is target specific.
+ * Refer to other target-specific examples for details.
+ * In some cases, these values are extracted from registers
+ * already put into the register cache by the lower-level
+ * portion of the exception handler in vectors_template.s
+ */
+ ExceptionAddr = 0;
+ ExceptionType = 0;
+
+ /* Allow the console uart fifo to empty...
+ */
+ flush_console_out();
+ monrestart(EXCEPTION);
+}
+
+/* vinit():
+ * This function is called by init1() at startup of the monitor to
+ * install the monitor-based vector table. The actual functions are
+ * in vectors.s.
+ */
+void
+vinit()
+{
+ /* ADD_CODE_HERE */
+}
+
+/* ExceptionType2String():
+ * This function simply returns a string that verbosely describes
+ * the incoming exception type (vector number).
+ */
+char *
+ExceptionType2String(int type)
+{
+ char *string;
+
+ /* ADD_CODE_HERE */
+ return(string);
+}
+
diff --git a/ports/template/flashtest.scr b/ports/template/flashtest.scr
new file mode 100755
index 0000000..c45f8c5
--- /dev/null
+++ b/ports/template/flashtest.scr
@@ -0,0 +1,122 @@
+# flashtest.scr:
+# This script can be run after a port is completed to verify
+# that the flash driver can properly deal with various address
+# and data alignments.
+#
+# Required shell variables: SECTORBASE & SNUM ...
+#
+# SECTORBASE: set to the base address of some sector within
+# TFS that can be erased during this test.
+# SNUM: the number of the sector whose base address is
+# $SECTORBASE.
+# NOLOCK: set to TRUE if the flash driver doesn't support flash
+# lock/unlock
+
+if $SECTORBASE seq \$SECTORBASE goto USAGE
+if $SNUM seq \$SNUM goto USAGE
+
+# Copy SECTORBASE to SBASE, and APPRAMBASE to SRC
+set SBASE $SECTORBASE
+set SRC $APPRAMBASE
+
+# TEST1:
+echo TEST1:
+echo Verify pattern
+# Establish a few known bytes of source data:
+pm $SRC 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a
+set SRC=hex($SRC+8)
+pm $SRC 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a
+dm $APPRAMBASE 16
+set SRC $APPRAMBASE
+
+# Unlock and erase the sector and verify erasure
+# (should be all 0xff):
+gosub FLASH_UNLOCK
+flash erase $SNUM
+dm $SBASE 16
+set SIZE 16
+
+# LOOP:
+if $SIZE eq 0 goto NEXTLOOP
+gosub FLASHTEST
+set SBASE=hex($SBASE+1)
+set SRC=hex($SRC+1)
+set SIZE=hex($SIZE-2)
+goto LOOP
+
+# NEXTLOOP:
+set SRC $APPRAMBASE
+set SBASE $SECTORBASE
+set SIZE 8
+# LOOP2:
+if $SIZE eq 0 goto TEST2
+gosub FLASHTEST
+set SIZE=hex($SIZE-1)
+goto LOOP2
+
+# FLASHTEST
+flash write $SBASE $SRC $SIZE
+dm $SECTORBASE 16
+flash erase $SNUM
+dm $SECTORBASE 16
+return
+
+# TEST2:
+# Write a few known initial bytes of data with 0xff's within
+# the data...
+echo TEST2:
+pm $APPRAMBASE 0x41 0xff 0xff 0x44 0x45 0xff 0x47 0x48
+flash write $SECTORBASE $APPRAMBASE 8
+
+# Then try to insert data into the fields that were
+# originally 0xff...
+pm $APPRAMBASE 0x42 0x43
+set ADDR=hex($SECTORBASE+1)
+flash write $ADDR $APPRAMBASE 2
+
+pm $APPRAMBASE 0x46
+set ADDR=hex($SECTORBASE+5)
+flash write $ADDR $APPRAMBASE 1
+
+# Now make sure the write worked...
+pm $APPRAMBASE 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48
+echo Next two lines of data should match...
+dm $SECTORBASE 8
+dm $APPRAMBASE 8
+cm -v $APPRAMBASE $SECTORBASE 8
+flash erase $SNUM
+
+#####################
+#
+# TEST 3:
+echo TEST3:
+if $NOLOCK seq TRUE exit
+echo Verify that a locked sector will not write or erase:
+set SCRIPT_IGNORE_ERROR TRUE
+flash write $SECTORBASE $APPRAMBASE 1
+flash lock $SNUM
+dm $SECTORBASE 16
+echo This line should generate a flash write error...
+flash write $SECTORBASE $APPRAMBASE 16
+dm $SECTORBASE 16
+echo This erase should fail...
+flash erase $SNUM
+gosub FLASH_UNLOCK
+echo This erase should succeed...
+flash erase $SNUM
+dm $SECTORBASE 16
+
+exit
+
+# FLASH_UNLOCK:
+if $NOLOCK seq TRUE return
+flash unlock $SNUM
+return
+
+# FLASH_LOCK:
+if $NOLOCK seq TRUE return
+flash lock $SNUM
+return
+
+# USAGE:
+echo Establish SECTORBASE and SNUM, then rerun.
diff --git a/ports/template/makefile b/ports/template/makefile
new file mode 100644
index 0000000..b808f97
--- /dev/null
+++ b/ports/template/makefile
@@ -0,0 +1,212 @@
+###############################################################################
+#
+# MicroMonitor Release 1.0 template board makefile.
+#
+# This file can be used as a starting point for a new port makefile.
+# Structurally, this makefile should work for all ports, so the majority
+# of the changes will be to modify the content of variables already defined.
+# If you are transitioning to release 1.0 of MicroMonitor from an earlier
+# verion, refer to the OLD_TO_NEW.txt file for a set of conversion steps.
+#
+# The VERY FIRST ERROR that this makefile is likely to generate will
+# be due to the fact that the UMONTOP shell variable is either missing
+# or not properly specified. Make sure you start off by setting
+# the UMONTOP variable to be set to the full path of the umon_main
+# directory which contains all of the common source code for both target
+# and host related builds for uMon.
+#
+# This template defaults to use a ppc-elf- GCC tool prefix. Refer to
+# CPUTYPE & FILETYPE variables below to change that.
+#
+###############################################################################
+#
+# Build Variables:
+# TOPDIR:
+# Set to the content of UMONTOP, which is an externally defined
+# shell variable assumed by this environment to be set to the full
+# path of the umon_main directory.
+# PLATFORM:
+# ASCII name of the target platform (e.g. "Cogent CSB472")
+# TGTDIR:
+# The name of the working directory that this port is to be built in.
+# CPUTYPE/FILETYPE:
+# This combination of variables builds the GCC prefix (and is used for
+# a few other purposes.
+# Typical values for CPUTYPE are arm, ppc, m68k, mips and xscale.
+# Typical values for FILETYPE are elf, coff, rtems and aout.
+# CUSTOM_FLAGS:
+# Establish the custom portion of the 'C' flags used for cross-compilation.
+# Refer to the file $(UMONTOP)/target/make/common.make for the set of
+# variables used (in addition to this one) to build the final CFLAGS
+# variable.
+# CUSTOM_AFLAGS:
+# Similar to CUSTOM_FLAGS, this is used for assembler files.
+# CUSTOM_INCLUDE:
+# Used to specify port-specific additions to the INCLUDES list.
+#
+PLATFORM = TEMPLATE
+TOPDIR = $(UMONTOP)
+TGTDIR = template
+CPUTYPE = arm
+FILETYPE = elf
+CUSTOM_CFLAGS =
+CUSTOM_AFLAGS =
+CUSTOM_INCLUDE =
+
+# Using tools installed by "sudo apt-get install gcc-arm-none-eabi"...
+ABIDIR = /usr/lib/gcc/arm-none-eabi/4.8.2
+TOOL_PREFIX = /usr/bin/arm-none-eabi
+
+# If using something other than the Microcross model for the GNU
+# tools (i.e. CPUTYPE-FILETYPE-TOOL) then specify the tool prefix
+# here... (for example, powerpc-405-linux-gnu)
+#TOOL_PREFIX = powerpc-405-linux-gnu
+
+###############################################################################
+#
+# Memory map configuration:
+# The following variables are used to establish the system's memory map.
+# The values associated with these variables are substituted into
+# the .ldt (.ld template) files to generate the .ld files actually used
+# for the final linkage. This allows the user to override these defaults
+# without touching a memory map file. Adjust them appropriately based on
+# the target memory map.
+#
+# BOOTRAMBASE/BOOTRAMLEN:
+# BOOTROMBASE/BOOTROMLEN:
+# Specify the base and length of RAM and ROM (i.e. flash) space used by
+# the version of the monitor that will reside (and run out of) boot flash.
+# RAMTSTBASE/RAMTSTLEN:
+# Specify the base and length of RAM to be used by the "test" version of
+# the monitor that will reside entirely in RAM.
+BOOTRAMBASE=0x3000
+BOOTRAMLEN=0x7ffff
+BOOTROMBASE=0xfff80000
+BOOTROMLEN=0x7ffff
+RAMTSTBASE=0x200000
+RAMTSTLEN=0x7ffff
+
+# These next two hard-coded values are used by ram-based versions of
+# uMon to allow them to know where these flash-based structures are located.
+# Obviously the addresses are port-specific and are specified here for
+# reference only.
+MACADDRBASE=0xfff80000
+ALTTFSDEVTBLBASE=0xfff80020
+
+
+include $(TOPDIR)/target/make/common.make
+
+###############################################################################
+#
+# Build each variable from a list of individual filenames...
+#
+# LOCSSRC:
+# Local (in this directory) assembler files.
+# LOCCSRC:
+# Local (in this directory) 'C' files.
+# Note regarding except_xxx.c and strace_xxx.c...
+# Prior to writing your processor-specific except_xxx.c and strace_xxx.c
+# check the target's cpu directory to make sure it isn't already available.
+# If available, then change the filenames accordingly and move them to
+# the CPUCSRC filelist. If you need to develop them, build them in
+# this port-specific directory, then upon completion they can be moved
+# to the cpu-specific directory so that they can be used by other ports.
+# CPUSSRC:
+# CPU-specific assembler files in the main/target/cpu/CPU directory.
+# CPUSSRC:
+# CPU-specific 'C' files in the main/target/cpu/CPU directory.
+# COMCSRC:
+# Core 'C' files found in the main/target/core directory.
+# IODEVSRC:
+# Device-specific files found in main/target/dev directory.
+# FLASHSRC:
+# The flash driver file found in main/target/flash/devices directory.
+#
+LOCSSRC = reset.S
+CPUSSRC =
+LOCCSRC = cpuio.c etherdev.c except_template.c strace_template.c
+COMCSRC = arp.c bbc.c cast.c cache.c chario.c cmdtbl.c crypt.c \
+ docmd.c dhcp_00.c dhcpboot.c edit.c ee.c env.c ethernet.c \
+ flash.c genlib.c icmp.c if.c ledit_vt100.c monprof.c \
+ mprintf.c memcmds.c malloc.c moncom.c memtrace.c misccmds.c \
+ misc.c password.c redirect.c reg_cache.c sbrk.c start.c \
+ struct.c symtbl.c tcpstuff.c tfs.c tfsapi.c tfsclean1.c \
+ tfscli.c \
+ tfsloader.c tfslog.c tftp.c timestuff.c xmodem.c gdb.c
+CPUCSRC =
+IODEVSRC =
+FLASHSRC = am29lv160d_16x1.c
+
+include $(TOPDIR)/target/make/objects.make
+
+OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \
+ $(FLASHOBJ) $(IODEVOBJ)
+
+#########################################################################
+#
+# Targets...
+
+# boot:
+# The default target is "boot", a shortcut to $(BUILDDIR)/boot.$(FILETYPE).
+# This builds the bootflash image that can be used by 'newmon' to
+# load a new version onto an already running system.
+#
+boot: $(BUILDDIR)/boot.$(FILETYPE)
+ @echo Boot version of uMon built under $(BUILDDIR) ...
+ @ls $(BUILDDIR)/boot*
+
+# ramtst:
+# A shortcut to $(BUILDDIR)/ramtst.$(FILETYPE). This is a version of uMon
+# that resides strictly in RAM and is used for two main purposes:
+# 1. To test new monitor features prior to burning the boot flash.
+# 2. To be downloaded into the RAM space of a board that has no programmed
+# boot flash. This provides a running monitor that can then accept
+# an incoming bootflash image using 'newmon'.
+#
+ramtst: $(BUILDDIR)/ramtst.$(FILETYPE)
+ @echo Ram-resident test version of uMon built under $(BUILDDIR) ...
+ @ls $(BUILDDIR)/ramtst*
+
+$(BUILDDIR)/boot.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a libg.a makefile
+ $(MAKE_MONBUILT)
+ $(MAKE_LDFILE) \
+ BOOTRAMBASE=$(BOOTRAMBASE) BOOTRAMLEN=$(BOOTRAMLEN) \
+ BOOTROMBASE=$(BOOTROMBASE) BOOTROMLEN=$(BOOTROMLEN)
+ $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC)
+ $(MAKE_BINARY)
+ $(MAKE_GNUSYMS)
+
+$(BUILDDIR)/ramtst.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a libg.a makefile
+ $(MAKE_MONBUILT)
+ $(MAKE_LDFILE) \
+ RAMTSTBASE=$(RAMTSTBASE) RAMTSTLEN=$(RAMTSTLEN) \
+ MACADDRBASE=$(MACADDRBASE) ALTTFSDEVTBLBASE=$(ALTTFSDEVTBLBASE)
+ $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC)
+ $(MAKE_BINARY)
+ $(MAKE_GNUSYMS)
+
+include $(TOPDIR)/target/make/rules.make
+
+#########################################################################
+#
+# Miscellaneous...
+#
+######
+#
+# cscope_local:
+# Put additional files here that should be included in the cscope
+# files list. This is called before the generic cscope file builder,
+# so it should create the cscope.files file.
+#
+cscope_local:
+ echo $(CPUDIR)/regs_403.c >cscope.files
+
+######
+#
+# help_local:
+# Add text here as needed by the port.
+#
+help_local:
+ @echo "This template defaults to using ppc-elf as the tool prefix."
+ @echo "To override this default modify CPU & FILETYPE variables."
+ @echo
diff --git a/ports/template/regnames.c b/ports/template/regnames.c
new file mode 100644
index 0000000..4e4afd3
--- /dev/null
+++ b/ports/template/regnames.c
@@ -0,0 +1,10 @@
+/* This file is included by the common file reg_cache.c.
+ * The file included below is the table of register names.
+ * The purpose behind this multiple level of file inclusion is to allow
+ * the common file "reg_cache.c" to include a file called "regnames.c"
+ * which will have a target-specific register table without the target-
+ * specific filename.
+ * If the file specified below isn't correct, then check main/cpu/CPU for
+ * others.
+ */
+#include "regs_403.c"
diff --git a/ports/template/reset.S b/ports/template/reset.S
new file mode 100644
index 0000000..08ddf72
--- /dev/null
+++ b/ports/template/reset.S
@@ -0,0 +1,110 @@
+/* reset.s:
+ *
+ * First bit of boot code run by the processor.
+ *
+ */
+ .file "reset.s"
+
+ .extern start
+ .extern MonStack
+ .global reset
+ .global warmstart
+ .global coldstart
+
+#include "warmstart.h"
+
+/* Depending on the CPU, these entries may have to be shuffled
+ * around a bit. The position of coldstart is very CPU specific
+ * and the location of moncomptr should be in a place where it is
+ * unlikely to be moved if other monitor functionality is changed.
+ */
+
+/*********************************************************************
+ *
+ * coldstart:
+ * The reset point.
+ */
+reset:
+coldstart:
+ /* - Invalidate and disable caches
+ * - Load INITIALIZE (defined in warmstart.h) into whereever it
+ * needs to be put so that warmstart sees it as an argument
+ * passed to it.
+ *
+ * - Jump to warmstart
+ */
+
+/*********************************************************************
+ *
+ * moncomptr:
+ * Pointer to the moncom function, used to link application to monitor.
+ * Refer to umon_main/target/core/moncomptr.S
+ */
+#include "moncomptr.S"
+
+/*********************************************************************
+ *
+ * etheraddr:
+ * Location that could be used to store a fixed MAC address.
+ * Refer to umon_main/target/core/etheraddr.S.
+ * NOTE:
+ * This should only be included in flash-resident code, then
+ * the address in flash should be accessible to ram-based versions of
+ * uMon via tags in the linker map file.
+ */
+#include "etheraddr.S"
+
+/*********************************************************************
+ *
+ * alttfsdevtbl.S:
+ * Location that could be used to store an "alternate" TFS device
+ * table for use by the "tfs cfg" command.
+ * Refer to umon_main/target/core/alttfsdevtbl.S.
+ * NOTE:
+ * This should only be included in flash-resident code, then
+ * the address in flash should be accessible to ram-based versions of
+ * uMon via tags in the linker map file.
+ */
+#include "alttfsdevtbl.S"
+
+/*********************************************************************
+ *
+ * warmstart:
+ * A point callable by C, as warmstart(int type), where
+ * 'type' is one of the values defined in warmstart.h.
+ */
+warmstart:
+ /* Minimal CPU/IO Initialization (i.e. chip selects) here.
+ * Stay in assembler here if possible.
+ */
+
+/*********************************************************************
+ *
+ * SPInit:
+ * Establish a stack frame.
+ */
+SPInit:
+ /* First initialize stack to point to MonStack+MONSTACKSIZE+64
+ * (an address that is outside the MonStack array), and then
+ * call stkinit(). This loads the MonStack[] array with a known
+ * pattern that allows uMon to later analyze the running stack usage.
+ */
+
+ /* Next, re-initialize stack to point to MonStack+MONSTACKSIZE...
+ * This is important because other portions of the code
+ * assume this is where the stack resides.
+ */
+
+/*********************************************************************
+ *
+ * gotoC:
+ * This code jumps to the start() function in the monitor
+ * and should never return.
+ */
+gotoC:
+ /* - Retrieve the variable passed to warmstart and place it
+ * whereever it needs to be so that the start() function in
+ * 'C' sees it as an argument. Note that if FORCE_BSS_INIT
+ * is defined, then start() will ignore this argument.
+ * - Branch to start().
+ */
diff --git a/ports/template/strace_template.c b/ports/template/strace_template.c
new file mode 100644
index 0000000..38a44c0
--- /dev/null
+++ b/ports/template/strace_template.c
@@ -0,0 +1,116 @@
+/* strace.c:
+ * General notice:
+ * This code is part of a boot-monitor package developed as a generic base
+ * platform for embedded system designs. As such, it is likely to be
+ * distributed to various projects beyond the control of the original
+ * author. Please notify the author of any enhancements made or bugs found
+ * so that all may benefit from the changes. In addition, notification back
+ * to the author will allow the new user to pick up changes that may have
+ * been made by other users after this version of the code was distributed.
+ *
+ * Note1: the majority of this code was edited with 4-space tabs.
+ * Note2: as more and more contributions are accepted, the term "author"
+ * is becoming a mis-representation of credit.
+ *
+ * Original author: Ed Sutter
+ * Email: esutter@lucent.com
+ * Phone: 908-582-2351
+ *
+ */
+#include "config.h"
+#if INCLUDE_STRACE
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "ctype.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "cpu.h"
+
+char *StraceHelp[] = {
+ "Stack trace",
+ "-[d:F:P:rs:v]",
+ " -d # max depth count (def=20)",
+ " -F # specify frame-pointer (don't use content of A6)",
+ " -P # specify PC (don't use content of PC)",
+ " -r dump regs",
+ " -v verbose",
+ 0,
+};
+
+int
+Strace(int argc,char *argv[])
+{
+ char *symfile, fname[64];
+ TFILE *tfp;
+ ulong *framepointer, pc, fp, offset;
+ int tfd, opt, maxdepth, pass, verbose, bullseye;
+
+ tfd = fp = 0;
+ maxdepth = 20;
+ verbose = 0;
+ pc = ExceptionAddr;
+ while ((opt=getopt(argc,argv,"d:F:P:rs:v")) != -1) {
+ switch(opt) {
+ case 'd':
+ maxdepth = atoi(optarg);
+ break;
+ case 'F':
+ fp = strtoul(optarg,0,0);
+ break;
+ case 'P':
+ pc = strtoul(optarg,0,0);
+ break;
+ case 'r':
+ showregs();
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ return(0);
+ }
+ }
+
+ if (!fp)
+ getreg("A6", (ulong *)&framepointer);
+ else
+ framepointer = (ulong *)fp;
+
+ /* Start by detecting the presence of a symbol table file... */
+ symfile = getenv("SYMFILE");
+ if (!symfile)
+ symfile = SYMFILE;
+
+ tfp = tfsstat(symfile);
+ if (tfp) {
+ tfd = tfsopen(symfile,TFS_RDONLY,0);
+ if (tfd < 0)
+ tfp = (TFILE *)0;
+ }
+
+ /* Show current position: */
+ printf(" 0x%08lx",pc);
+ if (tfp) {
+ AddrToSym(tfd,pc,fname,&offset);
+ printf(": %s()",fname);
+ if (offset)
+ printf(" + 0x%lx",offset);
+ }
+ putchar('\n');
+
+ /* Now step through the stack frame... */
+ bullseye = pass = 0;
+ while(maxdepth) {
+ /* ADD_CODE_HERE */
+ }
+
+ if (!maxdepth)
+ printf("Max depth termination\n");
+
+ if (tfp) {
+ tfsclose(tfd,0);
+ }
+ return(0);
+}
+
+#endif
diff --git a/ports/template/target_version.h b/ports/template/target_version.h
new file mode 100644
index 0000000..fa728a7
--- /dev/null
+++ b/ports/template/target_version.h
@@ -0,0 +1,8 @@
+/* target_version.h:
+ * Initial version for all ports is zero. As the TARGET_VERSION incrments
+ * as a result of changes made to the target-specific code, this file should
+ * be used as an informal log of those changes for easy reference by others.
+ *
+ * 1->2: Added 'struct' command.
+ */
+#define TARGET_VERSION 2
diff --git a/ports/template/tfsdev.h b/ports/template/tfsdev.h
new file mode 100644
index 0000000..541f3fb
--- /dev/null
+++ b/ports/template/tfsdev.h
@@ -0,0 +1,36 @@
+/* tfsdev.h:
+ This file is ONLY included by tfs.c. It is seperate from tfs.h because
+ it is target-specific. It is not part of config.h because it includes
+ the declaration of the tfsdevtbl[].
+ A prefix in the name of the file determines what device is used to store
+ that file. If no prefix is found the the first device in the table is
+ used as a default. The syntax of the prefix is "//STRING/" where STRING
+ is user-definable, but the initial // and final / are required by tfs
+ code.
+*/
+
+struct tfsdev tfsdevtbl[] = {
+ {
+ "//FLASH/",
+ TFSSTART,
+ TFSEND,
+ TFSSPARE,
+ TFSSPARESIZE,
+ TFSSECTORCOUNT,
+ TFS_DEVTYPE_FLASH },
+
+#ifdef FLASHRAM_BASE
+ {
+ "//RAM/",
+ FLASHRAM_BASE,
+ FLASHRAM_END - FLASHRAM_SPARESIZE,
+ FLASHRAM_END - FLASHRAM_SPARESIZE + 1,
+ FLASHRAM_SPARESIZE,
+ FLASHRAM_SECTORCOUNT-1,
+ TFS_DEVTYPE_RAM | TFS_DEVINFO_AUTOINIT },
+#endif
+
+ { 0, TFSEOT,0,0,0,0,0 }
+};
+
+#define TFSDEVTOT ((sizeof(tfsdevtbl))/(sizeof(struct tfsdev)))
diff --git a/ports/template/xcmddcl.h b/ports/template/xcmddcl.h
new file mode 100644
index 0000000..1057b07
--- /dev/null
+++ b/ports/template/xcmddcl.h
@@ -0,0 +1,14 @@
+/* xcmdtbl.h:
+ * This file must exist even if it is empty because it is #included in the
+ * common file cmdtbl.c. The purpose is to keep the common comand table
+ * file (common/cmdtbl.c) from being corrupted with non-generic commands
+ * that may be target specific.
+ * This is the declaration portion of the code that must be at the top of
+ * the cmdtbl[] array.
+ *
+ * For example...
+
+extern int date();
+extern char *dateHelp[];
+
+ */
diff --git a/ports/template/xcmdtbl.h b/ports/template/xcmdtbl.h
new file mode 100644
index 0000000..ad74e63
--- /dev/null
+++ b/ports/template/xcmdtbl.h
@@ -0,0 +1,12 @@
+/* xcmdtbl.c:
+ * This file must exist even if it is empty because it is #included in the
+ * common file cmdtbl.c. The purpose is to keep the common comand table
+ * file (common/cmdtbl.c) from being corrupted with non-generic commands
+ * that may be target specific.
+ * It is the entry in the command table representing the new command being
+ * added to the cmdtbl[] array.
+ * For example:
+
+{"date", date, dateHelp, 0},
+
+ */