Browse Source

[Add Tools][rootfs][mtd-utils]

2020.11.03 / Folus Wen

Actions:
1. Add mtd-utils-2.1.2 to GPL.

Files:
1. As follow commit history

Image version: D0.00.XX.XXXX.XX
Image checksum: XXXXXXXX

Hardware PWB P/N : XXXXXXX
Hardware Version : XXXXXXX
FolusWen 4 years ago
parent
commit
afd8b9f123
100 changed files with 27104 additions and 1 deletions
  1. 10 1
      EVSE/GPL/Makefile
  2. BIN
      EVSE/GPL/mtd-utils-2.1.2.tar.gz
  3. 153 0
      EVSE/GPL/mtd-utils-2.1.2/.gitignore
  4. 340 0
      EVSE/GPL/mtd-utils-2.1.2/COPYING
  5. 75 0
      EVSE/GPL/mtd-utils-2.1.2/Makefile.am
  6. 3 0
      EVSE/GPL/mtd-utils-2.1.2/autogen.sh
  7. 370 0
      EVSE/GPL/mtd-utils-2.1.2/configure.ac
  8. 278 0
      EVSE/GPL/mtd-utils-2.1.2/include/common.h
  9. 13 0
      EVSE/GPL/mtd-utils-2.1.2/include/crc32.h
  10. 174 0
      EVSE/GPL/mtd-utils-2.1.2/include/dictionary.h
  11. 37 0
      EVSE/GPL/mtd-utils-2.1.2/include/libfec.h
  12. 265 0
      EVSE/GPL/mtd-utils-2.1.2/include/libiniparser.h
  13. 17 0
      EVSE/GPL/mtd-utils-2.1.2/include/libmissing.h
  14. 352 0
      EVSE/GPL/mtd-utils-2.1.2/include/libmtd.h
  15. 113 0
      EVSE/GPL/mtd-utils-2.1.2/include/libscan.h
  16. 489 0
      EVSE/GPL/mtd-utils-2.1.2/include/libubi.h
  17. 194 0
      EVSE/GPL/mtd-utils-2.1.2/include/libubigen.h
  18. 218 0
      EVSE/GPL/mtd-utils-2.1.2/include/linux/jffs2.h
  19. 76 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/ftl-user.h
  20. 89 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/inftl-user.h
  21. 82 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/jffs2-user.h
  22. 282 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/mtd-abi.h
  23. 34 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/mtd-user.h
  24. 76 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/nftl-user.h
  25. 384 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubi-media.h
  26. 452 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubi-user.h
  27. 869 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubifs-media.h
  28. 51 0
      EVSE/GPL/mtd-utils-2.1.2/include/mtd_swab.h
  29. 106 0
      EVSE/GPL/mtd-utils-2.1.2/include/xalloc.h
  30. 37 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/Makemodule.am
  31. 538 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr.c
  32. 119 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr.h
  33. 136 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_lzo.c
  34. 119 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_rtime.c
  35. 148 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_zlib.c
  36. 129 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/device_table.txt
  37. 801 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/jffs2dump.c
  38. 914 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/jffs2reader.c
  39. 268 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/mkfs.jffs2.1
  40. 1811 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/mkfs.jffs2.c
  41. 390 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/rbtree.c
  42. 171 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/rbtree.h
  43. 177 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/summary.h
  44. 873 0
      EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/sumtool.c
  45. 20 0
      EVSE/GPL/mtd-utils-2.1.2/lib/LICENSE.libiniparser
  46. 30 0
      EVSE/GPL/mtd-utils-2.1.2/lib/Makemodule.am
  47. 164 0
      EVSE/GPL/mtd-utils-2.1.2/lib/common.c
  48. 405 0
      EVSE/GPL/mtd-utils-2.1.2/lib/dictionary.c
  49. 28 0
      EVSE/GPL/mtd-utils-2.1.2/lib/execinfo.c
  50. 105 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libcrc32.c
  51. 904 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libfec.c
  52. 606 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libiniparser.c
  53. 1356 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libmtd.c
  54. 116 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libmtd_int.h
  55. 430 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libmtd_legacy.c
  56. 225 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libscan.c
  57. 1364 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libubi.c
  58. 134 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libubi_int.h
  59. 315 0
      EVSE/GPL/mtd-utils-2.1.2/lib/libubigen.c
  60. 104 0
      EVSE/GPL/mtd-utils-2.1.2/make_a_release.sh
  61. 41 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/MAKEDEV
  62. 67 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/Makemodule.am
  63. 150 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/doc_loadbios.c
  64. 322 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/docfdisk.c
  65. 92 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/fectest.c
  66. 263 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_erase.c
  67. 4 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_eraseall
  68. 8 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_lock.c
  69. 71 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_dump.c
  70. 65 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_info.c
  71. 72 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_lock.c
  72. 122 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_write.c
  73. 218 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_unlock.c
  74. 406 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/flashcp.c
  75. 231 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/ftl_check.c
  76. 343 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/ftl_format.c
  77. 112 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.8
  78. 794 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.c
  79. 67 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.h
  80. 224 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd_scan.c
  81. 22 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/mcast_image.h
  82. 396 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/mtd_debug.c
  83. 195 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/mtdpart.c
  84. 485 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/recv_image.c
  85. 303 0
      EVSE/GPL/mtd-utils-2.1.2/misc-utils/serve_image.c
  86. 32 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/Makemodule.am
  87. 127 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/load_nandsim.sh
  88. 557 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/nanddump.c
  89. 322 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/nandtest.c
  90. 620 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/nandwrite.c
  91. 445 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/nftl_format.c
  92. 280 0
      EVSE/GPL/mtd-utils-2.1.2/nand-utils/nftldump.c
  93. 10 0
      EVSE/GPL/mtd-utils-2.1.2/nor-utils/Makemodule.am
  94. 335 0
      EVSE/GPL/mtd-utils-2.1.2/nor-utils/rfddump.c
  95. 158 0
      EVSE/GPL/mtd-utils-2.1.2/nor-utils/rfdformat.c
  96. 4 0
      EVSE/GPL/mtd-utils-2.1.2/release/sbin/flash_eraseall
  97. 268 0
      EVSE/GPL/mtd-utils-2.1.2/release/share/man/man1/mkfs.jffs2.1
  98. 112 0
      EVSE/GPL/mtd-utils-2.1.2/release/share/man/man8/lsmtd.8
  99. 136 0
      EVSE/GPL/mtd-utils-2.1.2/release/share/man/man8/ubinize.8
  100. 86 0
      EVSE/GPL/mtd-utils-2.1.2/tests/fs-tests/Makemodule.am

+ 10 - 1
EVSE/GPL/Makefile

@@ -3,7 +3,7 @@
 export PATH=/bin:/sbin:/usr/bin:$(SDK_PATH_TARGET)usr/bin:usr/bin:$PATH
 
 
-all: libwebsocket Openssl ZIP30 BZIP2 DropBear WPA pppd Marvell8801 WirelessTool sqlite3 lighttpd libxml2 php pcre glibc json-c libpcap tcpdump can-utils iftop logrotate curl libmodbus ifmetric open-plc-utils
+all: libwebsocket Openssl ZIP30 BZIP2 DropBear WPA pppd Marvell8801 WirelessTool sqlite3 lighttpd libxml2 php pcre glibc json-c libpcap tcpdump can-utils iftop logrotate curl libmodbus ifmetric open-plc-utils mtd-utils
 
 libwebsocket :
 	echo "libwebsockets-2.2.2-stable"
@@ -246,3 +246,12 @@ open-plc-utils:
 	make -C open-plc-utils-0.3 CC=$(CROSS_COMPILE)gcc clean
 	make -C open-plc-utils-0.3 CC=$(CROSS_COMPILE)gcc
 	make -C open-plc-utils-0.3 CC=$(CROSS_COMPILE)gcc install
+
+mtd-utils:
+	echo "mtd-utils-2.1.2"
+	cd mtd-utils-2.1.2/;./configure --without-ubifs --host=arm-linux-gnueabihf --prefix=$(shell pwd)/mtd-utils-2.1.2/release CC=$(CROSS_COMPILE)gcc AR=$(CROSS_COMPILE)ar RANLIB=$(CROSS_COMPILE)ranlib STRIP=$(CROSS_COMPILE)strip CXX=$(CROSS_COMPILE)g++ ;cd ../
+	make -C mtd-utils-2.1.2 CC=$(CROSS_COMPILE)gcc clean
+	make -C mtd-utils-2.1.2 CC=$(CROSS_COMPILE)gcc
+	make -C mtd-utils-2.1.2 CC=$(CROSS_COMPILE)gcc install
+#       cp -r -f mtd-utils-2.1.2/release/* ../rootfs/
+

BIN
EVSE/GPL/mtd-utils-2.1.2.tar.gz


+ 153 - 0
EVSE/GPL/mtd-utils-2.1.2/.gitignore

@@ -0,0 +1,153 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# Normal rules
+#
+.*
+*.gdb
+*.o
+*.a
+*.s
+*.ko
+*.so
+*.mod.c
+*~
+
+#
+# Our programs
+#
+doc_loadbios
+docfdisk
+flash_erase
+flash_lock
+flash_otp_dump
+flash_otp_info
+flash_otp_lock
+flash_otp_write
+flash_unlock
+flashcp
+ftl_check
+ftl_format
+jffs2dump
+jffs2reader
+mkfs.jffs2
+mtd_debug
+mtdpart
+nanddump
+nandtest
+nandwrite
+nftl_format
+nftldump
+recv_image
+rfddump
+rfdformat
+serve_image
+sumtool
+JitterTest
+checkfs
+free_space
+fstest_monitor
+ftrunc
+fwrite00
+gcd_hupper
+integ
+integck
+io_basic
+io_paral
+io_read
+io_update
+lsmtd
+makefiles
+mkfs.ubifs
+mkvol_bad
+mkvol_basic
+mkvol_paral
+mtdinfo
+orph
+pdfrun
+perf
+plotJittervsFill
+rmdir00
+rndrm00
+rndrm99
+rndwrite00
+rsvol
+stress_1
+stress_2
+stress_3
+test_1
+test_2
+flash_torture
+flash_stress
+flash_speed
+flash_readtest
+nandbiterrs
+nandpagetest
+nandsubpagetest
+ubiattach
+ubiblock
+ubicrc32
+ubidetach
+ubiformat
+ubimkvol
+ubinfo
+ubinize
+ubirename
+ubirmvol
+ubirsvol
+ubiupdatevol
+volrefcnt
+mtdlib_test
+ubilib_test
+ubihealthd
+tests/fs-tests/fs_help_all.sh
+tests/fs-tests/fs_run_all.sh
+tests/fs-tests/stress/fs_stress00.sh
+tests/fs-tests/stress/fs_stress01.sh
+tests/ubi-tests/runubitests.sh
+tests/ubi-tests/ubi-stress-test.sh
+
+#
+# Files generated by autotools
+#
+/Makefile
+/Makefile.in
+/aclocal.m4
+/autom4te.cache/
+/config.*
+/configure
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/m4/
+/missing
+/stamp-h?
+/compile
+/include/config.h
+/include/config.h.in
+/include/stamp-h1
+test-driver
+*.log
+*.trs
+
+#
+# Top-level generic files
+#
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+
+# stgit generated dirs
+patches-*
+*.patch
+
+# cscope and ctag files
+cscope.*
+ncscope.*
+/TAGS
+/tags

+ 340 - 0
EVSE/GPL/mtd-utils-2.1.2/COPYING

@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

+ 75 - 0
EVSE/GPL/mtd-utils-2.1.2/Makefile.am

@@ -0,0 +1,75 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CPPFLAGS = $(WARN_CFLAGS) -D_GNU_SOURCE -std=gnu99 -I$(top_srcdir)/include
+
+if WITHOUT_XATTR
+AM_CPPFLAGS += -DWITHOUT_XATTR
+endif
+
+if WITHOUT_LZO
+AM_CPPFLAGS += -DWITHOUT_LZO
+endif
+
+if WITHOUT_ZSTD
+AM_CPPFLAGS += -DWITHOUT_ZSTD
+endif
+
+if WITH_SELINUX
+AM_CPPFLAGS += -DWITH_SELINUX
+endif
+
+if WITH_CRYPTO
+AM_CPPFLAGS += -DWITH_CRYPTO
+endif
+
+if WITH_GETRANDOM
+AM_CPPFLAGS += -DWITH_GETRANDOM
+endif
+
+sbin_PROGRAMS =
+sbin_SCRIPTS =
+check_PROGRAMS =
+noinst_LIBRARIES =
+noinst_PROGRAMS =
+noinst_SCRIPTS =
+pkglibexec_PROGRAMS =
+pkglibexec_SCRIPTS =
+dist_man1_MANS =
+dist_man8_MANS =
+
+TESTS =
+EXTRA_DIST =
+
+GLOBAL_HEADER = \
+	include
+
+GLOBAL_EXTRA = \
+	COPYING
+
+EXTRA_DIST += $(GLOBAL_HEADER) $(GLOBAL_EXTRA)
+
+include lib/Makemodule.am
+include ubi-utils/Makemodule.am
+include misc-utils/Makemodule.am
+include nand-utils/Makemodule.am
+include nor-utils/Makemodule.am
+
+if BUILD_UBIFS
+include ubifs-utils/Makemodule.am
+endif
+
+if BUILD_JFFSX
+include jffsX-utils/Makemodule.am
+endif
+
+if BUILD_TESTS
+include tests/ubi-tests/Makemodule.am
+include tests/jittertest/Makemodule.am
+include tests/checkfs/Makemodule.am
+include tests/fs-tests/Makemodule.am
+include tests/mtd-tests/Makemodule.am
+endif
+
+if UNIT_TESTS
+include tests/unittests/Makemodule.am
+endif

+ 3 - 0
EVSE/GPL/mtd-utils-2.1.2/autogen.sh

@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf --force --install --symlink

+ 370 - 0
EVSE/GPL/mtd-utils-2.1.2/configure.ac

@@ -0,0 +1,370 @@
+AC_PREREQ([2.60])
+
+m4_define([RELEASE], 2.1.2)
+
+AC_INIT([mtd-utils], [RELEASE], [linux-mtd@lists.infradead.org], mtd-utils)
+
+AC_ARG_ENABLE([unit-tests],
+	[AS_HELP_STRING([--enable-unit-tests], [Compile unit test programs])],
+	[case "${enableval}" in
+	yes) AM_CONDITIONAL([UNIT_TESTS], [true]) ;;
+	no)  AM_CONDITIONAL([UNIT_TESTS], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${enableval} for --enable-unit-tests]) ;;
+	esac],
+	[AM_CONDITIONAL([UNIT_TESTS], [false])])
+
+AM_COND_IF([UNIT_TESTS], [: ${CFLAGS=""}], [])
+
+
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign subdir-objects dist-bzip2])
+AM_SILENT_RULES([yes])
+AC_PROG_LIBTOOL
+AC_DISABLE_STATIC
+AC_PROG_CC
+AC_PROG_INSTALL
+
+
+m4_ifndef([PKG_PROG_PKG_CONFIG],
+  [m4_fatal([Could not locate the pkg-config autoconf
+    macros. These are usually located in /usr/share/aclocal/pkg.m4.
+    If your macros are in a different location, try setting the
+    environment variable AL_OPTS="-I/other/macro/dir" before running
+    ./autogen.sh or autoreconf again. Make sure pkg-config is installed.])])
+PKG_PROG_PKG_CONFIG
+
+## compiler warnings
+UL_WARN_ADD([-Wall])
+UL_WARN_ADD([-Wextra])
+UL_WARN_ADD([-Wunused])
+UL_WARN_ADD([-Wmissing-prototypes])
+UL_WARN_ADD([-Wmissing-declarations])
+UL_WARN_ADD([-Wwrite-strings])
+UL_WARN_ADD([-Wjump-misses-init])
+UL_WARN_ADD([-Wuninitialized])
+UL_WARN_ADD([-Winit-self])
+UL_WARN_ADD([-Wlogical-op])
+UL_WARN_ADD([-Wunused-but-set-parameter])
+UL_WARN_ADD([-Wunused-but-set-variable])
+UL_WARN_ADD([-Wunused-parameter])
+UL_WARN_ADD([-Wunused-result])
+UL_WARN_ADD([-Wunused-variable])
+UL_WARN_ADD([-Wduplicated-cond])
+UL_WARN_ADD([-Wduplicated-branches])
+UL_WARN_ADD([-Wrestrict])
+UL_WARN_ADD([-Wnull-dereference])
+
+UL_WARN_ADD([-Wno-shadow])
+UL_WARN_ADD([-Wno-sign-compare])
+
+AC_SUBST([WARN_CFLAGS])
+
+###### handle configure switches, select dependencies ######
+
+need_clock_gettime="no"
+need_pthread="no"
+need_uuid="no"
+need_zlib="no"
+need_lzo="no"
+need_zstd="no"
+need_xattr="no"
+need_cmocka="no"
+need_selinux="no"
+need_openssl="no"
+need_getrandom="no"
+
+AM_COND_IF([UNIT_TESTS], [
+	need_cmocka="yes"
+])
+
+
+AC_ARG_ENABLE([tests],
+	[AS_HELP_STRING([--disable-tests], [Compile test programs])],
+	[case "${enableval}" in
+	yes) AM_CONDITIONAL([BUILD_TESTS], [true]) ;;
+	no)  AM_CONDITIONAL([BUILD_TESTS], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${enableval} for --disable-tests]) ;;
+	esac],
+	[AM_CONDITIONAL([BUILD_TESTS], [true])])
+
+AM_COND_IF([BUILD_TESTS], [
+	need_clock_gettime="yes"
+	need_pthread="yes"
+])
+
+
+AC_ARG_ENABLE([install-tests],
+	[AS_HELP_STRING([--enable-install-tests], [Install test programs])],
+	[case "${enableval}" in
+	yes) AM_CONDITIONAL([INSTALL_TESTS], [true]) ;;
+	no)  AM_CONDITIONAL([INSTALL_TESTS], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${enableval} for --enable-install-tests]) ;;
+	esac],
+	[AM_CONDITIONAL([INSTALL_TESTS], [false])])
+
+
+AM_COND_IF([INSTALL_TESTS],
+	[AC_SUBST(testbindir, ["\$libexecpath"])],
+	[AC_SUBST(testbindir, ["\".\""])])
+
+
+AC_ARG_ENABLE([lsmtd],
+	[AS_HELP_STRING([--disable-lsmtd], [Do not build the lsmtd program])],
+	[case "${enableval}" in
+	yes) AM_CONDITIONAL([BUILD_LSMTD], [true]) ;;
+	no)  AM_CONDITIONAL([BUILD_LSMTD], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${enableval} for --disable-lsmtd]) ;;
+	esac],
+	[AM_CONDITIONAL([BUILD_LSMTD], [true])])
+
+AC_ARG_WITH([jffs],
+	[AS_HELP_STRING([--without-jffs], [Disable jffsX utilities])],
+	[case "${withval}" in
+	yes) AM_CONDITIONAL([BUILD_JFFSX], [true]) ;;
+	no)  AM_CONDITIONAL([BUILD_JFFSX], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-jffs]) ;;
+	esac],
+	[AM_CONDITIONAL([BUILD_JFFSX], [true])])
+
+AC_ARG_WITH([ubifs],
+	[AS_HELP_STRING([--without-ubifs], [Disable ubifs utilities])],
+	[case "${withval}" in
+	yes) AM_CONDITIONAL([BUILD_UBIFS], [true]) ;;
+	no)  AM_CONDITIONAL([BUILD_UBIFS], [false]) ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-ubifs]) ;;
+	esac],
+	[AM_CONDITIONAL([BUILD_UBIFS], [true])])
+
+AM_COND_IF([BUILD_UBIFS], [
+	need_uuid="yes"
+	need_xattr="yes"
+	need_zlib="yes"
+	need_lzo="yes"
+	need_zstd="yes"
+	need_openssl="yes"
+	need_getrandom="yes"
+])
+
+AM_COND_IF([BUILD_JFFSX], [
+	need_xattr="yes"
+	need_zlib="yes"
+	need_lzo="yes"
+])
+
+AC_ARG_WITH([xattr],
+	[AS_HELP_STRING([--without-xattr],
+		[Disable support forextended file attributes])],
+	[case "${withval}" in
+	yes) ;;
+	no) need_xattr="no" ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-xattr]) ;;
+	esac])
+
+AC_ARG_WITH([lzo],
+	[AS_HELP_STRING([--without-lzo], [Disable support for LZO compression])],
+	[case "${withval}" in
+	yes) ;;
+	no) need_lzo="no" ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-lzo]) ;;
+	esac])
+
+AC_ARG_WITH([zstd],
+	[AS_HELP_STRING([--without-zstd], [Disable support for ZSTD compression])],
+	[case "${withval}" in
+	yes) ;;
+	no) need_zstd="no" ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-zstd]) ;;
+	esac])
+
+AC_ARG_WITH([selinux],
+	[AS_HELP_STRING([--with-selinux],
+		[Enable support for selinux extended attributes])],
+	[case "${withval}" in
+	yes) need_selinux="yes";;
+	no) ;;
+	*) AC_MSG_ERROR([bad value ${withval} for --with-selinux]) ;;
+	esac])
+
+AC_ARG_WITH([crypto],
+	[AS_HELP_STRING([--without-crypto],
+		[Disable support for UBIFS crypto features])],
+	[case "${withval}" in
+	yes) ;;
+	no) need_openssl="no";;
+	*) AC_MSG_ERROR([bad value ${withval} for --without-crypto]) ;;
+	esac])
+
+##### search for dependencies #####
+
+clock_gettime_missing="no"
+pthread_missing="no"
+uuid_missing="no"
+zlib_missing="no"
+lzo_missing="no"
+zstd_missing="no"
+xattr_missing="no"
+cmocka_missing="no"
+selinux_missing="no"
+openssl_missing="no"
+getrandom_missing="no"
+
+if test "x$need_zlib" = "xyes"; then
+	PKG_CHECK_MODULES(ZLIB, [zlib], [], [zlib_missing="yes"])
+fi
+
+if test "x$need_selinux" = "xyes"; then
+	PKG_CHECK_MODULES(LIBSELINUX, [libselinux], [], [selinux_missing="yes"])
+fi
+
+if test "x$need_uuid" = "xyes"; then
+	PKG_CHECK_MODULES(UUID, [uuid], [], [uuid_missing="yes"])
+fi
+
+if test "x$need_clock_gettime" = "xyes"; then
+	AC_SEARCH_LIBS([clock_gettime], [rt posix4])
+	AC_CHECK_FUNCS([clock_gettime], [], [clock_gettime_missing="yes"])
+fi
+
+if test "x$need_pthread" = "xyes"; then
+	AX_PTHREAD([], [pthread_missing="yes"])
+fi
+
+if test "x$need_lzo" = "xyes"; then
+	AC_ARG_VAR([LZO_CFLAGS], [C compiler flags for lzo])
+	AC_ARG_VAR([LZO_LIBS], [linker flags for lzo])
+	AC_CHECK_LIB([lzo2], [lzo1x_1_15_compress], [LZO_LIBS="-llzo2"],
+		[AC_CHECK_LIB([lzo],[lzo1x_1_15_compress],[LZO_LIBS="-llzo"],
+			[lzo_missing="yes"]
+		)]
+	)
+fi
+
+if test "x$need_zstd" = "xyes"; then
+	PKG_CHECK_MODULES([ZSTD], [libzstd],, zstd_missing="yes")
+fi
+
+if test "x$need_xattr" = "xyes"; then
+	AC_CHECK_HEADERS([sys/xattr.h], [], [xattr_missing="yes"])
+	AC_CHECK_HEADERS([sys/acl.h], [], [xattr_missing="yes"])
+fi
+
+if test "x$need_selinux" = "xyes"; then
+	AC_CHECK_HEADERS([selinux/selinux.h], [], [selinux_missing="yes"])
+	AC_CHECK_HEADERS([selinux/label.h], [], [selinux_missing="yes"])
+fi
+
+if test "x$need_openssl" = "xyes"; then
+	AC_CHECK_HEADER(openssl/rand.h)
+	PKG_CHECK_MODULES(OPENSSL, [openssl], [], [openssl_missing="yes"])
+fi
+
+if test "x$need_getrandom" = "xyes"; then
+	AC_CHECK_HEADERS([sys/random.h], [], [getrandom_missing="yes"])
+fi
+
+if test "x$need_cmocka" = "xyes"; then
+	PKG_CHECK_MODULES(CMOCKA, [cmocka], [], [cmocka_missing="yes"])
+fi
+
+AC_CHECK_HEADERS([execinfo.h])
+
+##### produce summary on dependencies #####
+
+dep_missing="no"
+
+if test "x$clock_gettime_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find clock_gettime function required for MTD tests])
+	AC_MSG_NOTICE([building test programs can optionally be dissabled])
+	dep_missing="yes"
+fi
+
+if test "x$pthread_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find pthread support required for test programs])
+	AC_MSG_NOTICE([building test programs can optionally be dissabled])
+	dep_missing="yes"
+fi
+
+if test "x$uuid_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find uuid library required for mkfs.ubifs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.ubifs])
+	dep_missing="yes"
+fi
+
+if test "x$zlib_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find ZLIB library required for mkfs programs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.ubifs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.jffs2])
+	dep_missing="yes"
+fi
+
+if test "x$lzo_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find LZO library required for mkfs programs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.ubifs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.jffs2])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without LZO support])
+	dep_missing="yes"
+fi
+
+if test "x$zstd_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find ZSTD library required for mkfs program])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without mkfs.ubifs])
+	AC_MSG_NOTICE([mtd-utils can optionally be built without ZSTD support])
+	dep_missing="yes"
+fi
+
+if test "x$xattr_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find headers for extended attributes])
+	AC_MSG_WARN([disabling XATTR support])
+	need_xattr="no"
+fi
+
+if test "x$selinux_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find headers for selinux library])
+	AC_MSG_WARN([disabling SELINUX support])
+	need_selinux="no"
+fi
+
+if test "x$openssl_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find headers for OpenSSL library])
+	AC_MSG_WARN([disabling OpenSSL support])
+	need_openssl="no"
+fi
+
+if test "x$getrandom_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find headers for getrandom() function])
+	AC_MSG_WARN([disabling UBIFS ubihealthd support])
+	need_getrandom="no"
+fi
+
+if test "x$cmocka_missing" = "xyes"; then
+	AC_MSG_WARN([cannot find CMocka library required for unit tests])
+	AC_MSG_NOTICE([unit tests can optionally be disabled])
+	dep_missing="yes"
+fi
+
+if test "x$dep_missing" = "xyes"; then
+	AC_MSG_ERROR([missing one or more dependencies])
+fi
+
+##### generate output #####
+
+AM_CONDITIONAL([WITHOUT_LZO], [test "x$need_lzo" != "xyes"])
+AM_CONDITIONAL([WITHOUT_ZSTD], [test "x$need_zstd" != "xyes"])
+AM_CONDITIONAL([WITHOUT_XATTR], [test "x$need_xattr" != "xyes"])
+AM_CONDITIONAL([WITH_SELINUX], [test "x$need_selinux" == "xyes"])
+AM_CONDITIONAL([WITH_CRYPTO], [test "x$need_openssl" == "xyes"])
+AM_CONDITIONAL([WITH_GETRANDOM], [test "x$need_getrandom" == "xyes"])
+
+AC_CHECK_SIZEOF([off_t])
+AC_CHECK_SIZEOF([loff_t])
+
+AC_CONFIG_HEADERS([include/config.h])
+
+AC_CONFIG_FILES([tests/fs-tests/fs_help_all.sh
+	tests/fs-tests/fs_run_all.sh
+	tests/fs-tests/stress/fs_stress00.sh
+	tests/fs-tests/stress/fs_stress01.sh
+	tests/ubi-tests/runubitests.sh
+	tests/ubi-tests/ubi-stress-test.sh])
+
+AC_OUTPUT([Makefile])

+ 278 - 0
EVSE/GPL/mtd-utils-2.1.2/include/common.h

@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MTD_UTILS_COMMON_H__
+#define __MTD_UTILS_COMMON_H__
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <features.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/sysmacros.h>
+
+#include "config.h"
+
+#ifndef PROGRAM_NAME
+# error "You must define PROGRAM_NAME before including this header"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN	/* some C lib headers define this for us */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#define min(a, b) MIN(a, b) /* glue for linux kernel source */
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+
+#define min_t(t,x,y) ({ \
+	typeof((x)) _x = (x); \
+	typeof((y)) _y = (y); \
+	(_x < _y) ? _x : _y; \
+})
+
+#define max_t(t,x,y) ({ \
+	typeof((x)) _x = (x); \
+	typeof((y)) _y = (y); \
+	(_x > _y) ? _x : _y; \
+})
+
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+/* Verbose messages */
+#define bareverbose(verbose, fmt, ...) do {                        \
+	if (verbose)                                               \
+		printf(fmt, ##__VA_ARGS__);                        \
+} while(0)
+#define verbose(verbose, fmt, ...) \
+	bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
+
+/* Normal messages */
+#define normsg_cont(fmt, ...) do {                                 \
+	printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__);           \
+} while(0)
+#define normsg(fmt, ...) do {                                      \
+	normsg_cont(fmt "\n", ##__VA_ARGS__);                      \
+} while(0)
+
+/* Error messages */
+#define errmsg(fmt, ...)  ({                                                \
+	fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+	-1;                                                                 \
+})
+#define errmsg_die(fmt, ...) do {                                           \
+	exit(errmsg(fmt, ##__VA_ARGS__));                                   \
+} while(0)
+
+/* System error messages */
+#define sys_errmsg(fmt, ...)  ({                                            \
+	int _err = errno;                                                   \
+	errmsg(fmt, ##__VA_ARGS__);                                         \
+	fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\
+		"", _err, strerror(_err));                                  \
+	-1;                                                                 \
+})
+#define sys_errmsg_die(fmt, ...) do {                                       \
+	exit(sys_errmsg(fmt, ##__VA_ARGS__));                               \
+} while(0)
+
+/* Warnings */
+#define warnmsg(fmt, ...) do {                                                \
+	fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
+} while(0)
+
+/* for tagging functions that always exit */
+#if defined(__GNUC__) || defined(__clang__)
+	#define NORETURN __attribute__((noreturn))
+#else
+	#define NORETURN
+#endif
+
+/**
+ * prompt the user for confirmation
+ */
+static inline bool prompt(const char *msg, bool def)
+{
+	bool ret = def;
+	char line[64];
+
+	do {
+		normsg_cont("%s (%c/%c) ", msg, def ? 'Y' : 'y', def ? 'n' : 'N');
+		fflush(stdout);
+
+		if (fgets(line, sizeof(line), stdin) == NULL) {
+			printf("failed to read prompt; assuming '%s'\n",
+				def ? "yes" : "no");
+			break;
+		}
+
+		if (strcmp("\n", line) != 0) {
+			switch (line[0]) {
+			case 'N':
+			case 'n': ret = false; break;
+			case 'Y':
+			case 'y': ret = true; break;
+			default:
+				puts("unknown response; please try again");
+				continue;
+			}
+		}
+		break;
+	} while (1);
+
+	return ret;
+}
+
+static inline int is_power_of_2(unsigned long long n)
+{
+	return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/* Check whether buffer is filled with character 'pattern' */
+static inline int buffer_check_pattern(unsigned char *buffer, size_t size,
+				       unsigned char pattern)
+{
+	/* Invalid input */
+	if (!buffer || (size == 0))
+		return 0;
+
+	/* No match on first byte */
+	if (*buffer != pattern)
+		return 0;
+
+	/* First byte matched and buffer is 1 byte long, OK. */
+	if (size == 1)
+		return 1;
+
+	/*
+	 * Check buffer longer than 1 byte. We already know that buffer[0]
+	 * matches the pattern, so the test below only checks whether the
+	 * buffer[0...size-2] == buffer[1...size-1] , which is a test for
+	 * whether the buffer is filled with constant value.
+	 */
+	return !memcmp(buffer, buffer + 1, size - 1);
+}
+
+/**
+ * simple_strtoX - convert a hex/dec/oct string into a number
+ * @snum: buffer to convert
+ * @error: set to 1 when buffer isn't fully consumed
+ *
+ * These functions are similar to the standard strtoX() functions, but they are
+ * a little bit easier to use if you want to convert full string of digits into
+ * the binary form. The typical usage:
+ *
+ * int error = 0;
+ * unsigned long num;
+ *
+ * num = simple_strtoul(str, &error);
+ * if (error || ... if needed, your check that num is not out of range ...)
+ * 	error_happened();
+ */
+#define simple_strtoX(func, type) \
+static inline type simple_##func(const char *snum, int *error) \
+{ \
+	char *endptr; \
+	type ret = func(snum, &endptr, 0); \
+ \
+	if (error && (!*snum || *endptr)) { \
+		errmsg("%s: unable to parse the number '%s'", #func, snum); \
+		*error = 1; \
+	} \
+ \
+	return ret; \
+}
+simple_strtoX(strtol, long int)
+simple_strtoX(strtoll, long long int)
+simple_strtoX(strtoul, unsigned long int)
+simple_strtoX(strtoull, unsigned long long int)
+
+/* Simple version-printing for utils */
+#define common_print_version() \
+do { \
+	printf("%s (mtd-utils) %s\n", PROGRAM_NAME, VERSION); \
+} while (0)
+
+#include "xalloc.h"
+
+long long util_get_bytes(const char *str);
+void util_print_bytes(long long bytes, int bracket);
+int util_srand(void);
+
+/*
+ * The following helpers are here to avoid compiler complaints about unchecked
+ * return code.
+ * FIXME: The proper fix would be to check the return code in all those places,
+ * but it's usually placed in old code which have no proper exit path and
+ * handling  errors requires rewriting a lot of code.
+ *
+ * WARNING: Please do not use these helpers in new code. Instead, make sure
+ * you check the function return code and provide coherent error handling in
+ * case of error.
+ */
+static inline ssize_t read_nocheck(int fd, void *buf, size_t count)
+{
+	return read(fd, buf, count);
+}
+
+static inline ssize_t write_nocheck(int fd, void *buf, size_t count)
+{
+	return write(fd, buf, count);
+}
+
+static inline ssize_t pread_nocheck(int fd, void *buf, size_t count,
+				    off_t offset)
+{
+	return pread(fd, buf, count, offset);
+}
+
+static inline ssize_t pwrite_nocheck(int fd, void *buf, size_t count,
+				     off_t offset)
+{
+	return pwrite(fd, buf, count, offset);
+}
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__MTD_UTILS_COMMON_H__ */

+ 13 - 0
EVSE/GPL/mtd-utils-2.1.2/include/crc32.h

@@ -0,0 +1,13 @@
+/*
+ * This code was taken from the linux kernel. The license is GPL Version 2.
+ */
+
+#ifndef __CRC32_H__
+#define __CRC32_H__
+
+#include <stdint.h>
+
+/* Return a 32-bit CRC of the contents of the buffer */
+extern uint32_t mtd_crc32(uint32_t val, const void *ss, int len);
+
+#endif /* __CRC32_H__ */

+ 174 - 0
EVSE/GPL/mtd-utils-2.1.2/include/dictionary.h

@@ -0,0 +1,174 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    dictionary.h
+   @author  N. Devillard
+   @date    Sep 2007
+   @version $Revision: 1.12 $
+   @brief   Implements a dictionary for string variables.
+
+   This module implements a simple dictionary object, i.e. a list
+   of string/string associations. This object is useful to store e.g.
+   informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+	$Id: dictionary.h,v 1.12 2007-11-23 21:37:00 ndevilla Exp $
+	$Author: ndevilla $
+	$Date: 2007-11-23 21:37:00 $
+	$Revision: 1.12 $
+*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+   								Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+   								New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Dictionary object
+
+  This object contains a list of string/string associations. Each
+  association is identified by a unique string key. Looking up values
+  in the dictionary is speeded up by the use of a (hopefully collision-free)
+  hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+	int				n ;		/** Number of entries in dictionary */
+	int				size ;	/** Storage size */
+	char 		**	val ;	/** List of string values */
+	char 		**  key ;	/** List of string keys */
+	unsigned	 *	hash ;	/** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+  							Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Compute the hash key for a string.
+  @param    key     Character string to use for key.
+  @return   1 unsigned int on at least 32 bits.
+
+  This hash function has been taken from an Article in Dr Dobbs Journal.
+  This is normally a collision-free function, distributing keys evenly.
+  The key is stored anyway in the struct so that collision can be avoided
+  by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Create a new dictionary object.
+  @param    size    Optional initial size of the dictionary.
+  @return   1 newly allocated dictionary objet.
+
+  This function allocates a new dictionary object of given size and returns
+  it. If you do not know in advance (roughly) the number of entries in the
+  dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a dictionary object
+  @param    d   dictionary object to deallocate.
+  @return   void
+
+  Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get a value from a dictionary.
+  @param    d       dictionary object to search.
+  @param    key     Key to look for in the dictionary.
+  @param    def     Default value to return if key not found.
+  @return   1 pointer to internally allocated character string.
+
+  This function locates a key in a dictionary and returns a pointer to its
+  value, or the passed 'def' pointer if no such key can be found in
+  dictionary. The returned character pointer points to data internal to the
+  dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set a value in a dictionary.
+  @param    d       dictionary object to modify.
+  @param    key     Key to modify or add.
+  @param    val     Value to add.
+  @return   int     0 if Ok, anything else otherwise
+
+  If the given key is found in the dictionary, the associated value is
+  replaced by the provided one. If the key cannot be found in the
+  dictionary, it is added to it.
+
+  It is Ok to provide a NULL value for val, but NULL values for the dictionary
+  or the key are considered as errors: the function will return immediately
+  in such a case.
+
+  Notice that if you dictionary_set a variable to NULL, a call to
+  dictionary_get will return a NULL value: the variable will be found, and
+  its value (NULL) is returned. In other words, setting the variable
+  content to NULL is equivalent to deleting the variable from the
+  dictionary. It is not possible (in this implementation) to have a key in
+  the dictionary without value.
+
+  This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, char * key, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a key in a dictionary
+  @param    d       dictionary object to modify.
+  @param    key     Key to remove.
+  @return   void
+
+  This function deletes a key in a dictionary. Nothing is done if the
+  key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer.
+  @return   void
+
+  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+  output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif

+ 37 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libfec.h

@@ -0,0 +1,37 @@
+#ifndef LIBFEC_H
+#define LIBFEC_H
+
+struct fec_parms;
+
+/* k - number of actual data packets
+ * n - total number of packets including data and redundant packets
+ *   (actual packet size isn't relevant here) */
+struct fec_parms *fec_new(int k, int n);
+void fec_free(struct fec_parms *p);
+
+/* src   - array of (n) pointers to data packets
+ * fec   - buffer for packet to be generated
+ * index - index of packet to be generated (0 <= index < n)
+ * sz    - data packet size
+ *
+ * _linear version just takes a pointer to the raw data; no
+ * mucking about with packet pointers.
+ */
+void fec_encode(struct fec_parms *code, unsigned char *src[],
+		unsigned char *fec, int index, int sz);
+void fec_encode_linear(struct fec_parms *code, unsigned char *src,
+		       unsigned char *fec, int index, int sz);
+
+/* data  - array of (k) pointers to data packets, in arbitrary order (see i)
+ * i     - indices of (data) packets
+ * sz    - data packet size
+ *
+ * Will never fail as long as you give it (k) individual data packets.
+ * Will re-order the (data) pointers but not the indices -- data packets
+ * are ordered on return.
+ */
+int fec_decode(struct fec_parms *code, unsigned char *data[],
+	       int i[], int sz);
+
+#endif /* LIBFEC_H */
+

+ 265 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libiniparser.h

@@ -0,0 +1,265 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    iniparser.h
+   @author  N. Devillard
+   @date    Sep 2007
+   @version 3.0
+   @brief   Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+	$Id: iniparser.h,v 1.24 2007-11-23 21:38:19 ndevilla Exp $
+	$Revision: 1.24 $
+*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+   								Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+/*---------------------------------------------------------------------------
+   								Macros
+ ---------------------------------------------------------------------------*/
+/** For backwards compatibility only */
+#define iniparser_getstr(d, k)  iniparser_getstring(d, k, NULL)
+#define iniparser_setstr        iniparser_setstring
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get number of sections in a dictionary
+  @param    d   Dictionary to examine
+  @return   int Number of sections found in dictionary
+
+  This function returns the number of sections found in a dictionary.
+  The test to recognize sections is done on the string stored in the
+  dictionary: a section name is given as "section" whereas a key is
+  stored as "section:key", thus the test looks for entries that do not
+  contain a colon.
+
+  This clearly fails in the case a section name contains a colon, but
+  this should simply be avoided.
+
+  This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get name for section n in a dictionary.
+  @param    d   Dictionary to examine
+  @param    n   Section number (from 0 to nsec-1).
+  @return   Pointer to char string
+
+  This function locates the n-th section in a dictionary and returns
+  its name as a pointer to a string statically allocated inside the
+  dictionary. Do not free or modify the returned string!
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given dictionary into a loadable ini file.
+  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump.
+  @param    f   Opened file pointer to dump to.
+  @return   void
+
+  This function prints out the contents of a dictionary, one element by
+  line, onto the provided file pointer. It is OK to specify @c stderr
+  or @c stdout as output files. This function is meant for debugging
+  purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    key     Key string to look for
+  @param    def     Default value to return if key not found.
+  @return   pointer to statically allocated character string
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the pointer passed as 'def' is returned.
+  The returned char pointer is pointing to a string allocated in
+  the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  - "42"      ->  42
+  - "042"     ->  34 (octal -> decimal)
+  - "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+
+  Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a boolean
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  A true boolean is found if one of the following is matched:
+
+  - A string starting with 'y'
+  - A string starting with 'Y'
+  - A string starting with 't'
+  - A string starting with 'T'
+  - A string starting with '1'
+
+  A false boolean is found if one of the following is matched:
+
+  - A string starting with 'n'
+  - A string starting with 'N'
+  - A string starting with 'f'
+  - A string starting with 'F'
+  - A string starting with '0'
+
+  The notfound value returned if no boolean is identified, does not
+  necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set an entry in a dictionary.
+  @param    ini     Dictionary to modify.
+  @param    entry   Entry to modify (entry name)
+  @param    val     New value to associate to the entry.
+  @return   int 0 if Ok, -1 otherwise.
+
+  If the given entry can be found in the dictionary, it is modified to
+  contain the provided value. If it cannot be found, -1 is returned.
+  It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_setstring(dictionary * ini, char * entry, char * val);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete an entry in a dictionary
+  @param    ini     Dictionary to modify
+  @param    entry   Entry to delete (entry name)
+  @return   void
+
+  If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Finds out if a given entry exists in a dictionary
+  @param    ini     Dictionary to search
+  @param    entry   Name of the entry to look for
+  @return   integer 1 if entry exists, 0 otherwise
+
+  Finds out if a given entry exists in the dictionary. Since sections
+  are stored as keys with NULL associated values, this is the only way
+  of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(dictionary * ini, char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Parse an ini file and return an allocated dictionary object
+  @param    ininame Name of the ini file to read.
+  @return   Pointer to newly allocated dictionary
+
+  This is the parser for ini files. This function is called, providing
+  the name of the file to be read. It returns a dictionary object that
+  should not be accessed directly, but through accessor functions
+  instead.
+
+  The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Free all memory associated to an ini dictionary
+  @param    d Dictionary to free
+  @return   void
+
+  Free all memory associated to an ini dictionary.
+  It is mandatory to call this function before the dictionary object
+  gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#endif

+ 17 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libmissing.h

@@ -0,0 +1,17 @@
+#ifndef LIBMISSING_H
+#define LIBMISSING_H
+
+#include "config.h"
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifndef HAVE_EXECINFO_H
+int backtrace(void **buffer, int size);
+char **backtrace_symbols(void *const *buffer, int size);
+void backtrace_symbols_fd(void *const *buffer, int size, int fd);
+#endif
+
+#endif /* LIBMISSING_H */
+

+ 352 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libmtd.h

@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2008, 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#ifndef __LIBMTD_H__
+#define __LIBMTD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maximum MTD device name length */
+#define MTD_NAME_MAX 127
+/* Maximum MTD device type string length */
+#define MTD_TYPE_MAX 64
+
+/* MTD library descriptor */
+typedef void * libmtd_t;
+
+/* Forward decls */
+struct region_info_user;
+
+/**
+ * @mtd_dev_cnt: count of MTD devices in system
+ * @lowest_mtd_num: lowest MTD device number in system
+ * @highest_mtd_num: highest MTD device number in system
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ */
+struct mtd_info
+{
+	int mtd_dev_cnt;
+	int lowest_mtd_num;
+	int highest_mtd_num;
+	unsigned int sysfs_supported:1;
+};
+
+/**
+ * struct mtd_dev_info - information about an MTD device.
+ * @mtd_num: MTD device number
+ * @major: major number of corresponding character device
+ * @minor: minor number of corresponding character device
+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
+ * @type_str: static R/O flash type string
+ * @name: device name
+ * @size: device size in bytes
+ * @eb_cnt: count of eraseblocks
+ * @eb_size: eraseblock size
+ * @min_io_size: minimum input/output unit size
+ * @subpage_size: sub-page size
+ * @oob_size: OOB size (zero if the device does not have OOB area)
+ * @oobavail: free OOB size
+ * @region_cnt: count of additional erase regions
+ * @writable: zero if the device is read-only
+ * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
+ */
+struct mtd_dev_info
+{
+	int mtd_num;
+	int major;
+	int minor;
+	int type;
+	const char type_str[MTD_TYPE_MAX + 1];
+	const char name[MTD_NAME_MAX + 1];
+	long long size;
+	int eb_cnt;
+	int eb_size;
+	int min_io_size;
+	int subpage_size;
+	int oob_size;
+	int oobavail;
+	int region_cnt;
+	unsigned int writable:1;
+	unsigned int bb_allowed:1;
+};
+
+/**
+ * libmtd_open - open MTD library.
+ *
+ * This function initializes and opens the MTD library and returns MTD library
+ * descriptor in case of success and %NULL in case of failure. In case of
+ * failure, errno contains zero if MTD is not present in the system, or
+ * contains the error code if a real error happened.
+ */
+libmtd_t libmtd_open(void);
+
+/**
+ * libmtd_close - close MTD library.
+ * @desc: MTD library descriptor
+ */
+void libmtd_close(libmtd_t desc);
+
+/**
+ * mtd_dev_present - check whether a MTD device is present.
+ * @desc: MTD library descriptor
+ * @mtd_num: MTD device number to check
+ *
+ * This function returns %1 if MTD device is present and %0 if not.
+ */
+int mtd_dev_present(libmtd_t desc, int mtd_num);
+
+/**
+ * mtd_get_info - get general MTD information.
+ * @desc: MTD library descriptor
+ * @info: the MTD device information is returned here
+ *
+ * This function fills the passed @info object with general MTD information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_get_info(libmtd_t desc, struct mtd_info *info);
+
+/**
+ * mtd_get_dev_info - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function gets information about MTD device defined by the @node device
+ * node file and saves this information in the @mtd object. Returns %0 in case
+ * of success and %-1 in case of failure. If MTD subsystem is not present in the
+ * system, or the MTD device does not exist, errno is set to @ENODEV.
+ */
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_get_dev_info1 - get information about an MTD device.
+ * @desc: MTD library descriptor
+ * @mtd_num: MTD device number to fetch information about
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is identical to 'mtd_get_dev_info()' except that it accepts
+ * MTD device number, not MTD character device.
+ */
+int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd);
+
+/**
+ * mtd_lock - lock eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to lock
+ *
+ * This function locks eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_unlock - unlock eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to lock
+ *
+ * This function unlocks eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_erase - erase multiple eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: index of first eraseblock to erase
+ * @blocks: the number of eraseblocks to erase
+ *
+ * This function erases @blocks starting at eraseblock @eb of MTD device
+ * described by @fd. Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_erase_multi(libmtd_t desc, const struct mtd_dev_info *mtd,
+			int fd, int eb, int blocks);
+
+/**
+ * mtd_erase - erase an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to erase
+ *
+ * This function erases eraseblock @eb of MTD device described by @fd. Returns
+ * %0 in case of success and %-1 in case of failure.
+ */
+int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_regioninfo - get information about an erase region.
+ * @fd: MTD device node file descriptor
+ * @regidx: index of region to look up
+ * @reginfo: the region information is returned here
+ *
+ * This function gets information about an erase region defined by the
+ * @regidx index and saves this information in the @reginfo object.
+ * Returns %0 in case of success and %-1 in case of failure. If the
+ * @regidx is not valid or unavailable, errno is set to @ENODEV.
+ */
+int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo);
+
+/**
+ * mtd_is_locked - see if the specified eraseblock is locked.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to check
+ *
+ * This function checks to see if eraseblock @eb of MTD device described
+ * by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and
+ * %-1 in case of failure. If the ioctl is not supported (support was added in
+ * Linux kernel 2.6.36) or this particular device does not support it, errno is
+ * set to @ENOTSUPP.
+ */
+int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_torture - torture an eraseblock.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to torture
+ *
+ * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_is_bad - check if eraseblock is bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to check
+ *
+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
+ * and %-1 in case of failure.
+ */
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_mark_bad - mark an eraseblock as bad.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to mark as bad
+ *
+ * This function marks eraseblock @eb as bad. Returns %0 in case of success and
+ * %-1 in case of failure.
+ */
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
+
+/**
+ * mtd_read - read data from an MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to read from
+ * @offs: offset withing the eraseblock to read from
+ * @buf: buffer to read data to
+ * @len: how many bytes to read
+ *
+ * This function reads @len bytes of data from eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd and stores the read data at buffer @buf.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+	     void *buf, int len);
+
+/**
+ * mtd_write - write data to an MTD device.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @data: data buffer to write
+ * @len: how many data bytes to write
+ * @oob: OOB buffer to write
+ * @ooblen: how many OOB bytes to write
+ * @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW)
+ *
+ * This function writes @len bytes of data to eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
+ * case of failure.
+ *
+ * Can only write to a single page at a time if writing to OOB.
+ */
+int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
+	      int offs, void *data, int len, void *oob, int ooblen,
+	      uint8_t mode);
+
+/**
+ * mtd_read_oob - read out-of-band area.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @start: page-aligned start address
+ * @length: number of OOB bytes to read
+ * @data: read buffer
+ *
+ * This function reads @length OOB bytes starting from address @start on
+ * MTD device described by @fd. The address is specified as page byte offset
+ * from the beginning of the MTD device. This function returns %0 in case of
+ * success and %-1 in case of failure.
+ */
+int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+		 uint64_t start, uint64_t length, void *data);
+
+/**
+ * mtd_write_oob - write out-of-band area.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @start: page-aligned start address
+ * @length: number of OOB bytes to write
+ * @data: write buffer
+ *
+ * This function writes @length OOB bytes starting from address @start on
+ * MTD device described by @fd. The address is specified as page byte offset
+ * from the beginning of the MTD device. Returns %0 in case of success and %-1
+ * in case of failure.
+ */
+int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+		  uint64_t start, uint64_t length, void *data);
+
+/**
+ * mtd_probe_node - test MTD node.
+ * @desc: MTD library descriptor
+ * @node: the node to test
+ *
+ * This function tests whether @node is an MTD device node and returns %1 if it
+ * is, and %-1 if it is not (errno is %ENODEV in this case) or if an error
+ * occurred.
+ */
+int mtd_probe_node(libmtd_t desc, const char *node);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBMTD_H__ */

+ 113 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libscan.h

@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#ifndef __LIBSCAN_H__
+#define __LIBSCAN_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If an eraseblock does not contain an erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define NO_EC 0xFFFFFFFF
+
+/*
+ * If an eraseblock contains a corrupted erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define CORRUPT_EC 0xFFFFFFFE
+
+/*
+ * If an eraseblock does not contain an erase counter, one of these values is
+ * used.
+ *
+ * @EB_EMPTY: the eraseblock appeared to be empty
+ * @EB_CORRUPTED: the eraseblock contains corrupted erase counter header
+ * @EB_ALIEN: the eraseblock contains some non-UBI data
+ * @EC_MAX: maximum allowed erase counter value
+ */
+enum
+{
+	EB_EMPTY     = 0xFFFFFFFF,
+	EB_CORRUPTED = 0xFFFFFFFE,
+	EB_ALIEN     = 0xFFFFFFFD,
+	EB_BAD       = 0xFFFFFFFC,
+	EC_MAX       = UBI_MAX_ERASECOUNTER,
+};
+
+/**
+ * struct ubi_scan_info - UBI scanning information.
+ * @ec: erase counters or eraseblock status for all eraseblocks
+ * @mean_ec: mean erase counter
+ * @ok_cnt: count of eraseblock with correct erase counter header
+ * @empty_cnt: count of supposedly eraseblocks
+ * @corrupted_cnt: count of eraseblocks with corrupted erase counter header
+ * @alien_cnt: count of eraseblock containing non-ubi data
+ * @bad_cnt: count of bad eraseblocks
+ * @good_cnt: count of non-bad eraseblocks
+ * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
+ *                undefined)
+ * @data_offs: data offset from the found EC headers (%-1 means undefined)
+ */
+struct ubi_scan_info
+{
+	uint32_t *ec;
+	long long mean_ec;
+	int ok_cnt;
+	int empty_cnt;
+	int corrupted_cnt;
+	int alien_cnt;
+	int bad_cnt;
+	int good_cnt;
+	int vid_hdr_offs;
+	int data_offs;
+};
+
+struct mtd_dev_info;
+
+/**
+ * ubi_scan - scan an MTD device.
+ * @mtd: information about the MTD device to scan
+ * @fd: MTD device node file descriptor
+ * @info: the result of the scanning is returned here
+ * @verbose: verbose mode: %0 - be silent, %1 - output progress information,
+ *           2 - debugging output mode
+ */
+int ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+	     int verbose);
+
+/**
+ * ubi_scan_free - free scanning information.
+ * @si: scanning information to free
+ */
+void ubi_scan_free(struct ubi_scan_info *si);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBSCAN_H__ */

+ 489 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libubi.h

@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_H__
+#define __LIBUBI_H__
+
+#include <ctype.h>
+#include <stdint.h>
+#include <mtd/ubi-user.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* UBI version libubi is made for */
+#define LIBUBI_UBI_VERSION 1
+
+/* Maximum physical eraseblock size in bytes */
+#define UBI_MAX_PEB_SZ (2*1024*1024)
+
+/* The maximum volume name length (from Linux's ubi-media.h) */
+#define UBI_VOL_NAME_MAX 127
+
+/* UBI library descriptor */
+typedef void * libubi_t;
+
+/**
+ * struct ubi_attach_request - MTD device attachment request.
+ * @dev_num: number to assign to the newly created UBI device
+ *           (%UBI_DEV_NUM_AUTO should be used to automatically assign the
+ *           number)
+ * @mtd_num: MTD device number to attach (used if @mtd_dev_node is %NULL)
+ * @mtd_dev_node: path to MTD device node to attach
+ * @vid_hdr_offset: VID header offset (%0 means default offset and this is what
+ *                  most of the users want)
+ * @max_beb_per1024: Maximum expected bad eraseblocks per 1024 eraseblocks
+ */
+struct ubi_attach_request
+{
+	int dev_num;
+	int mtd_num;
+	const char *mtd_dev_node;
+	int vid_hdr_offset;
+	int max_beb_per1024;
+};
+
+/**
+ * struct ubi_mkvol_request - volume creation request.
+ * @vol_id: ID to assign to the new volume (%UBI_VOL_NUM_AUTO should be used to
+ *          automatically assign ID)
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @name: volume name
+ * @flags: volume flags
+ */
+struct ubi_mkvol_request
+{
+	int vol_id;
+	int alignment;
+	long long bytes;
+	int vol_type;
+	const char *name;
+	uint8_t flags;
+};
+
+/**
+ * struct ubi_info - general UBI information.
+ * @dev_count: count of UBI devices in system
+ * @lowest_dev_num: lowest UBI device number
+ * @highest_dev_num: highest UBI device number
+ * @version: UBI version
+ * @ctrl_major: major number of the UBI control device
+ * @ctrl_minor: minor number of the UBI control device
+ */
+struct ubi_info
+{
+	int dev_count;
+	int lowest_dev_num;
+	int highest_dev_num;
+	int version;
+	int ctrl_major;
+	int ctrl_minor;
+};
+
+/**
+ * struct ubi_dev_info - UBI device information.
+ * @dev_num: UBI device number
+ * @mtd_num: MTD device number on top of which this UBI device is working
+ * @vol_count: count of volumes on this UBI device
+ * @lowest_vol_id: lowest volume ID
+ * @highest_vol_id: highest volume ID
+ * @major: major number of corresponding character device
+ * @minor: minor number of corresponding character device
+ * @total_lebs: total number of logical eraseblocks on this UBI device
+ * @avail_lebs: how many logical eraseblocks are not used and available for new
+ *             volumes
+ * @total_bytes: @total_lebs * @leb_size
+ * @avail_bytes: @avail_lebs * @leb_size
+ * @bad_count: count of bad physical eraseblocks
+ * @leb_size: logical eraseblock size
+ * @max_ec: current highest erase counter value
+ * @bad_rsvd: how many physical eraseblocks of the underlying flash device are
+ *            reserved for bad eraseblocks handling
+ * @max_vol_count: maximum possible number of volumes on this UBI device
+ * @min_io_size: minimum input/output unit size of the UBI device
+ */
+struct ubi_dev_info
+{
+	int dev_num;
+	int mtd_num;
+	int vol_count;
+	int lowest_vol_id;
+	int highest_vol_id;
+	int major;
+	int minor;
+	int total_lebs;
+	int avail_lebs;
+	long long total_bytes;
+	long long avail_bytes;
+	int bad_count;
+	int leb_size;
+	long long max_ec;
+	int bad_rsvd;
+	int max_vol_count;
+	int min_io_size;
+};
+
+/**
+ * struct ubi_vol_info - UBI volume information.
+ * @dev_num: UBI device number the volume resides on
+ * @vol_id: ID of this volume
+ * @major: major number of corresponding volume character device
+ * @minor: minor number of corresponding volume character device
+ * @type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @alignment: alignment of this volume
+ * @data_bytes: how many data bytes are stored on this volume (equivalent to
+ *              @rsvd_bytes for dynamic volumes)
+ * @rsvd_bytes: how many bytes are reserved for this volume
+ * @rsvd_lebs: how many logical eraseblocks are reserved for this volume
+ * @leb_size: logical eraseblock size of this volume (may be less then
+ *            device's logical eraseblock size due to alignment)
+ * @corrupted: non-zero if the volume is corrupted
+ * @name: volume name (null-terminated)
+ */
+struct ubi_vol_info
+{
+	int dev_num;
+	int vol_id;
+	int major;
+	int minor;
+	int type;
+	int alignment;
+	long long data_bytes;
+	long long rsvd_bytes;
+	int rsvd_lebs;
+	int leb_size;
+	int corrupted;
+	char name[UBI_VOL_NAME_MAX + 1];
+};
+
+/**
+ * libubi_open - open UBI library.
+ *
+ * This function initializes and opens the UBI library and returns UBI library
+ * descriptor in case of success and %NULL in case of failure. In case of
+ * failure, errno contains the error code or zero if UBI is not present in the
+ * system.
+ */
+libubi_t libubi_open(void);
+
+/**
+ * libubi_close - close UBI library.
+ * @desc: UBI library descriptor
+ */
+void libubi_close(libubi_t desc);
+
+/**
+ * ubi_get_info - get general UBI information.
+ * @desc: UBI library descriptor
+ * @info: pointer to the &struct ubi_info object to fill
+ *
+ * This function fills the passed @info object with general UBI information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_info(libubi_t desc, struct ubi_info *info);
+
+/**
+ * mtd_num2ubi_dev - find UBI device by attached MTD device.
+ * @@desc: UBI library descriptor
+ * @mtd_num: MTD device number
+ * @dev_num: UBI device number is returned here
+ *
+ * This function finds UBI device to which MTD device @mtd_num is attached.
+ * Returns %0 if the UBI device was found and %-1 if not.
+ */
+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num);
+
+/**
+ * ubi_attach - attach an MTD device by its node path or bt MTD device number
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @req: MTD attach request
+ *
+ * This function creates new UBI device by attaching an MTD device described by
+ * @req. If @req->mtd_dev_node is given it should contain path to the MTD
+ * device node. Otherwise @req->mtd_num will be used.
+ *
+ * Returns %0 in case of success, %-1 in case of failure (errno is set) and %1
+ * if parameter @req->max_beb_per1024 was ignored by kernel (because the kernel
+ * is old and does not support this feature, which was added in 3.7). The newly
+ * created UBI device number is returned in @req->dev_num. In the MTD device
+ * was specified by its device node path, the MTD device number is returned in
+ * @req->mtd_num.
+ */
+int ubi_attach(libubi_t desc, const char *node, struct ubi_attach_request *req);
+
+/**
+ * ubi_detach_mtd - detach an MTD device.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @mtd_num: MTD device number to detach
+ *
+ * This function detaches MTD device number @mtd_num from UBI, which means the
+ * corresponding UBI device is removed. Returns zero in case of success and %-1
+ * in case of failure.
+ */
+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num);
+
+/**
+ * ubi_detach - detach an MTD device by its node path.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @mtd_dev_node: path to an MTD device node
+ *
+ * This function detaches an MTD device @mtd_dev_node from UBI. Returns zero in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_detach(libubi_t desc, const char *node, const char *mtd_dev_node);
+
+/**
+ * ubi_remove_dev - remove an UBI device.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @ubi_dev: UBI device number to remove
+ *
+ * This function removes UBI device number @ubi_dev and returns zero in case of
+ * success and %-1 in case of failure.
+ */
+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev);
+
+/**
+ * ubi_mkvol - create an UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to create a volume at
+ * @req: UBI volume creation request
+ *
+ * This function creates a UBI volume as described at @req and returns %0 in
+ * case of success and %-1 in case of failure. The assigned volume ID is
+ * returned in @req->vol_id.
+ */
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req);
+
+/**
+ * ubi_rmvol - remove a UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to remove a volume from
+ * @vol_id: ID of the volume to remove
+ *
+ * This function removes volume @vol_id from UBI device @node and returns %0 in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id);
+
+
+/**
+ * ubi_rnvols - rename UBI volumes.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to remove a volume from
+ * @rnvol: description of volumes to rename
+ *
+ * This function removes volume @vol_id from UBI device @node and returns %0 in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_rnvols(libubi_t desc, const char *node, struct ubi_rnvol_req *rnvol);
+
+/**
+ * ubi_rsvol - re-size UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device owning the volume which should be
+ *        re-sized
+ * @vol_id: volume ID to re-size
+ * @bytes: new volume size in bytes
+ *
+ * This function returns %0 in case of success and %-1 in case of error.
+ */
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
+
+/**
+ * ubi_probe_node - test UBI node.
+ * @desc: UBI library descriptor
+ * @node: the node to test
+ *
+ * This function tests whether @node is a UBI device or volume node and returns
+ * %1 if this is an UBI device node, %2 if this is a volume node, and %-1 if
+ * this is not an UBI device or volume node (errno is ENODEV in this case) or
+ * if an error occurred.
+ */
+int ubi_probe_node(libubi_t desc, const char *node);
+
+/**
+ * ubi_get_dev_info - get UBI device information.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to fetch information about
+ * @info: pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function fills the passed @info object with UBI device information and
+ * returns %0 in case of success and %-1 in case of failure. If the UBI device
+ * corresponding to @node does not exist, errno is set to @ENODEV.
+ */
+int ubi_get_dev_info(libubi_t desc, const char *node,
+		     struct ubi_dev_info *info);
+
+/**
+ * ubi_dev_present - check whether an UBI device is present.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number to check
+ *
+ * This function returns %1 if UBI device is present and %0 if not.
+ */
+int ubi_dev_present(libubi_t desc, int dev_num);
+
+/**
+ * ubi_get_dev_info1 - get UBI device information.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number to fetch information about
+ * @info: pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI
+ * device number, not UBI character device. If the UBI device @dev_num does not
+ * exist, errno is set to @ENODEV.
+ */
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info);
+
+/**
+ * ubi_get_vol_info - get UBI volume information.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI volume character device to fetch information about
+ * @info: pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function fills the passed @info object with UBI volume information and
+ * returns %0 in case of success and %-1 in case of failure. If the UBI volume
+ * corresponding to @node does not exist, errno is set to @ENODEV.
+ */
+int ubi_get_vol_info(libubi_t desc, const char *node,
+		     struct ubi_vol_info *info);
+
+/**
+ * ubi_get_vol_info1 - get UBI volume information.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number
+ * @vol_id: ID of the UBI volume to fetch information about
+ * @info: pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
+ * volume ID, not UBI volume character device. If the UBI device @dev_num does
+ * not exist, or if the UBI volume @vol_id does not exist, errno is set to
+ * @ENODEV.
+ */
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+		      struct ubi_vol_info *info);
+
+/**
+ * ubi_get_vol_info1_nm - get UBI volume information by volume name.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number
+ * @name: name of the UBI volume to fetch information about
+ * @info: pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
+ * volume name, not UBI volume ID. If the UBI device @dev_num does not exist,
+ * or if the UBI volume @name does not exist, errno is set to @ENODEV.
+ */
+int ubi_get_vol_info1_nm(libubi_t desc, int dev_num, const char *name,
+			 struct ubi_vol_info *info);
+
+/**
+ * ubi_vol_block_create - create a block device on top of an UBI volume.
+ * @fd: volume character device file descriptor
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_vol_block_create(int fd);
+
+/**
+ * ubi_vol_block_remove - remove a block device from an UBI volume.
+ * @fd: volume character device file descriptor
+ *
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_vol_block_remove(int fd);
+
+/**
+ * ubi_update_start - start UBI volume update.
+ * @desc: UBI library descriptor
+ * @fd: volume character device file descriptor
+ * @bytes: how many bytes will be written to the volume
+ *
+ * This function initiates UBI volume update and returns %0 in case of success
+ * and %-1 in case of error. The caller is assumed to write @bytes data to the
+ * volume @fd afterward.
+ */
+int ubi_update_start(libubi_t desc, int fd, long long bytes);
+
+/**
+ * ubi_leb_change_start - start atomic LEB change.
+ * @desc: UBI library descriptor
+ * @fd: volume character device file descriptor
+ * @lnum: LEB number to change
+ * @bytes: how many bytes of new data will be written to the LEB
+ *
+ * This function initiates atomic LEB change operation and returns %0 in case
+ * of success and %-1 in case of error. he caller is assumed to write @bytes
+ * data to the volume @fd afterward.
+ */
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes);
+
+/**
+ * ubi_set_property - set volume propety.
+ * @fd: volume character device file descriptor
+ * @property: the property to change (%UBI_VOL_PROP_DIRECT_WRITE, etc)
+ * @value: new value of the changed property
+ *
+ * This function changes a property of a volume. Returns zero in case of
+ * success and a negative error code in case of error.
+ */
+int ubi_set_property(int fd, uint8_t property, uint64_t value);
+
+/**
+ * ubi_leb_unmap - unmap a logical eraseblock.
+ * @fd: volume character device file descriptor
+ * @lnum: logical eraseblock to unmap
+ *
+ * This function unmaps LEB @lnum and returns zero in case of success and a
+ * negative error code in case of error.
+ */
+int ubi_leb_unmap(int fd, int lnum);
+
+/**
+ * ubi_is_mapped - check if logical eraseblock is mapped.
+ * @fd: volume character device file descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function checks if logical eraseblock @lnum is mapped to a physical
+ * eraseblock. If a logical eraseblock is un-mapped, this does not necessarily
+ * mean it will still be un-mapped after the UBI device is re-attached. The
+ * logical eraseblock may become mapped to the physical eraseblock it was last
+ * mapped to.
+ *
+ * This function returns %1 if the LEB is mapped, %0 if not, and %-1 in case of
+ * failure. If the volume is damaged because of an interrupted update errno
+ * set with %EBADF error code.
+ */
+int ubi_is_mapped(int fd, int lnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_H__ */

+ 194 - 0
EVSE/GPL/mtd-utils-2.1.2/include/libubigen.h

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Frank Haverkamp
+ *          Artem Bityutskiy
+ */
+
+#ifndef __LIBUBIGEN_H__
+#define __LIBUBIGEN_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * struct ubigen_info - libubigen information.
+ * @leb_size: logical eraseblock size
+ * @peb_size: size of the physical eraseblock
+ * @min_io_size: minimum input/output unit size
+ * @vid_hdr_offs: offset of the VID header
+ * @data_offs: data offset
+ * @ubi_ver: UBI version
+ * @vtbl_size: volume table size
+ * @max_volumes: maximum amount of volumes
+ * @image_seq: UBI image sequence number
+ */
+struct ubigen_info
+{
+	int leb_size;
+	int peb_size;
+	int min_io_size;
+	int vid_hdr_offs;
+	int data_offs;
+	int ubi_ver;
+	int vtbl_size;
+	int max_volumes;
+	uint32_t image_seq;
+};
+
+/**
+ * struct ubigen_vol_info - information about a volume.
+ * @id: volume id
+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ *            eraseblock to satisfy the requested alignment
+ * @usable_leb_size: LEB size accessible for volume users
+ * @name: volume name
+ * @name_len: volume name length
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ *          %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant
+ *            for static volumes only)
+ * @bytes: size of the volume contents in bytes (relevant for static volumes
+ *         only)
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ */
+struct ubigen_vol_info
+{
+	int id;
+	int type;
+	int alignment;
+	int data_pad;
+	int usable_leb_size;
+	const char *name;
+	int name_len;
+	int compat;
+	int used_ebs;
+	long long bytes;
+	uint8_t flags;
+};
+
+/**
+ * ubigen_info_init - initialize libubigen.
+ * @ui: libubigen information
+ * @peb_size: flash physical eraseblock size
+ * @min_io_size: flash minimum input/output unit size
+ * @subpage_size: flash sub-page, if present (has to be equivalent to
+ *                @min_io_size if does not exist)
+ * @vid_hdr_offs: offset of the VID header
+ * @ubi_ver: UBI version
+ * @image_seq: UBI image sequence number
+ */
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+		      int subpage_size, int vid_hdr_offs, int ubi_ver,
+		      uint32_t image_seq);
+
+/**
+ * ubigen_create_empty_vtbl - creates empty volume table.
+ * @ui: libubigen information
+ *
+ * This function creates an empty volume table and returns a pointer to it in
+ * case of success and %NULL in case of failure. The returned object has to be
+ * freed with 'free()' call.
+ */
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui);
+
+/**
+ * ubigen_init_ec_hdr - initialize EC header.
+ * @ui: libubigen information
+ * @hdr: the EC header to initialize
+ * @ec: erase counter value
+ */
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+		        struct ubi_ec_hdr *hdr, long long ec);
+
+/**
+ * ubigen_init_vid_hdr - initialize VID header.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @hdr: the VID header to initialize
+ * @lnum: logical eraseblock number
+ * @data: the contents of the LEB (static volumes only)
+ * @data_size: amount of data in this LEB (static volumes only)
+ *
+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
+ * volumes.
+ */
+void ubigen_init_vid_hdr(const struct ubigen_info *ui,
+			 const struct ubigen_vol_info *vi,
+			 struct ubi_vid_hdr *hdr, int lnum,
+			 const void *data, int data_size);
+
+/**
+ * ubigen_add_volume - add a volume to the volume table.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @vtbl: volume table to add to
+ *
+ * This function adds volume described by input parameters to the volume table
+ * @vtbl.
+ */
+int ubigen_add_volume(const struct ubigen_info *ui,
+		      const struct ubigen_vol_info *vi,
+		      struct ubi_vtbl_record *vtbl);
+
+/**
+ * ubigen_write_volume - write UBI volume.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @ec: erase counter value to put to EC headers
+ * @bytes: volume size in bytes
+ * @in: input file descriptor (has to be properly seeked)
+ * @out: output file descriptor
+ *
+ * This function reads the contents of the volume from the input file @in and
+ * writes the UBI volume to the output file @out. Returns zero on success and
+ * %-1 on failure.
+ */
+int ubigen_write_volume(const struct ubigen_info *ui,
+			const struct ubigen_vol_info *vi, long long ec,
+			long long bytes, int in, int out);
+
+/**
+ * ubigen_write_layout_vol - write UBI layout volume
+ * @ui: libubigen information
+ * @peb1: physical eraseblock number to write the first volume table copy
+ * @peb2: physical eraseblock number to write the second volume table copy
+ * @ec1: erase counter value for @peb1
+ * @ec2: erase counter value for @peb1
+ * @vtbl: volume table
+ * @fd: output file descriptor seeked to the proper position
+ *
+ * This function creates the UBI layout volume which contains 2 copies of the
+ * volume table. Returns zero in case of success and %-1 in case of failure.
+ */
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+			    long long ec1, long long ec2,
+			    struct ubi_vtbl_record *vtbl, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBIGEN_H__ */

+ 218 - 0
EVSE/GPL/mtd-utils-2.1.2/include/linux/jffs2.h

@@ -0,0 +1,218 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ *
+ * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $
+ *
+ */
+
+#ifndef __LINUX_JFFS2_H__
+#define __LINUX_JFFS2_H__
+
+/* You must include something which defines the C99 uintXX_t types.
+   We don't do it from here because this file is used in too many
+   different environments. */
+
+#define JFFS2_SUPER_MAGIC 0x72b6
+
+/* Values we may expect to find in the 'magic' field */
+#define JFFS2_OLD_MAGIC_BITMASK 0x1984
+#define JFFS2_MAGIC_BITMASK 0x1985
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
+#define JFFS2_EMPTY_BITMASK 0xffff
+#define JFFS2_DIRTY_BITMASK 0x0000
+
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC	0x02851885
+
+/* We only allow a single char for length, and 0xFF is empty flash so
+   we don't want it confused with a real length. Hence max 254.
+*/
+#define JFFS2_MAX_NAME_LEN 254
+
+/* How small can we sensibly write nodes? */
+#define JFFS2_MIN_DATA_LEN 128
+
+#define JFFS2_COMPR_NONE	0x00
+#define JFFS2_COMPR_ZERO	0x01
+#define JFFS2_COMPR_RTIME	0x02
+#define JFFS2_COMPR_RUBINMIPS	0x03
+#define JFFS2_COMPR_COPY	0x04
+#define JFFS2_COMPR_DYNRUBIN	0x05
+#define JFFS2_COMPR_ZLIB	0x06
+#define JFFS2_COMPR_LZO		0x07
+/* Compatibility flags. */
+#define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+#define JFFS2_NODE_ACCURATE 0x2000
+/* INCOMPAT: Fail to mount the filesystem */
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+/* ROCOMPAT: Mount read-only */
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER		1	/* for "user." */
+#define JFFS2_XPREFIX_SECURITY		2	/* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION		0x0001
+
+// Maybe later...
+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
+
+
+#define JFFS2_INO_FLAG_PREREAD	  1	/* Do read_inode() for this one at
+					   mount time, don't wait for it to
+					   happen later */
+#define JFFS2_INO_FLAG_USERCOMPR  2	/* User has requested a specific
+					   compression type */
+
+
+/* These can go once we've made sure we've caught all uses without
+   byteswapping */
+
+typedef struct {
+	uint32_t v32;
+} __attribute__((packed))  jint32_t;
+
+typedef struct {
+	uint32_t m;
+} __attribute__((packed))  jmode_t;
+
+typedef struct {
+	uint16_t v16;
+} __attribute__((packed)) jint16_t;
+
+struct jffs2_unknown_node
+{
+	/* All start like this */
+	jint16_t magic;
+	jint16_t nodetype;
+	jint32_t totlen; /* So we can skip over nodes we don't grok */
+	jint32_t hdr_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_dirent
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_DIRENT */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t pino;
+	jint32_t version;
+	jint32_t ino; /* == zero for unlink */
+	jint32_t mctime;
+	uint8_t nsize;
+	uint8_t type;
+	uint8_t unused[2];
+	jint32_t node_crc;
+	jint32_t name_crc;
+	uint8_t name[0];
+} __attribute__((packed));
+
+/* The JFFS2 raw inode structure: Used for storage on physical media.  */
+/* The uid, gid, atime, mtime and ctime members could be longer, but
+   are left like this for space efficiency. If and when people decide
+   they really need them extended, it's simple enough to add support for
+   a new type of raw node.
+*/
+struct jffs2_raw_inode
+{
+	jint16_t magic;      /* A constant magic number.  */
+	jint16_t nodetype;   /* == JFFS2_NODETYPE_INODE */
+	jint32_t totlen;     /* Total length of this node (inc data, etc.) */
+	jint32_t hdr_crc;
+	jint32_t ino;        /* Inode number.  */
+	jint32_t version;    /* Version number.  */
+	jmode_t mode;       /* The file's type or mode.  */
+	jint16_t uid;        /* The file's owner.  */
+	jint16_t gid;        /* The file's group.  */
+	jint32_t isize;      /* Total resultant size of this inode (used for truncations)  */
+	jint32_t atime;      /* Last access time.  */
+	jint32_t mtime;      /* Last modification time.  */
+	jint32_t ctime;      /* Change time.  */
+	jint32_t offset;     /* Where to begin to write.  */
+	jint32_t csize;      /* (Compressed) data size */
+	jint32_t dsize;	     /* Size of the node's data. (after decompression) */
+	uint8_t compr;       /* Compression algorithm used */
+	uint8_t usercompr;   /* Compression algorithm requested by the user */
+	jint16_t flags;	     /* See JFFS2_INO_FLAG_* */
+	jint32_t data_crc;   /* CRC for the (compressed) data.  */
+	jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xattr {
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t version;
+	uint8_t xprefix;
+	uint8_t name_len;
+	jint16_t value_len;
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t xseqno;	/* xref sequencial number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_summary
+{
+	jint16_t magic;
+	jint16_t nodetype; 	/* = JFFS2_NODETYPE_SUMMARY */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t sum_num;	/* number of sum entries*/
+	jint32_t cln_mkr;	/* clean marker size, 0 = no cleanmarker */
+	jint32_t padded;	/* sum of the size of padding nodes */
+	jint32_t sum_crc;	/* summary information crc */
+	jint32_t node_crc; 	/* node crc */
+	jint32_t sum[0]; 	/* inode summary info */
+} __attribute__((packed));
+
+union jffs2_node_union
+{
+	struct jffs2_raw_inode i;
+	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
+	struct jffs2_raw_summary s;
+	struct jffs2_unknown_node u;
+};
+
+#endif /* __LINUX_JFFS2_H__ */

+ 76 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/ftl-user.h

@@ -0,0 +1,76 @@
+/*
+ * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
+ *
+ * Derived from (and probably identical to):
+ * ftl.h 1.7 1999/10/25 20:23:17
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef __MTD_FTL_USER_H__
+#define __MTD_FTL_USER_H__
+
+typedef struct erase_unit_header_t {
+    u_int8_t	LinkTargetTuple[5];
+    u_int8_t	DataOrgTuple[10];
+    u_int8_t	NumTransferUnits;
+    u_int32_t	EraseCount;
+    u_int16_t	LogicalEUN;
+    u_int8_t	BlockSize;
+    u_int8_t	EraseUnitSize;
+    u_int16_t	FirstPhysicalEUN;
+    u_int16_t	NumEraseUnits;
+    u_int32_t	FormattedSize;
+    u_int32_t	FirstVMAddress;
+    u_int16_t	NumVMPages;
+    u_int8_t	Flags;
+    u_int8_t	Code;
+    u_int32_t	SerialNumber;
+    u_int32_t	AltEUHOffset;
+    u_int32_t	BAMOffset;
+    u_int8_t	Reserved[12];
+    u_int8_t	EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA		0x01
+#define REVERSE_POLARITY	0x02
+#define DOUBLE_BAI		0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b)		((b) == 0xffffffff)
+#define BLOCK_DELETED(b)	(((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b)		((b) & 0x7f)
+#define BLOCK_ADDRESS(b)	((b) & ~0x7f)
+#define BLOCK_NUMBER(b)		((b) >> 9)
+#define BLOCK_CONTROL		0x30
+#define BLOCK_DATA		0x40
+#define BLOCK_REPLACEMENT	0x60
+#define BLOCK_BAD		0x70
+
+#endif /* __MTD_FTL_USER_H__ */

+ 89 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/inftl-user.h

@@ -0,0 +1,89 @@
+/*
+ * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Parts of INFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_INFTL_USER_H__
+#define __MTD_INFTL_USER_H__
+
+#define	OSAK_VERSION	0x5120
+#define	PERCENTUSED	98
+
+#define	SECTORSIZE	512
+
+/* Block Control Information */
+
+struct inftl_bci {
+	uint8_t ECCsig[6];
+	uint8_t Status;
+	uint8_t Status1;
+} __attribute__((packed));
+
+struct inftl_unithead1 {
+	uint16_t virtualUnitNo;
+	uint16_t prevUnitNo;
+	uint8_t ANAC;
+	uint8_t NACs;
+	uint8_t parityPerField;
+	uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unithead2 {
+	uint8_t parityPerField;
+	uint8_t ANAC;
+	uint16_t prevUnitNo;
+	uint16_t virtualUnitNo;
+	uint8_t NACs;
+	uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unittail {
+	uint8_t Reserved[4];
+	uint16_t EraseMark;
+	uint16_t EraseMark1;
+} __attribute__((packed));
+
+union inftl_uci {
+	struct inftl_unithead1 a;
+	struct inftl_unithead2 b;
+	struct inftl_unittail c;
+};
+
+struct inftl_oob {
+	struct inftl_bci b;
+	union inftl_uci u;
+};
+
+
+/* INFTL Media Header */
+
+struct INFTLPartition {
+	__u32 virtualUnits;
+	__u32 firstUnit;
+	__u32 lastUnit;
+	__u32 flags;
+	__u32 spareUnits;
+	__u32 Reserved0;
+	__u32 Reserved1;
+} __attribute__((packed));
+
+struct INFTLMediaHeader {
+	char bootRecordID[8];
+	__u32 NoOfBootImageBlocks;
+	__u32 NoOfBinaryPartitions;
+	__u32 NoOfBDTLPartitions;
+	__u32 BlockMultiplierBits;
+	__u32 FormatFlags;
+	__u32 OsakVersion;
+	__u32 PercentUsed;
+	struct INFTLPartition Partitions[4];
+} __attribute__((packed));
+
+/* Partition flag types */
+#define	INFTL_BINARY	0x20000000
+#define	INFTL_BDTL	0x40000000
+#define	INFTL_LAST	0x80000000
+
+#endif /* __MTD_INFTL_USER_H__ */

+ 82 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/jffs2-user.h

@@ -0,0 +1,82 @@
+/*
+ * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
+ *
+ * JFFS2 definitions for use in user space only
+ */
+
+#ifndef __JFFS2_USER_H__
+#define __JFFS2_USER_H__
+
+/* This file is blessed for inclusion by userspace */
+#include <linux/jffs2.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#undef cpu_to_je16
+#undef cpu_to_je32
+#undef cpu_to_jemode
+#undef je16_to_cpu
+#undef je32_to_cpu
+#undef jemode_to_cpu
+
+extern int target_endian;
+
+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
+
+#define cpu_to_je16(x) ((jint16_t){t16(x)})
+#define cpu_to_je32(x) ((jint32_t){t32(x)})
+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
+
+#define je16_to_cpu(x) (t16((x).v16))
+#define je32_to_cpu(x) (t32((x).v32))
+#define jemode_to_cpu(x) (t32((x).m))
+
+#define le16_to_cpu(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define le32_to_cpu(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+#define cpu_to_le16(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define cpu_to_le32(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+
+/* XATTR/POSIX-ACL related definition */
+/* Namespaces copied from xattr.h and posix_acl_xattr.h */
+#define XATTR_USER_PREFIX		"user."
+#define XATTR_USER_PREFIX_LEN		(sizeof (XATTR_USER_PREFIX) - 1)
+#define XATTR_SECURITY_PREFIX		"security."
+#define XATTR_SECURITY_PREFIX_LEN	(sizeof (XATTR_SECURITY_PREFIX) - 1)
+#define POSIX_ACL_XATTR_ACCESS		"system.posix_acl_access"
+#define POSIX_ACL_XATTR_ACCESS_LEN	(sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
+#define POSIX_ACL_XATTR_DEFAULT		"system.posix_acl_default"
+#define POSIX_ACL_XATTR_DEFAULT_LEN	(sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
+#define XATTR_TRUSTED_PREFIX		"trusted."
+#define XATTR_TRUSTED_PREFIX_LEN	(sizeof (XATTR_TRUSTED_PREFIX) - 1)
+
+struct jffs2_acl_entry {
+	jint16_t	e_tag;
+	jint16_t	e_perm;
+	jint32_t	e_id;
+};
+
+struct jffs2_acl_entry_short {
+	jint16_t	e_tag;
+	jint16_t	e_perm;
+};
+
+struct jffs2_acl_header {
+	jint32_t	a_version;
+};
+
+/* copied from include/linux/posix_acl_xattr.h */
+#define POSIX_ACL_XATTR_VERSION 0x0002
+
+struct posix_acl_xattr_entry {
+	uint16_t		e_tag;
+	uint16_t		e_perm;
+	uint32_t		e_id;
+};
+
+struct posix_acl_xattr_header {
+	uint32_t			a_version;
+	struct posix_acl_xattr_entry	a_entries[0];
+};
+
+#endif /* __JFFS2_USER_H__ */

+ 282 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/mtd-abi.h

@@ -0,0 +1,282 @@
+/*
+ * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+#include <linux/types.h>
+
+struct erase_info_user {
+	__u32 start;
+	__u32 length;
+};
+
+struct erase_info_user64 {
+	__u64 start;
+	__u64 length;
+};
+
+struct mtd_oob_buf {
+	__u32 start;
+	__u32 length;
+	unsigned char *ptr;
+};
+
+struct mtd_oob_buf64 {
+	__u64 start;
+	__u32 pad;
+	__u32 length;
+	__u64 usr_ptr;
+};
+
+/**
+ * MTD operation modes
+ *
+ * @MTD_OPS_PLACE_OOB:	OOB data are placed at the given offset (default)
+ * @MTD_OPS_AUTO_OOB:	OOB data are automatically placed at the free areas
+ *			which are defined by the internal ecclayout
+ * @MTD_OPS_RAW:	data are transferred as-is, with no error correction;
+ *			this mode implies %MTD_OPS_PLACE_OOB
+ *
+ * These modes can be passed to ioctl(MEMWRITE) and are also used internally.
+ * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
+ * %MTD_FILE_MODE_RAW.
+ */
+enum {
+	MTD_OPS_PLACE_OOB = 0,
+	MTD_OPS_AUTO_OOB = 1,
+	MTD_OPS_RAW = 2,
+};
+
+/**
+ * struct mtd_write_req - data structure for requesting a write operation
+ *
+ * @start:	start address
+ * @len:	length of data buffer
+ * @ooblen:	length of OOB buffer
+ * @usr_data:	user-provided data buffer
+ * @usr_oob:	user-provided OOB buffer
+ * @mode:	MTD mode (see "MTD operation modes")
+ * @padding:	reserved, must be set to 0
+ *
+ * This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB
+ * writes in various modes. To write to OOB-only, set @usr_data == NULL, and to
+ * write data-only, set @usr_oob == NULL. However, setting both @usr_data and
+ * @usr_oob to NULL is not allowed.
+ */
+struct mtd_write_req {
+	__u64 start;
+	__u64 len;
+	__u64 ooblen;
+	__u64 usr_data;
+	__u64 usr_oob;
+	__u8 mode;
+	__u8 padding[7];
+};
+
+#define MTD_ABSENT		0
+#define MTD_RAM			1
+#define MTD_ROM			2
+#define MTD_NORFLASH		3
+#define MTD_NANDFLASH		4
+#define MTD_DATAFLASH		6
+#define MTD_UBIVOLUME		7
+#define MTD_MLCNANDFLASH	8
+
+#define MTD_WRITEABLE		0x400	/* Device is writeable */
+#define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
+#define MTD_NO_ERASE		0x1000	/* No erase necessary */
+#define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */
+
+/* Some common devices / combinations of capabilities */
+#define MTD_CAP_ROM		0
+#define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
+#define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)
+#define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)
+
+/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
+#define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY	3	// Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 	4	// Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF		0
+#define MTD_OTP_FACTORY		1
+#define MTD_OTP_USER		2
+
+struct mtd_info_user {
+	__u8 type;
+	__u32 flags;
+	__u32 size;	/* Total size of the MTD */
+	__u32 erasesize;
+	__u32 writesize;
+	__u32 oobsize;	/* Amount of OOB data per block (e.g. 16) */
+	__u64 padding;	/* Old obsolete field; do not use */
+};
+
+struct region_info_user {
+	__u32 offset;		/* At which this region starts,
+				 * from the beginning of the MTD */
+	__u32 erasesize;	/* For this region */
+	__u32 numblocks;	/* Number of blocks in this region */
+	__u32 regionindex;
+};
+
+struct otp_info {
+	__u32 start;
+	__u32 length;
+	__u32 locked;
+};
+
+/*
+ * Note, the following ioctl existed in the past and was removed:
+ * #define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
+ * Try to avoid adding a new ioctl with the same ioctl number.
+ */
+
+/* Get basic MTD characteristics info (better to use sysfs) */
+#define MEMGETINFO		_IOR('M', 1, struct mtd_info_user)
+/* Erase segment of MTD */
+#define MEMERASE		_IOW('M', 2, struct erase_info_user)
+/* Write out-of-band data from MTD */
+#define MEMWRITEOOB		_IOWR('M', 3, struct mtd_oob_buf)
+/* Read out-of-band data from MTD */
+#define MEMREADOOB		_IOWR('M', 4, struct mtd_oob_buf)
+/* Lock a chip (for MTD that supports it) */
+#define MEMLOCK			_IOW('M', 5, struct erase_info_user)
+/* Unlock a chip (for MTD that supports it) */
+#define MEMUNLOCK		_IOW('M', 6, struct erase_info_user)
+/* Get the number of different erase regions */
+#define MEMGETREGIONCOUNT	_IOR('M', 7, int)
+/* Get information about the erase region for a specific index */
+#define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
+/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
+#define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)
+/* Check if an eraseblock is bad */
+#define MEMGETBADBLOCK		_IOW('M', 11, __kernel_loff_t)
+/* Mark an eraseblock as bad */
+#define MEMSETBADBLOCK		_IOW('M', 12, __kernel_loff_t)
+/* Set OTP (One-Time Programmable) mode (factory vs. user) */
+#define OTPSELECT		_IOR('M', 13, int)
+/* Get number of OTP (One-Time Programmable) regions */
+#define OTPGETREGIONCOUNT	_IOW('M', 14, int)
+/* Get all OTP (One-Time Programmable) info about MTD */
+#define OTPGETREGIONINFO	_IOW('M', 15, struct otp_info)
+/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
+#define OTPLOCK			_IOR('M', 16, struct otp_info)
+/* Get ECC layout (deprecated) */
+#define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout_user)
+/* Get statistics about corrected/uncorrected errors */
+#define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats)
+/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */
+#define MTDFILEMODE		_IO('M', 19)
+/* Erase segment of MTD (supports 64-bit address) */
+#define MEMERASE64		_IOW('M', 20, struct erase_info_user64)
+/* Write data to OOB (64-bit version) */
+#define MEMWRITEOOB64		_IOWR('M', 21, struct mtd_oob_buf64)
+/* Read data from OOB (64-bit version) */
+#define MEMREADOOB64		_IOWR('M', 22, struct mtd_oob_buf64)
+/* Check if chip is locked (for MTD that supports it) */
+#define MEMISLOCKED		_IOR('M', 23, struct erase_info_user)
+/*
+ * Most generic write interface; can write in-band and/or out-of-band in various
+ * modes (see "struct mtd_write_req")
+ */
+#define MEMWRITE		_IOWR('M', 24, struct mtd_write_req)
+
+/*
+ * Obsolete legacy interface. Keep it in order not to break userspace
+ * interfaces
+ */
+struct nand_oobinfo {
+	__u32 useecc;
+	__u32 eccbytes;
+	__u32 oobfree[8][2];
+	__u32 eccpos[32];
+};
+
+struct nand_oobfree {
+	__u32 offset;
+	__u32 length;
+};
+
+#define MTD_MAX_OOBFREE_ENTRIES	8
+#define MTD_MAX_ECCPOS_ENTRIES	64
+/*
+ * OBSOLETE: ECC layout control structure. Exported to user-space via ioctl
+ * ECCGETLAYOUT for backwards compatbility and should not be mistaken as a
+ * complete set of ECC information. The ioctl truncates the larger internal
+ * structure to retain binary compatibility with the static declaration of the
+ * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
+ * the user struct, not the MAX size of the internal struct nand_ecclayout.
+ */
+struct nand_ecclayout_user {
+	__u32 eccbytes;
+	__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES];
+	__u32 oobavail;
+	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+};
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected:	number of corrected bits
+ * @failed:	number of uncorrectable errors
+ * @badblocks:	number of bad blocks in this partition
+ * @bbtblocks:	number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+	__u32 corrected;
+	__u32 failed;
+	__u32 badblocks;
+	__u32 bbtblocks;
+};
+
+/*
+ * MTD file modes - for read/write access to MTD
+ *
+ * @MTD_FILE_MODE_NORMAL:	OTP disabled, ECC enabled
+ * @MTD_FILE_MODE_OTP_FACTORY:	OTP enabled in factory mode
+ * @MTD_FILE_MODE_OTP_USER:	OTP enabled in user mode
+ * @MTD_FILE_MODE_RAW:		OTP disabled, ECC disabled
+ *
+ * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
+ * separately for each open file descriptor.
+ *
+ * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -
+ * raw access to the flash, without error correction or autoplacement schemes.
+ * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode
+ * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is
+ * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).
+ */
+enum mtd_file_modes {
+	MTD_FILE_MODE_NORMAL = MTD_OTP_OFF,
+	MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
+	MTD_FILE_MODE_OTP_USER = MTD_OTP_USER,
+	MTD_FILE_MODE_RAW,
+};
+
+static inline int mtd_type_is_nand_user(const struct mtd_info_user *mtd)
+{
+	return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
+}
+
+#endif /* __MTD_ABI_H__ */

+ 34 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/mtd-user.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __MTD_USER_H__
+#define __MTD_USER_H__
+
+#include <stdint.h>
+
+/* This file is blessed for inclusion by userspace */
+#include <mtd/mtd-abi.h>
+
+typedef struct mtd_info_user mtd_info_t;
+typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
+typedef struct nand_ecclayout_user nand_ecclayout_t;
+
+#endif /* __MTD_USER_H__ */

+ 76 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/nftl-user.h

@@ -0,0 +1,76 @@
+/*
+ * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Parts of NFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_NFTL_USER_H__
+#define __MTD_NFTL_USER_H__
+
+/* Block Control Information */
+
+struct nftl_bci {
+	unsigned char ECCSig[6];
+	uint8_t Status;
+	uint8_t Status1;
+}__attribute__((packed));
+
+/* Unit Control Information */
+
+struct nftl_uci0 {
+	uint16_t VirtUnitNum;
+	uint16_t ReplUnitNum;
+	uint16_t SpareVirtUnitNum;
+	uint16_t SpareReplUnitNum;
+} __attribute__((packed));
+
+struct nftl_uci1 {
+	uint32_t WearInfo;
+	uint16_t EraseMark;
+	uint16_t EraseMark1;
+} __attribute__((packed));
+
+struct nftl_uci2 {
+        uint16_t FoldMark;
+        uint16_t FoldMark1;
+	uint32_t unused;
+} __attribute__((packed));
+
+union nftl_uci {
+	struct nftl_uci0 a;
+	struct nftl_uci1 b;
+	struct nftl_uci2 c;
+};
+
+struct nftl_oob {
+	struct nftl_bci b;
+	union nftl_uci u;
+};
+
+/* NFTL Media Header */
+
+struct NFTLMediaHeader {
+	char DataOrgID[6];
+	uint16_t NumEraseUnits;
+	uint16_t FirstPhysicalEUN;
+	uint32_t FormattedSize;
+	unsigned char UnitSizeFactor;
+} __attribute__((packed));
+
+#define MAX_ERASE_ZONES (8192 - 512)
+
+#define ERASE_MARK 0x3c69
+#define SECTOR_FREE 0xff
+#define SECTOR_USED 0x55
+#define SECTOR_IGNORE 0x11
+#define SECTOR_DELETED 0x00
+
+#define FOLD_MARK_IN_PROGRESS 0x5555
+
+#define ZONE_GOOD 0xff
+#define ZONE_BAD_ORIGINAL 0
+#define ZONE_BAD_MARKED 7
+
+
+#endif /* __MTD_NFTL_USER_H__ */

+ 384 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubi-media.h

@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Thomas Gleixner
+ *          Frank Haverkamp
+ *          Oliver Lohmann
+ *          Andreas Arnez
+ */
+
+/*
+ * This file defines the layout of UBI headers and all the other UBI on-flash
+ * data structures.
+ */
+
+#ifndef __UBI_MEDIA_H__
+#define __UBI_MEDIA_H__
+
+#include <asm/byteorder.h>
+
+/* The version of UBI images supported by this implementation */
+#define UBI_VERSION 1
+
+/* The highest erase counter value supported by this implementation */
+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+
+/* The initial CRC32 value used when calculating CRC checksums */
+#define UBI_CRC32_INIT 0xFFFFFFFFU
+
+/* Erase counter header magic number (ASCII "UBI#") */
+#define UBI_EC_HDR_MAGIC  0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
+
+/*
+ * Volume type constants used in the volume identifier header.
+ *
+ * @UBI_VID_DYNAMIC: dynamic volume
+ * @UBI_VID_STATIC: static volume
+ */
+enum {
+	UBI_VID_DYNAMIC = 1,
+	UBI_VID_STATIC  = 2
+};
+
+/*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ * @UBI_VTBL_SKIP_CRC_CHECK_FLG: skip the CRC check done on a static volume at
+ *				 open time. Should only be set on volumes that
+ *				 are used by upper layers doing this kind of
+ *				 check. Main use-case for this flag is
+ *				 boot-time reduction
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+	UBI_VTBL_AUTORESIZE_FLG = 0x01,
+	UBI_VTBL_SKIP_CRC_CHECK_FLG = 0x02,
+};
+
+/*
+ * Compatibility constants used by internal volumes.
+ *
+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
+ *                     to the flash
+ * @UBI_COMPAT_RO: attach this device in read-only mode
+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+ *                       physical eraseblocks, don't allow the wear-leveling
+ *                       sub-system to move them
+ * @UBI_COMPAT_REJECT: reject this UBI image
+ */
+enum {
+	UBI_COMPAT_DELETE   = 1,
+	UBI_COMPAT_RO       = 2,
+	UBI_COMPAT_PRESERVE = 4,
+	UBI_COMPAT_REJECT   = 5
+};
+
+/* Sizes of UBI headers */
+#define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+
+/* Sizes of UBI headers without the ending CRC */
+#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_ec_hdr - UBI erase counter header.
+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+ * @version: version of UBI implementation which is supposed to accept this
+ *           UBI image
+ * @padding1: reserved for future, zeroes
+ * @ec: the erase counter
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data start
+ * @image_seq: image sequence number
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: erase counter header CRC checksum
+ *
+ * The erase counter header takes 64 bytes and has a plenty of unused space for
+ * future usage. The unused fields are zeroed. The @version field is used to
+ * indicate the version of UBI implementation which is supposed to be able to
+ * work with this UBI image. If @version is greater than the current UBI
+ * version, the image is rejected. This may be useful in future if something
+ * is changed radically. This field is duplicated in the volume identifier
+ * header.
+ *
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * volume identifier header and user data, relative to the beginning of the
+ * physical eraseblock. These values have to be the same for all physical
+ * eraseblocks.
+ *
+ * The @image_seq field is used to validate a UBI image that has been prepared
+ * for a UBI device. The @image_seq value can be any value, but it must be the
+ * same on all eraseblocks. UBI will ensure that all new erase counter headers
+ * also contain this value, and will check the value when scanning at start-up.
+ * One way to make use of @image_seq is to increase its value by one every time
+ * an image is flashed over an existing image, then, if the flashing does not
+ * complete, UBI will detect the error when scanning.
+ */
+struct ubi_ec_hdr {
+	__be32  magic;
+	__u8    version;
+	__u8    padding1[3];
+	__be64  ec; /* Warning: the current limit is 31-bit anyway! */
+	__be32  vid_hdr_offset;
+	__be32  data_offset;
+	__be32  image_seq;
+	__u8    padding2[32];
+	__be32  hdr_crc;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+ * @version: UBI implementation version which is supposed to accept this UBI
+ *           image (%UBI_VERSION)
+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @copy_flag: if this logical eraseblock was copied from another physical
+ *             eraseblock (for wear-leveling reasons)
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ *          %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @vol_id: ID of this volume
+ * @lnum: logical eraseblock number
+ * @padding1: reserved for future, zeroes
+ * @data_size: how many bytes of data this logical eraseblock contains
+ * @used_ebs: total number of used logical eraseblocks in this volume
+ * @data_pad: how many bytes at the end of this physical eraseblock are not
+ *            used
+ * @data_crc: CRC checksum of the data stored in this logical eraseblock
+ * @padding2: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding3: reserved for future, zeroes
+ * @hdr_crc: volume identifier header CRC checksum
+ *
+ * The @sqnum is the value of the global sequence counter at the time when this
+ * VID header was created. The global sequence counter is incremented each time
+ * UBI writes a new VID header to the flash, i.e. when it maps a logical
+ * eraseblock to a new physical eraseblock. The global sequence counter is an
+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+ * (sequence number) is used to distinguish between older and newer versions of
+ * logical eraseblocks.
+ *
+ * There are 2 situations when there may be more than one physical eraseblock
+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+ * and @lnum values in the volume identifier header. Suppose we have a logical
+ * eraseblock L and it is mapped to the physical eraseblock P.
+ *
+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+ * situation is possible: L is asynchronously erased, so P is scheduled for
+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+ * so P1 is written to, then an unclean reboot happens. Result - there are 2
+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+ * flash.
+ *
+ * 2. From time to time UBI moves logical eraseblocks to other physical
+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+ * to P1, and an unclean reboot happens before P is physically erased, there
+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+ * select one of them when the flash is attached. The @sqnum field says which
+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+ * it is not enough to select the physical eraseblock with the higher sequence
+ * number, because the unclean reboot could have happen in the middle of the
+ * copying process, so the data in P is corrupted. It is also not enough to
+ * just select the physical eraseblock with lower sequence number, because the
+ * data there may be old (consider a case if more data was added to P1 after
+ * the copying). Moreover, the unclean reboot may happen when the erasure of P
+ * was just started, so it result in unstable P, which is "mostly" OK, but
+ * still has unstable bits.
+ *
+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+ * copy. UBI also calculates data CRC when the data is moved and stores it at
+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+ * examined. If it is cleared, the situation* is simple and the newer one is
+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+ * the older one (P) is selected.
+ *
+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
+ *
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume.  And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+ * - it just ignores the Ext3fs journal.
+ *
+ * The @data_crc field contains the CRC checksum of the contents of the logical
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * not contain the CRC checksum as a rule. The only exception is when the
+ * data of the physical eraseblock was moved by the wear-leveling sub-system,
+ * then the wear-leveling sub-system calculates the data CRC and stores it in
+ * the @data_crc field. And of course, the @copy_flag is %in this case.
+ *
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+ * contents and uses both @data_crc and @data_size fields. In this case, the
+ * @data_size field contains data size.
+ *
+ * The @used_ebs field is used only for static volumes and indicates how many
+ * eraseblocks the data of the volume takes. For dynamic volumes this field is
+ * not used and always contains zero.
+ *
+ * The @data_pad is calculated when volumes are created using the alignment
+ * parameter. So, effectively, the @data_pad field reduces the size of logical
+ * eraseblocks of this volume. This is very handy when one uses block-oriented
+ * software (say, cramfs) on top of the UBI volume.
+ */
+struct ubi_vid_hdr {
+	__be32  magic;
+	__u8    version;
+	__u8    vol_type;
+	__u8    copy_flag;
+	__u8    compat;
+	__be32  vol_id;
+	__be32  lnum;
+	__be32  leb_ver;
+	__be32  data_size;
+	__be32  used_ebs;
+	__be32  data_pad;
+	__be32  data_crc;
+	__u8    padding2[4];
+	__be64  sqnum;
+	__u8    padding3[12];
+	__be32  hdr_crc;
+} __attribute__ ((packed));
+
+/* Internal UBI volumes count */
+#define UBI_INT_VOL_COUNT 1
+
+/*
+ * Starting ID of internal volumes. There is reserved room for 4096 internal
+ * volumes.
+ */
+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+
+/* The layout volume contains the volume table */
+
+#define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_TYPE   UBI_VID_DYNAMIC
+#define UBI_LAYOUT_VOLUME_ALIGN  1
+#define UBI_LAYOUT_VOLUME_EBS    2
+#define UBI_LAYOUT_VOLUME_NAME   "layout volume"
+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+
+/* The maximum number of volumes per one UBI device */
+#define UBI_MAX_VOLUMES 128
+
+/* The maximum volume name length */
+#define UBI_VOL_NAME_MAX 127
+
+/* Size of the volume table record */
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+
+/* Size of the volume table record without the ending CRC */
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
+
+/**
+ * struct ubi_vtbl_record - a record in the volume table.
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @upd_marker: if volume update was started but not finished
+ * @name_len: volume name length
+ * @name: the volume name
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
+ * @crc: a CRC32 checksum of the record
+ *
+ * The volume table records are stored in the volume table, which is stored in
+ * the layout volume. The layout volume consists of 2 logical eraseblock, each
+ * of which contains a copy of the volume table (i.e., the volume table is
+ * duplicated). The volume table is an array of &struct ubi_vtbl_record
+ * objects indexed by the volume ID.
+ *
+ * If the size of the logical eraseblock is large enough to fit
+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+ * records. Otherwise, it contains as many records as it can fit (i.e., size of
+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+ *
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update. So if the update operation was
+ * interrupted, UBI knows that the volume is corrupted.
+ *
+ * The @alignment field is specified when the volume is created and cannot be
+ * later changed. It may be useful, for example, when a block-oriented file
+ * system works on top of UBI. The @data_pad field is calculated using the
+ * logical eraseblock size and @alignment. The alignment must be multiple to the
+ * minimal flash I/O unit. If @alignment is 1, all the available space of
+ * the physical eraseblocks is used.
+ *
+ * Empty records contain all zeroes and the CRC checksum of those zeroes.
+ */
+struct ubi_vtbl_record {
+	__be32  reserved_pebs;
+	__be32  alignment;
+	__be32  data_pad;
+	__u8    vol_type;
+	__u8    upd_marker;
+	__be16  name_len;
+	__u8    name[UBI_VOL_NAME_MAX+1];
+	__u8    flags;
+	__u8    padding[23];
+	__be32  crc;
+} __attribute__ ((packed));
+
+#endif /* !__UBI_MEDIA_H__ */

+ 452 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubi-user.h

@@ -0,0 +1,452 @@
+/*
+ * Copyright © International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Artem Bityutskiy (Битюцкий Артём)
+ */
+
+#ifndef __UBI_USER_H__
+#define __UBI_USER_H__
+
+/*
+ * UBI device creation (the same as MTD device attachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
+ * control device. The caller has to properly fill and pass
+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in
+ * the request and return the newly created UBI device number as the ioctl
+ * return value.
+ *
+ * UBI device deletion (the same as MTD device detachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
+ * control device.
+ *
+ * UBI volume creation
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character
+ * device. A &struct ubi_mkvol_req object has to be properly filled and a
+ * pointer to it has to be passed to the ioctl.
+ *
+ * UBI volume deletion
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character
+ * device should be used. A pointer to the 32-bit volume ID hast to be passed
+ * to the ioctl.
+ *
+ * UBI volume re-size
+ * ~~~~~~~~~~~~~~~~~~
+ *
+ * To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character
+ * device should be used. A &struct ubi_rsvol_req object has to be properly
+ * filled and a pointer to it has to be passed to the ioctl.
+ *
+ * UBI volumes re-name
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
+ * of the UBI character device should be used. A &struct ubi_rnvol_req object
+ * has to be properly filled and a pointer to it has to be passed to the ioctl.
+ *
+ * UBI volume update
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Volume update should be done via the %UBI_IOCVOLUP ioctl command of the
+ * corresponding UBI volume character device. A pointer to a 64-bit update
+ * size should be passed to the ioctl. After this, UBI expects user to write
+ * this number of bytes to the volume character device. The update is finished
+ * when the claimed number of bytes is passed. So, the volume update sequence
+ * is something like:
+ *
+ * fd = open("/dev/my_volume");
+ * ioctl(fd, UBI_IOCVOLUP, &image_size);
+ * write(fd, buf, image_size);
+ * close(fd);
+ *
+ * Logical eraseblock erase
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the
+ * corresponding UBI volume character device should be used. This command
+ * unmaps the requested logical eraseblock, makes sure the corresponding
+ * physical eraseblock is successfully erased, and returns.
+ *
+ * Atomic logical eraseblock change
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH
+ * ioctl command of the corresponding UBI volume character device. A pointer to
+ * a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the
+ * user is expected to write the requested amount of bytes (similarly to what
+ * should be done in case of the "volume update" ioctl).
+ *
+ * Logical eraseblock map
+ * ~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP
+ * ioctl command should be used. A pointer to a &struct ubi_map_req object is
+ * expected to be passed. The ioctl maps the requested logical eraseblock to
+ * a physical eraseblock and returns.  Only non-mapped logical eraseblocks can
+ * be mapped. If the logical eraseblock specified in the request is already
+ * mapped to a physical eraseblock, the ioctl fails and returns error.
+ *
+ * Logical eraseblock unmap
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP
+ * ioctl command should be used. The ioctl unmaps the logical eraseblocks,
+ * schedules corresponding physical eraseblock for erasure, and returns. Unlike
+ * the "LEB erase" command, it does not wait for the physical eraseblock being
+ * erased. Note, the side effect of this is that if an unclean reboot happens
+ * after the unmap ioctl returns, you may find the LEB mapped again to the same
+ * physical eraseblock after the UBI is run again.
+ *
+ * Check if logical eraseblock is mapped
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To check if a logical eraseblock is mapped to a physical eraseblock, the
+ * %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is
+ * not mapped, and %1 if it is mapped.
+ *
+ * Set an UBI volume property
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
+ * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
+ * passed. The object describes which property should be set, and to which value
+ * it should be set.
+ *
+ * Block devices on UBI volumes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * To create a R/O block device on top of an UBI volume the %UBI_IOCVOLCRBLK
+ * should be used. A pointer to a &struct ubi_blkcreate_req object is expected
+ * to be passed, which is not used and reserved for future usage.
+ *
+ * Conversely, to remove a block device the %UBI_IOCVOLRMBLK should be used,
+ * which takes no arguments.
+ */
+
+/*
+ * When a new UBI volume or UBI device is created, users may either specify the
+ * volume/device number they want to create or to let UBI automatically assign
+ * the number using these constants.
+ */
+#define UBI_VOL_NUM_AUTO (-1)
+#define UBI_DEV_NUM_AUTO (-1)
+
+/* Maximum volume name length */
+#define UBI_MAX_VOLUME_NAME 127
+
+/* ioctl commands of UBI character devices */
+
+#define UBI_IOC_MAGIC 'o'
+
+/* Create an UBI volume */
+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
+/* Remove an UBI volume */
+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
+/* Re-size an UBI volume */
+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
+/* Re-name volumes */
+#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
+
+/* ioctl commands of the UBI control character device */
+
+#define UBI_CTRL_IOC_MAGIC 'o'
+
+/* Attach an MTD device */
+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
+/* Detach an MTD device */
+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
+
+/* ioctl commands of UBI volume character devices */
+
+#define UBI_VOL_IOC_MAGIC 'O'
+
+/* Start UBI volume update */
+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
+/* LEB erasure command, used for debugging, disabled by default */
+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+/* Atomic LEB change command */
+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
+/* Map LEB command */
+#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req)
+/* Unmap LEB command */
+#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t)
+/* Check if LEB is mapped command */
+#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t)
+/* Set an UBI volume property */
+#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+			       struct ubi_set_vol_prop_req)
+/* Create a R/O block device on top of an UBI volume */
+#define UBI_IOCVOLCRBLK _IOW(UBI_VOL_IOC_MAGIC, 7, struct ubi_blkcreate_req)
+/* Remove the R/O block device */
+#define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8)
+
+/* Maximum MTD device name length supported by UBI */
+#define MAX_UBI_MTD_NAME_LEN 127
+
+/* Maximum amount of UBI volumes that can be re-named at one go */
+#define UBI_MAX_RNVOL 32
+
+/*
+ * UBI volume type constants.
+ *
+ * @UBI_DYNAMIC_VOLUME: dynamic volume
+ * @UBI_STATIC_VOLUME:  static volume
+ */
+enum {
+	UBI_DYNAMIC_VOLUME = 3,
+	UBI_STATIC_VOLUME  = 4,
+};
+
+/*
+ * UBI set volume property ioctl constants.
+ *
+ * @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0)
+ *                             user to directly write and erase individual
+ *                             eraseblocks on dynamic volumes
+ */
+enum {
+	UBI_VOL_PROP_DIRECT_WRITE = 1,
+};
+
+/**
+ * struct ubi_attach_req - attach MTD device request.
+ * @ubi_num: UBI device number to create
+ * @mtd_num: MTD device number to attach
+ * @vid_hdr_offset: VID header offset (use defaults if %0)
+ * @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * This data structure is used to specify MTD device UBI has to attach and the
+ * parameters it has to use. The number which should be assigned to the new UBI
+ * device is passed in @ubi_num. UBI may automatically assign the number if
+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
+ * @ubi_num.
+ *
+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default
+ * offset of the VID header within physical eraseblocks. The default offset is
+ * the next min. I/O unit after the EC header. For example, it will be offset
+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
+ *
+ * But in rare cases, if this optimizes things, the VID header may be placed to
+ * a different offset. For example, the boot-loader might do things faster if
+ * the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages.
+ * As the boot-loader would not normally need to read EC headers (unless it
+ * needs UBI in RW mode), it might be faster to calculate ECC. This is weird
+ * example, but it real-life example. So, in this example, @vid_hdr_offer would
+ * be 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
+ * aligned, which is OK, as UBI is clever enough to realize this is 4th
+ * sub-page of the first page and add needed padding.
+ *
+ * The @max_beb_per1024 is the maximum amount of bad PEBs UBI expects on the
+ * UBI device per 1024 eraseblocks.  This value is often given in an other form
+ * in the NAND datasheet (min NVB i.e. minimal number of valid blocks). The
+ * maximum expected bad eraseblocks per 1024 is then:
+ *    1024 * (1 - MinNVB / MaxNVB)
+ * Which gives 20 for most NAND devices.  This limit is used in order to derive
+ * amount of eraseblock UBI reserves for handling new bad blocks. If the device
+ * has more bad eraseblocks than this limit, UBI does not reserve any physical
+ * eraseblocks for new bad eraseblocks, but attempts to use available
+ * eraseblocks (if any). The accepted range is 0-768. If 0 is given, the
+ * default kernel value of %CONFIG_MTD_UBI_BEB_LIMIT will be used.
+ */
+struct ubi_attach_req {
+	int32_t ubi_num;
+	int32_t mtd_num;
+	int32_t vid_hdr_offset;
+	int16_t max_beb_per1024;
+	int8_t  padding[10];
+};
+
+/*
+ * UBI volume flags.
+ *
+ * @UBI_VOL_SKIP_CRC_CHECK_FLG: skip the CRC check done on a static volume at
+ *				open time. Only valid for static volumes and
+ *				should only be used if the volume user has a
+ *				way to verify data integrity
+ */
+enum {
+	UBI_VOL_SKIP_CRC_CHECK_FLG = 0x1,
+};
+
+/**
+ * struct ubi_mkvol_req - volume description data structure used in
+ *                        volume creation requests.
+ * @vol_id: volume number
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @flags: volume flags (%UBI_VOL_SKIP_CRC_CHECK_FLG)
+ * @name_len: volume name length
+ * @padding2: reserved for future, not used, has to be zeroed
+ * @name: volume name
+ *
+ * This structure is used by user-space programs when creating new volumes. The
+ * @used_bytes field is only necessary when creating static volumes.
+ *
+ * The @alignment field specifies the required alignment of the volume logical
+ * eraseblock. This means, that the size of logical eraseblocks will be aligned
+ * to this number, i.e.,
+ *	(UBI device logical eraseblock size) mod (@alignment) = 0.
+ *
+ * To put it differently, the logical eraseblock of this volume may be slightly
+ * shortened in order to make it properly aligned. The alignment has to be
+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire
+ * available space of logical eraseblocks.
+ *
+ * The @alignment field may be useful, for example, when one wants to maintain
+ * a block device on top of an UBI volume. In this case, it is desirable to fit
+ * an integer number of blocks in logical eraseblocks of this UBI volume. With
+ * alignment it is possible to update this volume using plane UBI volume image
+ * BLOBs, without caring about how to properly align them.
+ */
+struct ubi_mkvol_req {
+	int32_t vol_id;
+	int32_t alignment;
+	int64_t bytes;
+	int8_t vol_type;
+	uint8_t flags;
+	int16_t name_len;
+	int8_t padding2[4];
+	char name[UBI_MAX_VOLUME_NAME + 1];
+} __attribute__((packed));
+
+/**
+ * struct ubi_rsvol_req - a data structure used in volume re-size requests.
+ * @vol_id: ID of the volume to re-size
+ * @bytes: new size of the volume in bytes
+ *
+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic
+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be
+ * smaller than the number of bytes they bear. To arbitrarily shrink a static
+ * volume, it must be wiped out first (by means of volume update operation with
+ * zero number of bytes).
+ */
+struct ubi_rsvol_req {
+	int64_t bytes;
+	int32_t vol_id;
+} __attribute__((packed));
+
+/**
+ * struct ubi_rnvol_req - volumes re-name request.
+ * @count: count of volumes to re-name
+ * @padding1:  reserved for future, not used, has to be zeroed
+ * @vol_id: ID of the volume to re-name
+ * @name_len: name length
+ * @padding2:  reserved for future, not used, has to be zeroed
+ * @name: new volume name
+ *
+ * UBI allows to re-name up to %32 volumes at one go. The count of volumes to
+ * re-name is specified in the @count field. The ID of the volumes to re-name
+ * and the new names are specified in the @vol_id and @name fields.
+ *
+ * The UBI volume re-name operation is atomic, which means that should power cut
+ * happen, the volumes will have either old name or new name. So the possible
+ * use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes
+ * A and B one may create temporary volumes %A1 and %B1 with the new contents,
+ * then atomically re-name A1->A and B1->B, in which case old %A and %B will
+ * be removed.
+ *
+ * If it is not desirable to remove old A and B, the re-name request has to
+ * contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1
+ * become A and B, and old A and B will become A1 and B1.
+ *
+ * It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1
+ * and B1 become A and B, and old A and B become X and Y.
+ *
+ * In other words, in case of re-naming into an existing volume name, the
+ * existing volume is removed, unless it is re-named as well at the same
+ * re-name request.
+ */
+struct ubi_rnvol_req {
+	int32_t count;
+	int8_t padding1[12];
+	struct {
+		int32_t vol_id;
+		int16_t name_len;
+		int8_t  padding2[2];
+		char    name[UBI_MAX_VOLUME_NAME + 1];
+	} ents[UBI_MAX_RNVOL];
+} __attribute__((packed));
+
+/**
+ * struct ubi_leb_change_req - a data structure used in atomic LEB change
+ *                             requests.
+ * @lnum: logical eraseblock number to change
+ * @bytes: how many bytes will be written to the logical eraseblock
+ * @dtype: pass "3" for better compatibility with old kernels
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * The @dtype field used to inform UBI about what kind of data will be written
+ * to the LEB: long term (value 1), short term (value 2), unknown (value 3).
+ * UBI tried to pick a PEB with lower erase counter for short term data and a
+ * PEB with higher erase counter for long term data. But this was not really
+ * used because users usually do not know this and could easily mislead UBI. We
+ * removed this feature in May 2012. UBI currently just ignores the @dtype
+ * field. But for better compatibility with older kernels it is recommended to
+ * set @dtype to 3 (unknown).
+ */
+struct ubi_leb_change_req {
+	int32_t lnum;
+	int32_t bytes;
+	int8_t  dtype; /* obsolete, do not use! */
+	int8_t  padding[7];
+} __attribute__((packed));
+
+/**
+ * struct ubi_map_req - a data structure used in map LEB requests.
+ * @dtype: pass "3" for better compatibility with old kernels
+ * @lnum: logical eraseblock number to unmap
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_map_req {
+	int32_t lnum;
+	int8_t  dtype; /* obsolete, do not use! */
+	int8_t  padding[3];
+} __attribute__((packed));
+
+
+/**
+ * struct ubi_set_vol_prop_req - a data structure used to set an UBI volume
+ *                               property.
+ * @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE)
+ * @padding: reserved for future, not used, has to be zeroed
+ * @value: value to set
+ */
+struct ubi_set_vol_prop_req {
+	uint8_t  property;
+	uint8_t  padding[7];
+	uint64_t value;
+}  __attribute__((packed));
+
+/**
+ * struct ubi_blkcreate_req - a data structure used in block creation requests.
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_blkcreate_req {
+	int8_t  padding[128];
+}  __attribute__((packed));
+
+#endif /* __UBI_USER_H__ */

+ 869 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd/ubifs-media.h

@@ -0,0 +1,869 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+/*
+ * This file describes UBIFS on-flash format and contains definitions of all the
+ * relevant data structures and constants.
+ *
+ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start
+ * with the UBIFS node magic number and have the same common header. Nodes
+ * always sit at 8-byte aligned positions on the media and node header sizes are
+ * also 8-byte aligned (except for the indexing node and the padding node).
+ */
+
+#ifndef __UBIFS_MEDIA_H__
+#define __UBIFS_MEDIA_H__
+
+#include <asm/byteorder.h>
+
+/* UBIFS node magic number (must not have the padding byte first or last) */
+#define UBIFS_NODE_MAGIC  0x06101831
+
+/*
+ * UBIFS on-flash format version. This version is increased when the on-flash
+ * format is changing. If this happens, UBIFS is will support older versions as
+ * well. But older UBIFS code will not support newer formats. Format changes
+ * will be rare and only when absolutely necessary, e.g. to fix a bug or to add
+ * a new feature.
+ *
+ * UBIFS went into mainline kernel with format version 4. The older formats
+ * were development formats.
+ */
+#define UBIFS_FORMAT_VERSION 5
+
+/*
+ * Read-only compatibility version. If the UBIFS format is changed, older UBIFS
+ * implementations will not be able to mount newer formats in read-write mode.
+ * However, depending on the change, it may be possible to mount newer formats
+ * in R/O mode. This is indicated by the R/O compatibility version which is
+ * stored in the super-block.
+ *
+ * This is needed to support boot-loaders which only need R/O mounting. With
+ * this flag it is possible to do UBIFS format changes without a need to update
+ * boot-loaders.
+ */
+#define UBIFS_RO_COMPAT_VERSION 0
+
+/* Minimum logical eraseblock size in bytes */
+#define UBIFS_MIN_LEB_SZ (15*1024)
+
+/* Initial CRC32 value used when calculating CRC checksums */
+#define UBIFS_CRC32_INIT 0xFFFFFFFFU
+
+/*
+ * UBIFS does not try to compress data if its length is less than the below
+ * constant.
+ */
+#define UBIFS_MIN_COMPR_LEN 128
+
+/*
+ * If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
+ * shorter than uncompressed data length, UBIFS prefers to leave this data
+ * node uncompress, because it'll be read faster.
+ */
+#define UBIFS_MIN_COMPRESS_DIFF 64
+
+/* Root inode number */
+#define UBIFS_ROOT_INO 1
+
+/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */
+#define UBIFS_FIRST_INO 64
+
+/*
+ * Maximum file name and extended attribute length (must be a multiple of 8,
+ * minus 1).
+ */
+#define UBIFS_MAX_NLEN 255
+
+/* Maximum number of data journal heads */
+#define UBIFS_MAX_JHEADS 1
+
+/*
+ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system,
+ * which means that it does not treat the underlying media as consisting of
+ * blocks like in case of hard drives. Do not be confused. UBIFS block is just
+ * the maximum amount of data which one data node can have or which can be
+ * attached to an inode node.
+ */
+#define UBIFS_BLOCK_SIZE  4096
+#define UBIFS_BLOCK_SHIFT 12
+
+/* UBIFS padding byte pattern (must not be first or last byte of node magic) */
+#define UBIFS_PADDING_BYTE 0xCE
+
+/* Maximum possible key length */
+#define UBIFS_MAX_KEY_LEN 16
+
+/* Key length ("simple" format) */
+#define UBIFS_SK_LEN 8
+
+/* Minimum index tree fanout */
+#define UBIFS_MIN_FANOUT 3
+
+/* Maximum number of levels in UBIFS indexing B-tree */
+#define UBIFS_MAX_LEVELS 512
+
+/* Maximum amount of data attached to an inode in bytes */
+#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE
+
+/* LEB Properties Tree fanout (must be power of 2) and fanout shift */
+#define UBIFS_LPT_FANOUT 4
+#define UBIFS_LPT_FANOUT_SHIFT 2
+
+/* LEB Properties Tree bit field sizes */
+#define UBIFS_LPT_CRC_BITS 16
+#define UBIFS_LPT_CRC_BYTES 2
+#define UBIFS_LPT_TYPE_BITS 4
+
+/* The key is always at the same position in all keyed nodes */
+#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key)
+
+/* Garbage collector journal head number */
+#define UBIFS_GC_HEAD   0
+/* Base journal head number */
+#define UBIFS_BASE_HEAD 1
+/* Data journal head number */
+#define UBIFS_DATA_HEAD 2
+
+/*
+ * LEB Properties Tree node types.
+ *
+ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties)
+ * UBIFS_LPT_NNODE: LPT internal node
+ * UBIFS_LPT_LTAB: LPT's own lprops table
+ * UBIFS_LPT_LSAVE: LPT's save table (big model only)
+ * UBIFS_LPT_NODE_CNT: count of LPT node types
+ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type
+ */
+enum {
+	UBIFS_LPT_PNODE,
+	UBIFS_LPT_NNODE,
+	UBIFS_LPT_LTAB,
+	UBIFS_LPT_LSAVE,
+	UBIFS_LPT_NODE_CNT,
+	UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1,
+};
+
+/*
+ * UBIFS inode types.
+ *
+ * UBIFS_ITYPE_REG: regular file
+ * UBIFS_ITYPE_DIR: directory
+ * UBIFS_ITYPE_LNK: soft link
+ * UBIFS_ITYPE_BLK: block device node
+ * UBIFS_ITYPE_CHR: character device node
+ * UBIFS_ITYPE_FIFO: fifo
+ * UBIFS_ITYPE_SOCK: socket
+ * UBIFS_ITYPES_CNT: count of supported file types
+ */
+enum {
+	UBIFS_ITYPE_REG,
+	UBIFS_ITYPE_DIR,
+	UBIFS_ITYPE_LNK,
+	UBIFS_ITYPE_BLK,
+	UBIFS_ITYPE_CHR,
+	UBIFS_ITYPE_FIFO,
+	UBIFS_ITYPE_SOCK,
+	UBIFS_ITYPES_CNT,
+};
+
+/*
+ * Supported key hash functions.
+ *
+ * UBIFS_KEY_HASH_R5: R5 hash
+ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name
+ */
+enum {
+	UBIFS_KEY_HASH_R5,
+	UBIFS_KEY_HASH_TEST,
+};
+
+/*
+ * Supported key formats.
+ *
+ * UBIFS_SIMPLE_KEY_FMT: simple key format
+ */
+enum {
+	UBIFS_SIMPLE_KEY_FMT,
+};
+
+/*
+ * The simple key format uses 29 bits for storing UBIFS block number and hash
+ * value.
+ */
+#define UBIFS_S_KEY_BLOCK_BITS 29
+#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF
+#define UBIFS_S_KEY_HASH_BITS  UBIFS_S_KEY_BLOCK_BITS
+#define UBIFS_S_KEY_HASH_MASK  UBIFS_S_KEY_BLOCK_MASK
+
+/*
+ * Key types.
+ *
+ * UBIFS_INO_KEY: inode node key
+ * UBIFS_DATA_KEY: data node key
+ * UBIFS_DENT_KEY: directory entry node key
+ * UBIFS_XENT_KEY: extended attribute entry key
+ * UBIFS_KEY_TYPES_CNT: number of supported key types
+ */
+enum {
+	UBIFS_INO_KEY,
+	UBIFS_DATA_KEY,
+	UBIFS_DENT_KEY,
+	UBIFS_XENT_KEY,
+	UBIFS_KEY_TYPES_CNT,
+};
+
+/* Count of LEBs reserved for the superblock area */
+#define UBIFS_SB_LEBS 1
+/* Count of LEBs reserved for the master area */
+#define UBIFS_MST_LEBS 2
+
+/* First LEB of the superblock area */
+#define UBIFS_SB_LNUM 0
+/* First LEB of the master area */
+#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS)
+/* First LEB of the log area */
+#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS)
+
+/*
+ * The below constants define the absolute minimum values for various UBIFS
+ * media areas. Many of them actually depend of flash geometry and the FS
+ * configuration (number of journal heads, orphan LEBs, etc). This means that
+ * the smallest volume size which can be used for UBIFS cannot be pre-defined
+ * by these constants. The file-system that meets the below limitation will not
+ * necessarily mount. UBIFS does run-time calculations and validates the FS
+ * size.
+ */
+
+/* Minimum number of logical eraseblocks in the log */
+#define UBIFS_MIN_LOG_LEBS 2
+/* Minimum number of bud logical eraseblocks (one for each head) */
+#define UBIFS_MIN_BUD_LEBS 3
+/* Minimum number of journal logical eraseblocks */
+#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS)
+/* Minimum number of LPT area logical eraseblocks */
+#define UBIFS_MIN_LPT_LEBS 2
+/* Minimum number of orphan area logical eraseblocks */
+#define UBIFS_MIN_ORPH_LEBS 1
+/*
+ * Minimum number of main area logical eraseblocks (buds, 3 for the index, 1
+ * for GC, 1 for deletions, and at least 1 for committed data).
+ */
+#define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 6)
+
+/* Minimum number of logical eraseblocks */
+#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \
+			   UBIFS_MIN_LOG_LEBS + UBIFS_MIN_LPT_LEBS + \
+			   UBIFS_MIN_ORPH_LEBS + UBIFS_MIN_MAIN_LEBS)
+
+/* Node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_CH_SZ        sizeof(struct ubifs_ch)
+#define UBIFS_INO_NODE_SZ  sizeof(struct ubifs_ino_node)
+#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node)
+#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node)
+#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node)
+#define UBIFS_PAD_NODE_SZ  sizeof(struct ubifs_pad_node)
+#define UBIFS_SB_NODE_SZ   sizeof(struct ubifs_sb_node)
+#define UBIFS_MST_NODE_SZ  sizeof(struct ubifs_mst_node)
+#define UBIFS_REF_NODE_SZ  sizeof(struct ubifs_ref_node)
+#define UBIFS_IDX_NODE_SZ  sizeof(struct ubifs_idx_node)
+#define UBIFS_CS_NODE_SZ   sizeof(struct ubifs_cs_node)
+#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
+#define UBIFS_AUTH_NODE_SZ sizeof(struct ubifs_auth_node)
+#define UBIFS_SIG_NODE_SZ  sizeof(struct ubifs_sig_node)
+
+/* Extended attribute entry nodes are identical to directory entry nodes */
+#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
+/* Only this does not have to be multiple of 8 bytes */
+#define UBIFS_BRANCH_SZ    sizeof(struct ubifs_branch)
+
+/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */
+#define UBIFS_MAX_DATA_NODE_SZ  (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
+#define UBIFS_MAX_INO_NODE_SZ   (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA)
+#define UBIFS_MAX_DENT_NODE_SZ  (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1)
+#define UBIFS_MAX_XENT_NODE_SZ  UBIFS_MAX_DENT_NODE_SZ
+
+/* The largest UBIFS node */
+#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
+
+/* The maxmimum size of a hash, enough for sha512 */
+#define UBIFS_MAX_HASH_LEN 64
+
+/* The maxmimum size of a hmac, enough for hmac(sha512) */
+#define UBIFS_MAX_HMAC_LEN 64
+
+/*
+ * xattr name of UBIFS encryption context, we don't use a prefix
+ * nor a long name to not waste space on the flash.
+ */
+#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
+
+/* Type field in ubifs_sig_node */
+#define UBIFS_SIGNATURE_TYPE_PKCS7	1
+
+/*
+ * On-flash inode flags.
+ *
+ * UBIFS_COMPR_FL: use compression for this inode
+ * UBIFS_SYNC_FL:  I/O on this inode has to be synchronous
+ * UBIFS_IMMUTABLE_FL: inode is immutable
+ * UBIFS_APPEND_FL: writes to the inode may only append data
+ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
+ * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
+ * UBIFS_CRYPT_FL: use encryption for this inode
+ *
+ * Note, these are on-flash flags which correspond to ioctl flags
+ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
+ * have to be the same.
+ */
+enum {
+	UBIFS_COMPR_FL     = 0x01,
+	UBIFS_SYNC_FL      = 0x02,
+	UBIFS_IMMUTABLE_FL = 0x04,
+	UBIFS_APPEND_FL    = 0x08,
+	UBIFS_DIRSYNC_FL   = 0x10,
+	UBIFS_XATTR_FL     = 0x20,
+	UBIFS_CRYPT_FL     = 0x40,
+};
+
+/* Inode flag bits used by UBIFS */
+#define UBIFS_FL_MASK 0x0000001F
+
+/*
+ * UBIFS compression algorithms.
+ *
+ * UBIFS_COMPR_NONE: no compression
+ * UBIFS_COMPR_LZO: LZO compression
+ * UBIFS_COMPR_ZLIB: ZLIB compression
+ * UBIFS_COMPR_ZSTD: ZSTD compression
+ * UBIFS_COMPR_TYPES_CNT: count of supported compression types
+ */
+enum {
+	UBIFS_COMPR_NONE,
+	UBIFS_COMPR_LZO,
+	UBIFS_COMPR_ZLIB,
+	UBIFS_COMPR_ZSTD,
+	UBIFS_COMPR_TYPES_CNT,
+};
+
+/*
+ * UBIFS node types.
+ *
+ * UBIFS_INO_NODE: inode node
+ * UBIFS_DATA_NODE: data node
+ * UBIFS_DENT_NODE: directory entry node
+ * UBIFS_XENT_NODE: extended attribute node
+ * UBIFS_TRUN_NODE: truncation node
+ * UBIFS_PAD_NODE: padding node
+ * UBIFS_SB_NODE: superblock node
+ * UBIFS_MST_NODE: master node
+ * UBIFS_REF_NODE: LEB reference node
+ * UBIFS_IDX_NODE: index node
+ * UBIFS_CS_NODE: commit start node
+ * UBIFS_ORPH_NODE: orphan node
+ * UBIFS_AUTH_NODE: authentication node
+ * UBIFS_SIG_NODE: signature node
+ * UBIFS_NODE_TYPES_CNT: count of supported node types
+ *
+ * Note, we index arrays by these numbers, so keep them low and contiguous.
+ * Node type constants for inodes, direntries and so on have to be the same as
+ * corresponding key type constants.
+ */
+enum {
+	UBIFS_INO_NODE,
+	UBIFS_DATA_NODE,
+	UBIFS_DENT_NODE,
+	UBIFS_XENT_NODE,
+	UBIFS_TRUN_NODE,
+	UBIFS_PAD_NODE,
+	UBIFS_SB_NODE,
+	UBIFS_MST_NODE,
+	UBIFS_REF_NODE,
+	UBIFS_IDX_NODE,
+	UBIFS_CS_NODE,
+	UBIFS_ORPH_NODE,
+	UBIFS_AUTH_NODE,
+	UBIFS_SIG_NODE,
+	UBIFS_NODE_TYPES_CNT,
+};
+
+/*
+ * Master node flags.
+ *
+ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty
+ * UBIFS_MST_NO_ORPHS: no orphan inodes present
+ * UBIFS_MST_RCVRY: written by recovery
+ */
+enum {
+	UBIFS_MST_DIRTY = 1,
+	UBIFS_MST_NO_ORPHS = 2,
+	UBIFS_MST_RCVRY = 4,
+};
+
+/*
+ * Node group type (used by recovery to recover whole group or none).
+ *
+ * UBIFS_NO_NODE_GROUP: this node is not part of a group
+ * UBIFS_IN_NODE_GROUP: this node is a part of a group
+ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group
+ */
+enum {
+	UBIFS_NO_NODE_GROUP = 0,
+	UBIFS_IN_NODE_GROUP,
+	UBIFS_LAST_OF_NODE_GROUP,
+};
+
+/*
+ * Superblock flags.
+ *
+ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+ * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
+ *			  support 64bit cookies for lookups by hash
+ * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
+ * UBIFS_FLG_AUTHENTICATION: this filesystem contains hashes for authentication
+ */
+enum {
+	UBIFS_FLG_BIGLPT = 0x02,
+	UBIFS_FLG_SPACE_FIXUP = 0x04,
+	UBIFS_FLG_DOUBLE_HASH = 0x08,
+	UBIFS_FLG_ENCRYPTION = 0x10,
+	UBIFS_FLG_AUTHENTICATION = 0x20,
+};
+
+#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT | UBIFS_FLG_SPACE_FIXUP | \
+		UBIFS_FLG_DOUBLE_HASH | UBIFS_FLG_ENCRYPTION | \
+		UBIFS_FLG_AUTHENTICATION)
+
+/**
+ * struct ubifs_ch - common header node.
+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
+ * @crc: CRC-32 checksum of the node header
+ * @sqnum: sequence number
+ * @len: full node length
+ * @node_type: node type
+ * @group_type: node group type
+ * @padding: reserved for future, zeroes
+ *
+ * Every UBIFS node starts with this common part. If the node has a key, the
+ * key always goes next.
+ */
+struct ubifs_ch {
+	__le32 magic;
+	__le32 crc;
+	__le64 sqnum;
+	__le32 len;
+	__u8 node_type;
+	__u8 group_type;
+	__u8 padding[2];
+} __attribute__ ((packed));
+
+/**
+ * union ubifs_dev_desc - device node descriptor.
+ * @new: new type device descriptor
+ * @huge: huge type device descriptor
+ *
+ * This data structure describes major/minor numbers of a device node. In an
+ * inode is a device node then its data contains an object of this type. UBIFS
+ * uses standard Linux "new" and "huge" device node encodings.
+ */
+union ubifs_dev_desc {
+	__le32 new;
+	__le64 huge;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ino_node - inode node.
+ * @ch: common header
+ * @key: node key
+ * @creat_sqnum: sequence number at time of creation
+ * @size: inode size in bytes (amount of uncompressed data)
+ * @atime_sec: access time seconds
+ * @ctime_sec: creation time seconds
+ * @mtime_sec: modification time seconds
+ * @atime_nsec: access time nanoseconds
+ * @ctime_nsec: creation time nanoseconds
+ * @mtime_nsec: modification time nanoseconds
+ * @nlink: number of hard links
+ * @uid: owner ID
+ * @gid: group ID
+ * @mode: access flags
+ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc)
+ * @data_len: inode data length
+ * @xattr_cnt: count of extended attributes this inode has
+ * @xattr_size: summarized size of all extended attributes in bytes
+ * @padding1: reserved for future, zeroes
+ * @xattr_names: sum of lengths of all extended attribute names belonging to
+ *               this inode
+ * @compr_type: compression type used for this inode
+ * @padding2: reserved for future, zeroes
+ * @data: data attached to the inode
+ *
+ * Note, even though inode compression type is defined by @compr_type, some
+ * nodes of this inode may be compressed with different compressor - this
+ * happens if compression type is changed while the inode already has data
+ * nodes. But @compr_type will be use for further writes to the inode.
+ *
+ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing
+ * the padding fields.
+ */
+struct ubifs_ino_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le64 creat_sqnum;
+	__le64 size;
+	__le64 atime_sec;
+	__le64 ctime_sec;
+	__le64 mtime_sec;
+	__le32 atime_nsec;
+	__le32 ctime_nsec;
+	__le32 mtime_nsec;
+	__le32 nlink;
+	__le32 uid;
+	__le32 gid;
+	__le32 mode;
+	__le32 flags;
+	__le32 data_len;
+	__le32 xattr_cnt;
+	__le32 xattr_size;
+	__u8 padding1[4]; /* Watch 'zero_ino_node_unused()' if changing! */
+	__le32 xattr_names;
+	__le16 compr_type;
+	__u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+	__u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_dent_node - directory entry node.
+ * @ch: common header
+ * @key: node key
+ * @inum: target inode number
+ * @padding1: reserved for future, zeroes
+ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
+ * @nlen: name length
+ * @cookie: A 32bits random number, used to construct a 64bits
+ *          identifier.
+ * @name: zero-terminated name
+ *
+ * Note, do not forget to amend 'zero_dent_node_unused()' function when
+ * changing the padding fields.
+ */
+struct ubifs_dent_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le64 inum;
+	__u8 padding1;
+	__u8 type;
+	__le16 nlen;
+	__le32 cookie;
+	__u8 name[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_data_node - data node.
+ * @ch: common header
+ * @key: node key
+ * @size: uncompressed data size in bytes
+ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
+ * @compr_size: compressed data size in bytes, only valid when data is encrypted
+ * @data: data
+ *
+ */
+struct ubifs_data_node {
+	struct ubifs_ch ch;
+	__u8 key[UBIFS_MAX_KEY_LEN];
+	__le32 size;
+	__le16 compr_type;
+	__le16 compr_size;
+	__u8 data[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_trun_node - truncation node.
+ * @ch: common header
+ * @inum: truncated inode number
+ * @padding: reserved for future, zeroes
+ * @old_size: size before truncation
+ * @new_size: size after truncation
+ *
+ * This node exists only in the journal and never goes to the main area. Note,
+ * do not forget to amend 'zero_trun_node_unused()' function when changing the
+ * padding fields.
+ */
+struct ubifs_trun_node {
+	struct ubifs_ch ch;
+	__le32 inum;
+	__u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+	__le64 old_size;
+	__le64 new_size;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_pad_node - padding node.
+ * @ch: common header
+ * @pad_len: how many bytes after this node are unused (because padded)
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_pad_node {
+	struct ubifs_ch ch;
+	__le32 pad_len;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_sb_node - superblock node.
+ * @ch: common header
+ * @padding: reserved for future, zeroes
+ * @key_hash: type of hash function used in keys
+ * @key_fmt: format of the key
+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of LEBs used by file-system
+ * @max_leb_cnt: maximum count of LEBs used by file-system
+ * @max_bud_bytes: maximum amount of data stored in buds
+ * @log_lebs: log size in logical eraseblocks
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @orph_lebs: number of LEBs used for recording orphans
+ * @jhead_cnt: count of journal heads
+ * @fanout: tree fanout (max. number of links per indexing node)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @fmt_version: UBIFS on-flash format version
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @padding1: reserved for future, zeroes
+ * @rp_uid: reserve pool UID
+ * @rp_gid: reserve pool GID
+ * @rp_size: size of the reserved pool in bytes
+ * @padding2: reserved for future, zeroes
+ * @time_gran: time granularity in nanoseconds
+ * @uuid: UUID generated when the file system image was created
+ * @ro_compat_version: UBIFS R/O compatibility version
+ * @hmac: HMAC to authenticate the superblock node
+ * @hmac_wkm: HMAC of a well known message (the string "UBIFS") as a convenience
+ *            to the user to check if the correct key is passed.
+ * @hash_algo: The hash algo used for this filesystem (one of enum hash_algo)
+ * @hash_mst: hash of the master node, only valid for signed images in which the
+ *            master node does not contain a hmac
+ */
+struct ubifs_sb_node {
+	struct ubifs_ch ch;
+	__u8 padding[2];
+	__u8 key_hash;
+	__u8 key_fmt;
+	__le32 flags;
+	__le32 min_io_size;
+	__le32 leb_size;
+	__le32 leb_cnt;
+	__le32 max_leb_cnt;
+	__le64 max_bud_bytes;
+	__le32 log_lebs;
+	__le32 lpt_lebs;
+	__le32 orph_lebs;
+	__le32 jhead_cnt;
+	__le32 fanout;
+	__le32 lsave_cnt;
+	__le32 fmt_version;
+	__le16 default_compr;
+	__u8 padding1[2];
+	__le32 rp_uid;
+	__le32 rp_gid;
+	__le64 rp_size;
+	__le32 time_gran;
+	__u8 uuid[16];
+	__le32 ro_compat_version;
+	__u8 hmac[UBIFS_MAX_HMAC_LEN];
+	__u8 hmac_wkm[UBIFS_MAX_HMAC_LEN];
+	__le16 hash_algo;
+	__u8 hash_mst[UBIFS_MAX_HASH_LEN];
+	__u8 padding2[3774];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_mst_node - master node.
+ * @ch: common header
+ * @highest_inum: highest inode number in the committed index
+ * @cmt_no: commit number
+ * @flags: various flags (%UBIFS_MST_DIRTY, etc)
+ * @log_lnum: start of the log
+ * @root_lnum: LEB number of the root indexing node
+ * @root_offs: offset within @root_lnum
+ * @root_len: root indexing node length
+ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was
+ * not reserved and should be reserved on mount)
+ * @ihead_lnum: LEB number of index head
+ * @ihead_offs: offset of index head
+ * @index_size: size of index on flash
+ * @total_free: total free space in bytes
+ * @total_dirty: total dirty space in bytes
+ * @total_used: total used space in bytes (includes only data LEBs)
+ * @total_dead: total dead space in bytes (includes only data LEBs)
+ * @total_dark: total dark space in bytes (includes only data LEBs)
+ * @lpt_lnum: LEB number of LPT root nnode
+ * @lpt_offs: offset of LPT root nnode
+ * @nhead_lnum: LEB number of LPT head
+ * @nhead_offs: offset of LPT head
+ * @ltab_lnum: LEB number of LPT's own lprops table
+ * @ltab_offs: offset of LPT's own lprops table
+ * @lsave_lnum: LEB number of LPT's save table (big model only)
+ * @lsave_offs: offset of LPT's save table (big model only)
+ * @lscan_lnum: LEB number of last LPT scan
+ * @empty_lebs: number of empty logical eraseblocks
+ * @idx_lebs: number of indexing logical eraseblocks
+ * @leb_cnt: count of LEBs used by file-system
+ * @hash_root_idx: the hash of the root index node
+ * @hash_lpt: the hash of the LPT
+ * @hmac: HMAC to authenticate the master node
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_mst_node {
+	struct ubifs_ch ch;
+	__le64 highest_inum;
+	__le64 cmt_no;
+	__le32 flags;
+	__le32 log_lnum;
+	__le32 root_lnum;
+	__le32 root_offs;
+	__le32 root_len;
+	__le32 gc_lnum;
+	__le32 ihead_lnum;
+	__le32 ihead_offs;
+	__le64 index_size;
+	__le64 total_free;
+	__le64 total_dirty;
+	__le64 total_used;
+	__le64 total_dead;
+	__le64 total_dark;
+	__le32 lpt_lnum;
+	__le32 lpt_offs;
+	__le32 nhead_lnum;
+	__le32 nhead_offs;
+	__le32 ltab_lnum;
+	__le32 ltab_offs;
+	__le32 lsave_lnum;
+	__le32 lsave_offs;
+	__le32 lscan_lnum;
+	__le32 empty_lebs;
+	__le32 idx_lebs;
+	__le32 leb_cnt;
+	__u8 hash_root_idx[UBIFS_MAX_HASH_LEN];
+	__u8 hash_lpt[UBIFS_MAX_HASH_LEN];
+	__u8 hmac[UBIFS_MAX_HMAC_LEN];
+	__u8 padding[152];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_ref_node - logical eraseblock reference node.
+ * @ch: common header
+ * @lnum: the referred logical eraseblock number
+ * @offs: start offset in the referred LEB
+ * @jhead: journal head number
+ * @padding: reserved for future, zeroes
+ */
+struct ubifs_ref_node {
+	struct ubifs_ch ch;
+	__le32 lnum;
+	__le32 offs;
+	__le32 jhead;
+	__u8 padding[28];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_auth_node - node for authenticating other nodes
+ * @ch: common header
+ * @hmac: The HMAC
+ */
+struct ubifs_auth_node {
+	struct ubifs_ch ch;
+	__u8 hmac[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_sig_node - node for signing other nodes
+ * @ch: common header
+ * @type: type of the signature, currently only UBIFS_SIGNATURE_TYPE_PKCS7
+ * supported
+ * @len: The length of the signature data
+ * @padding: reserved for future, zeroes
+ * @sig: The signature data
+ */
+struct ubifs_sig_node {
+	struct ubifs_ch ch;
+	__le32 type;
+	__le32 len;
+	__u8 padding[32];
+	__u8 sig[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_branch - key/reference/length branch
+ * @lnum: LEB number of the target node
+ * @offs: offset within @lnum
+ * @len: target node length
+ * @key: key
+ *
+ * In an authenticated UBIFS we have the hash of the referenced node after @key.
+ * This can't be added to the struct type definition because @key is a
+ * dynamically sized element already.
+ */
+struct ubifs_branch {
+	__le32 lnum;
+	__le32 offs;
+	__le32 len;
+	__u8 key[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_idx_node - indexing node.
+ * @ch: common header
+ * @child_cnt: number of child index nodes
+ * @level: tree level
+ * @branches: LEB number / offset / length / key branches
+ */
+struct ubifs_idx_node {
+	struct ubifs_ch ch;
+	__le16 child_cnt;
+	__le16 level;
+	__u8 branches[];
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_cs_node - commit start node.
+ * @ch: common header
+ * @cmt_no: commit number
+ */
+struct ubifs_cs_node {
+	struct ubifs_ch ch;
+	__le64 cmt_no;
+} __attribute__ ((packed));
+
+/**
+ * struct ubifs_orph_node - orphan node.
+ * @ch: common header
+ * @cmt_no: commit number (also top bit is set on the last node of the commit)
+ * @inos: inode numbers of orphans
+ */
+struct ubifs_orph_node {
+	struct ubifs_ch ch;
+	__le64 cmt_no;
+	__le64 inos[];
+} __attribute__ ((packed));
+
+#endif /* __UBIFS_MEDIA_H__ */

+ 51 - 0
EVSE/GPL/mtd-utils-2.1.2/include/mtd_swab.h

@@ -0,0 +1,51 @@
+#ifndef MTD_SWAB_H
+#define MTD_SWAB_H
+
+#include <endian.h>
+
+#define swab16(x) \
+        ((uint16_t)( \
+                (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
+                (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
+#define swab32(x) \
+        ((uint32_t)( \
+                (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+                (((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) | \
+                (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) | \
+                (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#define swab64(x) \
+		((uint64_t)( \
+				(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+				(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+				(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+				(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
+				(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
+				(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+				(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+				(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); })
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be64(x) (x)
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); })
+#endif
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+#define le64_to_cpu(x) cpu_to_le64(x)
+#define be64_to_cpu(x) cpu_to_be64(x)
+
+#endif

+ 106 - 0
EVSE/GPL/mtd-utils-2.1.2/include/xalloc.h

@@ -0,0 +1,106 @@
+/*
+ * memory wrappers
+ *
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ * Copyright 2001, 2002 Red Hat, Inc.
+ *           2001 David A. Schleef <ds@lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen@codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *           2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MTD_UTILS_XALLOC_H__
+#define __MTD_UTILS_XALLOC_H__
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Mark these functions as unused so that gcc does not emit warnings
+ * when people include this header but don't use every function.
+ */
+
+__attribute__((unused))
+static void *xmalloc(size_t size)
+{
+	void *ptr = malloc(size);
+
+	if (ptr == NULL && size != 0)
+		sys_errmsg_die("out of memory");
+	return ptr;
+}
+
+__attribute__((unused))
+static void *xcalloc(size_t nmemb, size_t size)
+{
+	void *ptr = calloc(nmemb, size);
+
+	if (ptr == NULL && nmemb != 0 && size != 0)
+		sys_errmsg_die("out of memory");
+	return ptr;
+}
+
+__attribute__((unused))
+static void *xzalloc(size_t size)
+{
+	return xcalloc(1, size);
+}
+
+__attribute__((unused))
+static void *xrealloc(void *ptr, size_t size)
+{
+	ptr = realloc(ptr, size);
+	if (ptr == NULL && size != 0)
+		sys_errmsg_die("out of memory");
+	return ptr;
+}
+
+__attribute__((unused))
+static char *xstrdup(const char *s)
+{
+	char *t;
+
+	if (s == NULL)
+		return NULL;
+	t = strdup(s);
+	if (t == NULL)
+		sys_errmsg_die("out of memory");
+	return t;
+}
+
+#ifdef _GNU_SOURCE
+
+__attribute__((unused))
+static int xasprintf(char **strp, const char *fmt, ...)
+{
+	int cnt;
+	va_list ap;
+
+	va_start(ap, fmt);
+	cnt = vasprintf(strp, fmt, ap);
+	va_end(ap);
+
+	if (cnt == -1)
+		sys_errmsg_die("out of memory");
+
+	return cnt;
+}
+#endif
+
+#endif /* !__MTD_UTILS_XALLOC_H__ */

+ 37 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/Makemodule.am

@@ -0,0 +1,37 @@
+mkfs_jffs2_SOURCES = \
+	jffsX-utils/mkfs.jffs2.c \
+	jffsX-utils/rbtree.h \
+	jffsX-utils/compr_zlib.c \
+	jffsX-utils/compr.h \
+	jffsX-utils/rbtree.c \
+	jffsX-utils/compr_lzo.c \
+	jffsX-utils/compr.c \
+	jffsX-utils/compr_rtime.c
+mkfs_jffs2_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS)
+mkfs_jffs2_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_CFLAGS) $(LZO_CFLAGS)
+
+jffs2reader_SOURCES = jffsX-utils/jffs2reader.c
+jffs2reader_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS)
+
+jffs2dump_SOURCES = jffsX-utils/jffs2dump.c
+jffs2dump_LDADD = libmtd.a $(ZLIB_LIBS) $(LZO_LIBS)
+
+sumtool_SOURCES = jffsX-utils/sumtool.c
+sumtool_LDADD = libmtd.a
+
+JFFSX_BINS = \
+	mkfs.jffs2 jffs2dump jffs2reader sumtool
+
+JFFSX_MAN = \
+	jffsX-utils/mkfs.jffs2.1
+
+JFFSX_EXTRA = \
+	jffsX-utils/device_table.txt jffsX-utils/mkfs.jffs2.1
+
+JFFSX_HEADER = \
+	jffsX-utils/compr.h jffsX-utils/rbtree.h jffsX-utils/summary.h
+
+EXTRA_DIST += $(JFFSX_HEADER) $(JFFSX_EXTRA)
+
+dist_man1_MANS += $(JFFSX_MAN)
+sbin_PROGRAMS += $(JFFSX_BINS)

+ 538 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr.c

@@ -0,0 +1,538 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory
+ * in the jffs2 directory.
+ */
+
+#include "compr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <linux/jffs2.h>
+
+#define FAVOUR_LZO_PERCENT 80
+
+extern int page_size;
+
+/* LIST IMPLEMENTATION (from linux/list.h) */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void __list_add(struct list_head *new,
+		struct list_head *prev,
+		struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = (void *) 0;
+	entry->prev = (void *) 0;
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each_entry(pos, head, member)                          \
+	for (pos = list_entry((head)->next, typeof(*pos), member);      \
+			&pos->member != (head);                                    \
+			pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+
+void jffs2_set_compression_mode(int mode)
+{
+	jffs2_compression_mode = mode;
+}
+
+int jffs2_get_compression_mode(void)
+{
+	return jffs2_compression_mode;
+}
+
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
+
+/* Compression test stuffs */
+
+static int jffs2_compression_check = 0;
+
+static unsigned char *jffs2_compression_check_buf = NULL;
+
+void jffs2_compression_check_set(int yesno)
+{
+	jffs2_compression_check = yesno;
+}
+
+int jffs2_compression_check_get(void)
+{
+	return jffs2_compression_check;
+}
+
+static int jffs2_error_cnt = 0;
+
+int jffs2_compression_check_errorcnt_get(void)
+{
+	return jffs2_error_cnt;
+}
+
+#define JFFS2_BUFFER_FILL 0x55
+
+/* Called before compression (if compression_check is setted) to prepare
+   the buffer for buffer overflow test */
+static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
+{
+	memset(buf,JFFS2_BUFFER_FILL,size+1);
+}
+
+/* Called after compression (if compression_check is setted) to test the result */
+static void jffs2_decompression_test(struct jffs2_compressor *compr,
+		unsigned char *data_in, unsigned char *output_buf,
+		uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
+{
+	uint32_t i;
+
+	/* buffer overflow test */
+	for (i=buf_size;i>cdatalen;i--) {
+		if (output_buf[i]!=JFFS2_BUFFER_FILL) {
+			fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
+					"(bs=%d csize=%d b[%d]=%d)\n", compr->name,
+					buf_size, cdatalen, i, (int)(output_buf[i]));
+			jffs2_error_cnt++;
+			return;
+		}
+	}
+	/* allocing temporary buffer for decompression */
+	if (!jffs2_compression_check_buf) {
+		jffs2_compression_check_buf = malloc(page_size);
+		if (!jffs2_compression_check_buf) {
+			fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
+			jffs2_compression_check = 0;
+			return;
+		}
+	}
+	/* decompressing */
+	if (!compr->decompress) {
+		fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
+		jffs2_error_cnt++;
+		return;
+	}
+	if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
+		fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
+		jffs2_error_cnt++;
+	}
+	/* validate decompression */
+	else {
+		for (i=0;i<datalen;i++) {
+			if (data_in[i]!=jffs2_compression_check_buf[i]) {
+				fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
+				jffs2_error_cnt++;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Return 1 to use this compression
+ */
+static int jffs2_is_best_compression(struct jffs2_compressor *this,
+		struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
+{
+	switch (jffs2_compression_mode) {
+	case JFFS2_COMPR_MODE_SIZE:
+		if (bestsize > size)
+			return 1;
+		return 0;
+	case JFFS2_COMPR_MODE_FAVOURLZO:
+		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
+			return 1;
+		if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
+			return 1;
+		if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
+			return 1;
+		if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
+			return 1;
+
+		return 0;
+	}
+	/* Shouldn't happen */
+	return 0;
+}
+
+/* jffs2_compress:
+ * @data: Pointer to uncompressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
+ * @datalen: On entry, holds the amount of data available for compression.
+ *	On exit, expected to hold the amount of data actually compressed.
+ * @cdatalen: On entry, holds the amount of space available for compressed
+ *	data. On exit, expected to hold the actual size of the compressed
+ *	data.
+ *
+ * Returns: Lower byte to be stored with data indicating compression type used.
+ * Zero is used to show that the data could not be compressed - the
+ * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
+ *
+ * If the cdata buffer isn't large enough to hold all the uncompressed data,
+ * jffs2_compress should compress as much as will fit, and should set
+ * *datalen accordingly to show the amount of data which were compressed.
+ */
+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
+		uint32_t *datalen, uint32_t *cdatalen)
+{
+	int ret = JFFS2_COMPR_NONE;
+	int compr_ret;
+	struct jffs2_compressor *this, *best=NULL;
+	unsigned char *output_buf = NULL, *tmp_buf;
+	uint32_t orig_slen, orig_dlen;
+	uint32_t best_slen=0, best_dlen=0;
+
+	switch (jffs2_compression_mode) {
+		case JFFS2_COMPR_MODE_NONE:
+			break;
+		case JFFS2_COMPR_MODE_PRIORITY:
+			orig_slen = *datalen;
+			orig_dlen = *cdatalen;
+			output_buf = malloc(orig_dlen+jffs2_compression_check);
+			if (!output_buf) {
+				fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
+				goto out;
+			}
+			list_for_each_entry(this, &jffs2_compressor_list, list) {
+				/* Skip decompress-only backwards-compatibility and disabled modules */
+				if ((!this->compress)||(this->disabled))
+					continue;
+
+				this->usecount++;
+
+				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+					jffs2_decompression_test_prepare(output_buf, orig_dlen);
+
+				*datalen  = orig_slen;
+				*cdatalen = orig_dlen;
+				compr_ret = this->compress(data_in, output_buf, datalen, cdatalen);
+				this->usecount--;
+				if (!compr_ret) {
+					ret = this->compr;
+					this->stat_compr_blocks++;
+					this->stat_compr_orig_size += *datalen;
+					this->stat_compr_new_size  += *cdatalen;
+					if (jffs2_compression_check)
+						jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
+					break;
+				}
+			}
+			if (ret == JFFS2_COMPR_NONE) free(output_buf);
+			break;
+		case JFFS2_COMPR_MODE_FAVOURLZO:
+		case JFFS2_COMPR_MODE_SIZE:
+			orig_slen = *datalen;
+			orig_dlen = *cdatalen;
+			list_for_each_entry(this, &jffs2_compressor_list, list) {
+				uint32_t needed_buf_size;
+
+				if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
+					needed_buf_size = orig_slen + jffs2_compression_check;
+				else
+					needed_buf_size = orig_dlen + jffs2_compression_check;
+
+				/* Skip decompress-only backwards-compatibility and disabled modules */
+				if ((!this->compress)||(this->disabled))
+					continue;
+				/* Allocating memory for output buffer if necessary */
+				if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) {
+					free(this->compr_buf);
+					this->compr_buf_size=0;
+					this->compr_buf=NULL;
+				}
+				if (!this->compr_buf) {
+					tmp_buf = malloc(needed_buf_size);
+					if (!tmp_buf) {
+						fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+						continue;
+					}
+					else {
+						this->compr_buf = tmp_buf;
+						this->compr_buf_size = orig_dlen;
+					}
+				}
+				this->usecount++;
+				if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+					jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
+				*datalen  = orig_slen;
+				*cdatalen = orig_dlen;
+				compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
+				this->usecount--;
+				if (!compr_ret) {
+					if (jffs2_compression_check)
+						jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
+					if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
+								&& (*cdatalen < *datalen)) {
+						best_dlen = *cdatalen;
+						best_slen = *datalen;
+						best = this;
+					}
+				}
+			}
+			if (best_dlen) {
+				*cdatalen = best_dlen;
+				*datalen  = best_slen;
+				output_buf = best->compr_buf;
+				best->compr_buf = NULL;
+				best->compr_buf_size = 0;
+				best->stat_compr_blocks++;
+				best->stat_compr_orig_size += best_slen;
+				best->stat_compr_new_size  += best_dlen;
+				ret = best->compr;
+			}
+			break;
+		default:
+			fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n");
+	}
+out:
+	if (ret == JFFS2_COMPR_NONE) {
+		*cpage_out = data_in;
+		*datalen = *cdatalen;
+		none_stat_compr_blocks++;
+		none_stat_compr_size += *datalen;
+	}
+	else {
+		*cpage_out = output_buf;
+	}
+	return ret;
+}
+
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+	struct jffs2_compressor *this;
+
+	if (!comp->name) {
+		fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
+		return -1;
+	}
+	comp->compr_buf_size=0;
+	comp->compr_buf=NULL;
+	comp->usecount=0;
+	comp->stat_compr_orig_size=0;
+	comp->stat_compr_new_size=0;
+	comp->stat_compr_blocks=0;
+	comp->stat_decompr_blocks=0;
+
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (this->priority < comp->priority) {
+			list_add(&comp->list, this->list.prev);
+			goto out;
+		}
+	}
+	list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+	return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+
+	if (comp->usecount) {
+		fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
+		return -1;
+	}
+	list_del(&comp->list);
+
+	return 0;
+}
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+		if ((this->disabled)||(!this->compress))
+			act_buf += sprintf(act_buf,"disabled");
+		else
+			act_buf += sprintf(act_buf,"enabled");
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+char *jffs2_stats(void)
+{
+	struct jffs2_compressor *this;
+	char *buf, *act_buf;
+
+	act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+
+	act_buf += sprintf(act_buf,"Compression mode: ");
+	switch (jffs2_compression_mode) {
+		case JFFS2_COMPR_MODE_NONE:
+			act_buf += sprintf(act_buf,"none");
+			break;
+		case JFFS2_COMPR_MODE_PRIORITY:
+			act_buf += sprintf(act_buf,"priority");
+			break;
+		case JFFS2_COMPR_MODE_SIZE:
+			act_buf += sprintf(act_buf,"size");
+			break;
+		case JFFS2_COMPR_MODE_FAVOURLZO:
+			act_buf += sprintf(act_buf, "favourlzo");
+			break;
+		default:
+			act_buf += sprintf(act_buf, "unknown");
+			break;
+	}
+	act_buf += sprintf(act_buf,"\nCompressors:\n");
+	act_buf += sprintf(act_buf,"%10s             ","none");
+	act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
+			none_stat_compr_size, none_stat_decompr_blocks);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
+		if ((this->disabled)||(!this->compress))
+			act_buf += sprintf(act_buf,"- ");
+		else
+			act_buf += sprintf(act_buf,"+ ");
+		act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
+				this->stat_compr_new_size, this->stat_compr_orig_size,
+				this->stat_decompr_blocks);
+		act_buf += sprintf(act_buf,"\n");
+	}
+	return buf;
+}
+
+int jffs2_set_compression_mode_name(const char *name)
+{
+	if (!strcmp("none",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+		return 0;
+	}
+	if (!strcmp("priority",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+		return 0;
+	}
+	if (!strcmp("size",name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+		return 0;
+	}
+	if (!strcmp("favourlzo", name)) {
+		jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
+		return 0;
+	}
+
+	return 1;
+}
+
+static int jffs2_compressor_Xable(const char *name, int disabled)
+{
+	struct jffs2_compressor *this;
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (!strcmp(this->name, name)) {
+			this->disabled = disabled;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int jffs2_enable_compressor_name(const char *name)
+{
+	return jffs2_compressor_Xable(name, 0);
+}
+
+int jffs2_disable_compressor_name(const char *name)
+{
+	return jffs2_compressor_Xable(name, 1);
+}
+
+int jffs2_set_compressor_priority(const char *name, int priority)
+{
+	struct jffs2_compressor *this,*comp;
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (!strcmp(this->name, name)) {
+			this->priority = priority;
+			comp = this;
+			goto reinsert;
+		}
+	}
+	fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
+	return 1;
+reinsert:
+	/* list is sorted in the order of priority, so if
+	   we change it we have to reinsert it into the
+	   good place */
+	list_del(&comp->list);
+	list_for_each_entry(this, &jffs2_compressor_list, list) {
+		if (this->priority < comp->priority) {
+			list_add(&comp->list, this->list.prev);
+			return 0;
+		}
+	}
+	list_add_tail(&comp->list, &jffs2_compressor_list);
+	return 0;
+}
+
+
+int jffs2_compressors_init(void)
+{
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+	jffs2_lzo_init();
+#endif
+	return 0;
+}
+
+int jffs2_compressors_exit(void)
+{
+#ifdef CONFIG_JFFS2_RTIME
+	jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+	jffs2_zlib_exit();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+	jffs2_lzo_exit();
+#endif
+	return 0;
+}

+ 119 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr.h

@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "linux/jffs2.h"
+
+#define CONFIG_JFFS2_ZLIB
+#define CONFIG_JFFS2_RTIME
+#define CONFIG_JFFS2_LZO
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY  20
+#define JFFS2_RTIME_PRIORITY     50
+#define JFFS2_ZLIB_PRIORITY      60
+#define JFFS2_LZO_PRIORITY       80
+
+#define JFFS2_COMPR_MODE_NONE       0
+#define JFFS2_COMPR_MODE_PRIORITY   1
+#define JFFS2_COMPR_MODE_SIZE       2
+#define JFFS2_COMPR_MODE_FAVOURLZO  3
+
+#define kmalloc(a,b)                malloc(a)
+#define kfree(a)                    free(a)
+#ifndef GFP_KERNEL
+#define GFP_KERNEL                  0
+#endif
+
+#define vmalloc(a)                  malloc(a)
+#define vfree(a)                    free(a)
+
+#define printk(...)                 fprintf(stderr,__VA_ARGS__)
+
+#define KERN_EMERG
+#define KERN_ALERT
+#define KERN_CRIT
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_NOTICE
+#define KERN_INFO
+#define KERN_DEBUG
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+void jffs2_set_compression_mode(int mode);
+int jffs2_get_compression_mode(void);
+int jffs2_set_compression_mode_name(const char *mode_name);
+
+int jffs2_enable_compressor_name(const char *name);
+int jffs2_disable_compressor_name(const char *name);
+
+int jffs2_set_compressor_priority(const char *name, int priority);
+
+struct jffs2_compressor {
+	struct list_head list;
+	int priority;             /* used by prirority comr. mode */
+	const char *name;
+	char compr;               /* JFFS2_COMPR_XXX */
+	int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+			uint32_t *srclen, uint32_t *destlen);
+	int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+			uint32_t cdatalen, uint32_t datalen);
+	int usecount;
+	int disabled;             /* if seted the compressor won't compress */
+	unsigned char *compr_buf; /* used by size compr. mode */
+	uint32_t compr_buf_size;  /* used by size compr. mode */
+	uint32_t stat_compr_orig_size;
+	uint32_t stat_compr_new_size;
+	uint32_t stat_compr_blocks;
+	uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
+		uint32_t *datalen, uint32_t *cdatalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+int jffs2_compression_check_get(void);
+int jffs2_compression_check_errorcnt_get(void);
+
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+
+/* Compressor modules */
+
+/* These functions will be called by jffs2_compressors_init/exit */
+#ifdef CONFIG_JFFS2_ZLIB
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+int jffs2_rtime_init(void);
+void jffs2_rtime_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
+
+#endif /* __JFFS2_COMPR_H__ */

+ 136 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_lzo.c

@@ -0,0 +1,136 @@
+/*
+ * JFFS2 LZO Compression Interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WITHOUT_LZO
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include <lzo/lzo1x.h>
+#include "compr.h"
+
+extern int page_size;
+
+static void *lzo_mem;
+static void *lzo_compress_buf;
+
+/*
+ * Note about LZO compression.
+ *
+ * We want to use the _999_ compression routine which gives better compression
+ * rates at the expense of time. Decompression time is unaffected. We might as
+ * well use the standard lzo library routines for this but they will overflow
+ * the destination buffer since they don't check the destination size.
+ *
+ * We therefore compress to a temporary buffer and copy if it will fit.
+ *
+ */
+static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
+			  uint32_t *sourcelen, uint32_t *dstlen)
+{
+	lzo_uint compress_size;
+	int ret;
+
+	ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
+
+	if (ret != LZO_E_OK)
+		return -1;
+
+	if (compress_size > *dstlen)
+		return -1;
+
+	memcpy(cpage_out, lzo_compress_buf, compress_size);
+	*dstlen = compress_size;
+
+	return 0;
+}
+
+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
+				 uint32_t srclen, uint32_t destlen)
+{
+	int ret;
+	lzo_uint dl;
+
+	dl = destlen;
+	ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
+
+	if (ret != LZO_E_OK || dl != destlen)
+		return -1;
+
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_lzo_comp = {
+	.priority = JFFS2_LZO_PRIORITY,
+	.name = "lzo",
+	.compr = JFFS2_COMPR_LZO,
+	.compress = &jffs2_lzo_cmpr,
+	.decompress = &jffs2_lzo_decompress,
+	.disabled = 1,
+};
+
+int jffs2_lzo_init(void)
+{
+	int ret;
+
+	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
+	if (!lzo_mem)
+		return -1;
+
+	/* Worse case LZO compression size from their FAQ */
+	lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
+	if (!lzo_compress_buf) {
+		free(lzo_mem);
+		return -1;
+	}
+
+	ret = jffs2_register_compressor(&jffs2_lzo_comp);
+	if (ret < 0) {
+		free(lzo_compress_buf);
+		free(lzo_mem);
+	}
+
+	return ret;
+}
+
+void jffs2_lzo_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_lzo_comp);
+	free(lzo_compress_buf);
+	free(lzo_mem);
+}
+
+#else
+
+int jffs2_lzo_init(void)
+{
+	return 0;
+}
+
+void jffs2_lzo_exit(void)
+{
+}
+
+#endif

+ 119 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_rtime.c

@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * Very simple lz77-ish encoder.
+ *
+ * Theory of operation: Both encoder and decoder have a list of "last
+ * occurrences" for every possible source-value; after sending the
+ * first source-byte, the second byte indicated the "run" length of
+ * matches
+ *
+ * The algorithm is intended to only send "whole bytes", no bit-messing.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "compr.h"
+
+/* _compress returns the compressed size, -1 if bigger */
+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t *sourcelen, uint32_t *dstlen)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions,0,sizeof(positions));
+
+	while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) {
+		int backpos, runlen=0;
+		unsigned char value;
+
+		value = data_in[pos];
+
+		cpage_out[outpos++] = data_in[pos++];
+
+		backpos = positions[value];
+		positions[value]=pos;
+
+		while ((backpos < pos) && (pos < (*sourcelen)) &&
+				(data_in[pos]==data_in[backpos++]) && (runlen<255)) {
+			pos++;
+			runlen++;
+		}
+		cpage_out[outpos++] = runlen;
+	}
+
+	if (outpos >= pos) {
+		/* We failed */
+		return -1;
+	}
+
+	/* Tell the caller how much we managed to compress, and how much space it took */
+	*sourcelen = pos;
+	*dstlen = outpos;
+	return 0;
+}
+
+
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		__attribute__((unused)) uint32_t srclen, uint32_t destlen)
+{
+	short positions[256];
+	int outpos = 0;
+	int pos=0;
+
+	memset(positions,0,sizeof(positions));
+
+	while (outpos<destlen) {
+		unsigned char value;
+		int backoffs;
+		int repeat;
+
+		value = data_in[pos++];
+		cpage_out[outpos++] = value; /* first the verbatim copied byte */
+		repeat = data_in[pos++];
+		backoffs = positions[value];
+
+		positions[value]=outpos;
+		if (repeat) {
+			if (backoffs + repeat >= outpos) {
+				while(repeat) {
+					cpage_out[outpos++] = cpage_out[backoffs++];
+					repeat--;
+				}
+			} else {
+				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
+				outpos+=repeat;
+			}
+		}
+	}
+	return 0;
+}
+
+
+static struct jffs2_compressor jffs2_rtime_comp = {
+	.priority = JFFS2_RTIME_PRIORITY,
+	.name = "rtime",
+	.disabled = 0,
+	.compr = JFFS2_COMPR_RTIME,
+	.compress = &jffs2_rtime_compress,
+	.decompress = &jffs2_rtime_decompress,
+};
+
+int jffs2_rtime_init(void)
+{
+	return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_rtime_comp);
+}

+ 148 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/compr_zlib.c

@@ -0,0 +1,148 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ * The original JFFS, from which the design for JFFS2 was derived,
+ * was designed and implemented by Axis Communications AB.
+ *
+ * The contents of this file are subject to the Red Hat eCos Public
+ * License Version 1.1 (the "Licence"); you may not use this file
+ * except in compliance with the Licence.  You may obtain a copy of
+ * the Licence at http://www.redhat.com/
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+ *
+ * The Original Code is JFFS2 - Journalling Flash File System, version 2
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the RHEPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ */
+
+#define PROGRAM_NAME "compr_zlib"
+
+#include <stdint.h>
+#define crc32 __zlib_crc32
+#include <zlib.h>
+#undef crc32
+#include <stdio.h>
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include "common.h"
+#include "compr.h"
+
+/* Plan: call deflate() with avail_in == *sourcelen,
+   avail_out = *dstlen - 12 and flush == Z_FINISH.
+   If it doesn't manage to finish,	call it again with
+   avail_in == 0 and avail_out set to the remaining 12
+   bytes for it to clean up.
+Q: Is 12 bytes sufficient?
+ */
+#define STREAM_END_SPACE 12
+
+static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t *sourcelen, uint32_t *dstlen)
+{
+	z_stream strm;
+	int ret;
+
+	if (*dstlen <= STREAM_END_SPACE)
+		return -1;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != deflateInit(&strm, 3)) {
+		return -1;
+	}
+	strm.next_in = data_in;
+	strm.total_in = 0;
+
+	strm.next_out = cpage_out;
+	strm.total_out = 0;
+
+	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
+		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
+		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
+		ret = deflate(&strm, Z_PARTIAL_FLUSH);
+		if (ret != Z_OK) {
+			deflateEnd(&strm);
+			return -1;
+		}
+	}
+	strm.avail_out += STREAM_END_SPACE;
+	strm.avail_in = 0;
+	ret = deflate(&strm, Z_FINISH);
+	if (ret != Z_STREAM_END) {
+		deflateEnd(&strm);
+		return -1;
+	}
+	deflateEnd(&strm);
+
+	if (strm.total_out >= strm.total_in)
+		return -1;
+
+
+	*dstlen = strm.total_out;
+	*sourcelen = strm.total_in;
+	return 0;
+}
+
+static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+		uint32_t srclen, uint32_t destlen)
+{
+	z_stream strm;
+	int ret;
+
+	strm.zalloc = (void *)0;
+	strm.zfree = (void *)0;
+
+	if (Z_OK != inflateInit(&strm)) {
+		return 1;
+	}
+	strm.next_in = data_in;
+	strm.avail_in = srclen;
+	strm.total_in = 0;
+
+	strm.next_out = cpage_out;
+	strm.avail_out = destlen;
+	strm.total_out = 0;
+
+	while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+		;
+
+	inflateEnd(&strm);
+	return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+	.priority = JFFS2_ZLIB_PRIORITY,
+	.name = "zlib",
+	.disabled = 0,
+	.compr = JFFS2_COMPR_ZLIB,
+	.compress = &jffs2_zlib_compress,
+	.decompress = &jffs2_zlib_decompress,
+};
+
+int jffs2_zlib_init(void)
+{
+	return jffs2_register_compressor(&jffs2_zlib_comp);
+}
+
+void jffs2_zlib_exit(void)
+{
+	jffs2_unregister_compressor(&jffs2_zlib_comp);
+}

+ 129 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/device_table.txt

@@ -0,0 +1,129 @@
+# This is a sample device table file for use with mkfs.jffs2.  You can
+# do all sorts of interesting things with a device table file.  For
+# example, if you want to adjust the permissions on a particular file
+# you can just add an entry like:
+#   /sbin/foobar	f	2755	0	0	-	-	-	-	-
+# and (assuming the file /sbin/foobar exists) it will be made setuid
+# root (regardless of what its permissions are on the host filesystem.
+#
+# Device table entries take the form of:
+# <name>		<type>	<mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
+# where name is the file name,  type can be one of:
+#	f	A regular file
+#	d	Directory
+#	c	Character special device file
+#	b	Block special device file
+#	p	Fifo (named pipe)
+#	l	Link
+# uid is the user id for the target file, gid is the group id for the
+# target file.  The rest of the entried apply only to device special
+# file.
+
+# When building a target filesystem, it is desirable to not have to
+# become root and then run 'mknod' a thousand times.  Using a device
+# table you can create device nodes and directories "on the fly".
+# Furthermore, you can use a single table entry to create a many device
+# minors.  For example, if I wanted to create /dev/hda and /dev/hda[0-15]
+# I could just use the following two table entries:
+#   /dev/hda	b	640	0	0	3	0	0	0	-
+#   /dev/hda	b	640	0	0	3	1	1	1	15
+#
+# Have fun
+# -Erik Andersen <andersen@codepoet.org>
+#
+
+#<name>		<type>	<mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
+/dev		d	755	0	0	-	-	-	-	-
+/dev/mem	c	640	0	0	1	1	0	0	-
+/dev/kmem	c	640	0	0	1	2	0	0	-
+/dev/null	c	640	0	0	1	3	0	0	-
+/dev/zero	c	640	0	0	1	5	0	0	-
+/dev/random	c	640	0	0	1	8	0	0	-
+/dev/urandom	c	640	0	0	1	9	0	0	-
+/dev/tty	c	666	0	0	5	0	0	0	-
+/dev/tty	c	666	0	0	4	0	0	1	6
+/dev/console	c	640	0	0	5	1	0	0	-
+/dev/ram	b	640	0	0	1	1	0	0	-
+/dev/ram	b	640	0	0	1	0	0	1	4
+/dev/loop	b	640	0	0	7	0	0	1	2
+/dev/ptmx	c	666	0	0	5	2	0	0	-
+#/dev/ttyS	c	640	0	0	4	64	0	1	4
+#/dev/psaux	c	640	0	0	10	1	0	0	-
+#/dev/rtc	c	640	0	0	10	135	0	0	-
+
+# Adjust permissions on some normal files
+#/etc/shadow	f	600	0	0	-	-	-	-	-
+#/bin/tinylogin	f	4755	0	0	-	-	-	-	-
+
+# User-mode Linux stuff
+/dev/ubda	b	640	0	0	98	0	0	0	-
+/dev/ubda	b	640	0	0	98	1	1	1	15
+
+# IDE Devices
+/dev/hda	b	640	0	0	3	0	0	0	-
+/dev/hda	b	640	0	0	3	1	1	1	15
+/dev/hdb	b	640	0	0	3	64	0	0	-
+/dev/hdb	b	640	0	0	3	65	1	1	15
+#/dev/hdc	b	640	0	0	22	0	0	0	-
+#/dev/hdc	b	640	0	0	22	1	1	1	15
+#/dev/hdd	b	640	0	0	22	64	0	0	-
+#/dev/hdd	b	640	0	0	22	65	1	1	15
+#/dev/hde	b	640	0	0	33	0	0	0	-
+#/dev/hde	b	640	0	0	33	1	1	1	15
+#/dev/hdf	b	640	0	0	33	64	0	0	-
+#/dev/hdf	b	640	0	0	33	65	1	1	15
+#/dev/hdg	b	640	0	0	34	0	0	0	-
+#/dev/hdg	b	640	0	0	34	1	1	1	15
+#/dev/hdh	b	640	0	0	34	64	0	0	-
+#/dev/hdh	b	640	0	0	34	65	1	1	15
+
+# SCSI Devices
+#/dev/sda	b	640	0	0	8	0	0	0	-
+#/dev/sda	b	640	0	0	8	1	1	1	15
+#/dev/sdb	b	640	0	0	8	16	0	0	-
+#/dev/sdb	b	640	0	0	8	17	1	1	15
+#/dev/sdc	b	640	0	0	8	32	0	0	-
+#/dev/sdc	b	640	0	0	8	33	1	1	15
+#/dev/sdd	b	640	0	0	8	48	0	0	-
+#/dev/sdd	b	640	0	0	8	49	1	1	15
+#/dev/sde	b	640	0	0	8	64	0	0	-
+#/dev/sde	b	640	0	0	8	65	1	1	15
+#/dev/sdf	b	640	0	0	8	80	0	0	-
+#/dev/sdf	b	640	0	0	8	81	1	1	15
+#/dev/sdg	b	640	0	0	8	96	0	0	-
+#/dev/sdg	b	640	0	0	8	97	1	1	15
+#/dev/sdh	b	640	0	0	8	112	0	0	-
+#/dev/sdh	b	640	0	0	8	113	1	1	15
+#/dev/sg		c	640	0	0	21	0	0	1	15
+#/dev/scd	b	640	0	0	11	0	0	1	15
+#/dev/st		c	640	0	0	9	0	0	1	8
+#/dev/nst	c	640	0	0	9	128	0	1	8
+#/dev/st	c	640	0	0	9	32	1	1	4
+#/dev/st	c	640	0	0	9	64	1	1	4
+#/dev/st	c	640	0	0	9	96	1	1	4
+
+# Floppy disk devices
+#/dev/fd		b	640	0	0	2	0	0	1	2
+#/dev/fd0d360	b	640	0	0	2	4	0	0	-
+#/dev/fd1d360	b	640	0	0	2	5	0	0	-
+#/dev/fd0h1200	b	640	0	0	2	8	0	0	-
+#/dev/fd1h1200	b	640	0	0	2	9	0	0	-
+#/dev/fd0u1440	b	640	0	0	2	28	0	0	-
+#/dev/fd1u1440	b	640	0	0	2	29	0	0	-
+#/dev/fd0u2880	b	640	0	0	2	32	0	0	-
+#/dev/fd1u2880	b	640	0	0	2	33	0	0	-
+
+# All the proprietary cdrom devices in the world
+#/dev/aztcd	b	640	0	0	29	0	0	0	-
+#/dev/bpcd	b	640	0	0	41	0	0	0	-
+#/dev/capi20	c	640	0	0	68	0	0	1	2
+#/dev/cdu31a	b	640	0	0	15	0	0	0	-
+#/dev/cdu535	b	640	0	0	24	0	0	0	-
+#/dev/cm206cd	b	640	0	0	32	0	0	0	-
+#/dev/sjcd	b	640	0	0	18	0	0	0	-
+#/dev/sonycd	b	640	0	0	15	0	0	0	-
+#/dev/gscd	b	640	0	0	16	0	0	0	-
+#/dev/sbpcd	b	640	0	0	25	0	0	0	-
+#/dev/sbpcd	b	640	0	0	25	0	0	1	4
+#/dev/mcd	b	640	0	0	23	0	0	0	-
+#/dev/optcd	b	640	0	0	17	0	0	0	-

+ 801 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/jffs2dump.c

@@ -0,0 +1,801 @@
+/*
+ *  dumpjffs2.c
+ *
+ *  Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ *   This utility dumps the contents of a binary JFFS2 image
+ *
+ *
+ * Bug/ToDo:
+ */
+
+#define PROGRAM_NAME "jffs2dump"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <crc32.h>
+#include "summary.h"
+#include "common.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+/* For outputting a byte-swapped version of the input image. */
+#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)})
+#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)})
+
+#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; })
+#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)})
+
+// Global variables
+long	imglen;		// length of image
+char	*data;		// image data
+
+static void display_help (int error)
+{
+	printf("Usage: %s [OPTION]... INPUTFILE\n"
+	       "Dump the contents of a binary JFFS2 image.\n\n"
+	       " -h, --help                   display this help and exit\n"
+	       " -V, --version                display version information and exit\n"
+	       " -b, --bigendian              image is big endian\n"
+	       " -l, --littleendian           image is little endian\n"
+	       " -c, --content                dump image contents\n"
+	       " -e, --endianconvert=FNAME    convert image endianness, output to file fname\n"
+	       " -r, --recalccrc              recalc name and data crc on endian conversion\n"
+	       " -d, --datsize=LEN            size of data chunks, when oob data in binary image (NAND only)\n"
+	       " -o, --oobsize=LEN            size of oob data chunk in binary image (NAND only)\n"
+	       " -v, --verbose                verbose output\n",
+	       PROGRAM_NAME);
+	exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static void display_version (void)
+{
+	common_print_version();
+	printf("Copyright (C) 2003 Thomas Gleixner \n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(0);
+}
+
+// Option variables
+
+int 	verbose;		// verbose output
+char 	*img;			// filename of image
+int	dumpcontent;		// dump image content
+int	target_endian = __BYTE_ORDER;	// image endianess
+int	convertendian;		// convert endianness
+int	recalccrc;		// recalc name and data crc's on endian conversion
+char	cnvfile[256];		// filename for conversion output
+int	datsize;		// Size of data chunks, when oob data is inside the binary image
+int	oobsize;		// Size of oob chunks, when oob data is inside the binary image
+
+static void process_options (int argc, char *argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "blce:rd:o:vVh";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 'h'},
+			{"version", no_argument, 0, 'V'},
+			{"bigendian", no_argument, 0, 'b'},
+			{"littleendian", no_argument, 0, 'l'},
+			{"content", no_argument, 0, 'c'},
+			{"endianconvert", required_argument, 0, 'e'},
+			{"datsize", required_argument, 0, 'd'},
+			{"oobsize", required_argument, 0, 'o'},
+			{"recalccrc", required_argument, 0, 'r'},
+			{"verbose", no_argument, 0, 'v'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 'h':
+				display_help(0);
+				break;
+			case 'V':
+				display_version();
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'c':
+				dumpcontent = 1;
+				break;
+			case 'd':
+				datsize = atoi(optarg);
+				break;
+			case 'o':
+				oobsize = atoi(optarg);
+				break;
+			case 'e':
+				convertendian = 1;
+				strncpy (cnvfile, optarg, sizeof(cnvfile) - 1);
+				cnvfile[sizeof(cnvfile) - 1] = '\0';
+				break;
+			case 'r':
+				recalccrc = 1;
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help (error);
+
+	img = argv[optind];
+}
+
+
+/*
+ *	Dump image contents
+ */
+static void do_dumpcontent (void)
+{
+	char			*p = data, *p_free_begin;
+	union jffs2_node_union 	*node;
+	int			empty = 0, dirty = 0;
+	char			name[256];
+	uint32_t		crc;
+	uint16_t		type;
+	int			bitchbitmask = 0;
+	int			obsolete;
+
+	p_free_begin = NULL;
+	while ( p < (data + imglen)) {
+		node = (union jffs2_node_union*) p;
+
+		/* Skip empty space */
+		if (!p_free_begin)
+			p_free_begin = p;
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			empty += 4;
+			continue;
+		}
+
+		if (p != p_free_begin)
+			printf("Empty space found from 0x%08zx to 0x%08zx\n", p_free_begin-data, p-data);
+		p_free_begin = NULL;
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+			p += 4;
+			dirty += 4;
+			continue;
+		}
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else
+			obsolete = 0;
+		/* Set accurate for CRC check */
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			dirty += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+				printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					dirty += PAD(je32_to_cpu (node->i.totlen));;
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					dirty += PAD(je32_to_cpu (node->i.totlen));;
+					continue;
+				}
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+				printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+						node->d.nsize, name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					dirty += PAD(je32_to_cpu (node->d.totlen));;
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					printf ("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					dirty += PAD(je32_to_cpu (node->d.totlen));;
+					continue;
+				}
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				memcpy(name, node->x.data, node->x.name_len);
+				name[node->x.name_len] = '\x00';
+				printf ("%8s Xattr      node at 0x%08zx, totlen 0x%08x, xid   %5d, version %5d, name_len   %3d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - data,
+						je32_to_cpu (node->x.totlen),
+						je32_to_cpu (node->x.xid),
+						je32_to_cpu (node->x.version),
+						node->x.name_len,
+						name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_xattr) - sizeof (node->x.node_crc));
+				if (crc != je32_to_cpu (node->x.node_crc)) {
+					printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.node_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					dirty += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1);
+				if (crc != je32_to_cpu (node->x.data_crc)) {
+					printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->x.data_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					dirty += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				printf ("%8s Xref       node at 0x%08zx, totlen 0x%08x, xid   %5d, xseqno  %5d, #ino  %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - data,
+						je32_to_cpu (node->r.totlen),
+						je32_to_cpu (node->r.xid),
+						je32_to_cpu (node->r.xseqno),
+						je32_to_cpu (node->r.ino));
+				p += PAD(je32_to_cpu (node->r.totlen));
+				break;
+
+			case JFFS2_NODETYPE_SUMMARY: {
+
+											 int i;
+											 struct jffs2_sum_marker * sm;
+
+											 printf("%8s Inode Sum  node at 0x%08zx, totlen 0x%08x, sum_num  %5d, cleanmarker size %5d\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data,
+													 je32_to_cpu (node->s.totlen),
+													 je32_to_cpu (node->s.sum_num),
+													 je32_to_cpu (node->s.cln_mkr));
+
+											 crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
+											 if (crc != je32_to_cpu (node->s.node_crc)) {
+												 printf ("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
+												 p += PAD(je32_to_cpu (node->s.totlen));
+												 dirty += PAD(je32_to_cpu (node->s.totlen));;
+												 continue;
+											 }
+
+											 crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_summary),  je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary));
+											 if (crc != je32_to_cpu(node->s.sum_crc)) {
+												 printf ("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
+												 p += PAD(je32_to_cpu (node->s.totlen));
+												 dirty += PAD(je32_to_cpu (node->s.totlen));;
+												 continue;
+											 }
+
+											 if (verbose) {
+												 void *sp;
+												 sp = (p + sizeof(struct jffs2_raw_summary));
+
+												 for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
+
+													 switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+														 case JFFS2_NODETYPE_INODE : {
+
+																						 struct jffs2_sum_inode_flash *spi;
+																						 spi = sp;
+
+																						 printf ("%14s #ino  %5d,  version %5d, offset 0x%08x, totlen 0x%08x\n",
+																								 "",
+																								 je32_to_cpu (spi->inode),
+																								 je32_to_cpu (spi->version),
+																								 je32_to_cpu (spi->offset),
+																								 je32_to_cpu (spi->totlen));
+
+																						 sp += JFFS2_SUMMARY_INODE_SIZE;
+																						 break;
+																					 }
+
+														 case JFFS2_NODETYPE_DIRENT : {
+
+																						  char name[255];
+																						  struct jffs2_sum_dirent_flash *spd;
+																						  spd = sp;
+
+																						  memcpy(name,spd->name,spd->nsize);
+																						  name [spd->nsize] = 0x0;
+
+																						  printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino  %5d,  version %5d, #ino  %8d, nsize %8d, name %s \n",
+																								  "",
+																								  je32_to_cpu (spd->offset),
+																								  je32_to_cpu (spd->totlen),
+																								  je32_to_cpu (spd->pino),
+																								  je32_to_cpu (spd->version),
+																								  je32_to_cpu (spd->ino),
+																								  spd->nsize,
+																								  name);
+
+																						  sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+																						  break;
+																					  }
+
+														 case JFFS2_NODETYPE_XATTR : {
+																						  struct jffs2_sum_xattr_flash *spx;
+																						  spx = sp;
+																						  printf ("%14s Xattr  offset 0x%08x, totlen 0x%08x, version %5d, #xid %8d\n",
+																								  "",
+																								  je32_to_cpu (spx->offset),
+																								  je32_to_cpu (spx->totlen),
+																								  je32_to_cpu (spx->version),
+																								  je32_to_cpu (spx->xid));
+																						  sp += JFFS2_SUMMARY_XATTR_SIZE;
+																						  break;
+																					  }
+
+														 case JFFS2_NODETYPE_XREF : {
+																						  struct jffs2_sum_xref_flash *spr;
+																						  spr = sp;
+																						  printf ("%14s Xref   offset 0x%08x\n",
+																								  "",
+																								  je32_to_cpu (spr->offset));
+																						  sp += JFFS2_SUMMARY_XREF_SIZE;
+																						  break;
+																					  }
+
+														 default :
+																					  printf("Unknown summary node!\n");
+																					  break;
+													 }
+												 }
+
+												 sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
+
+												 printf("%14s Sum Node Offset  0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
+														 "",
+														 je32_to_cpu(sm->offset),
+														 je32_to_cpu(sm->magic),
+														 je32_to_cpu(node->s.padded));
+											 }
+
+											 p += PAD(je32_to_cpu (node->s.totlen));
+											 break;
+										 }
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+										 if (verbose) {
+											 printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 break;
+
+			case JFFS2_NODETYPE_PADDING:
+										 if (verbose) {
+											 printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 break;
+
+			case 0xffff:
+										 p += 4;
+										 empty += 4;
+										 break;
+
+			default:
+										 if (verbose) {
+											 printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+													 obsolete ? "Obsolete" : "",
+													 p - data, je32_to_cpu (node->u.totlen));
+										 }
+										 p += PAD(je32_to_cpu (node->u.totlen));
+										 dirty += PAD(je32_to_cpu (node->u.totlen));
+
+		}
+	}
+
+	if (verbose)
+		printf ("Empty space: %d, dirty space: %d\n", empty, dirty);
+}
+
+/*
+ *	Convert endianess
+ */
+static void do_endianconvert (void)
+{
+	char			*p = data;
+	union jffs2_node_union 	*node, newnode;
+	int			fd, len;
+	jint32_t		mode;
+	uint32_t		crc;
+
+	fd = open (cnvfile, O_WRONLY | O_CREAT, 0644);
+	if (fd < 0) {
+		fprintf (stderr, "Cannot open / create file: %s\n", cnvfile);
+		return;
+	}
+
+	while ( p < (data + imglen)) {
+		node = (union jffs2_node_union*) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			write_nocheck (fd, p, 4);
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+			newnode.u.magic = cnv_e16 (node->u.magic);
+			newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+			write_nocheck (fd, &newnode, 4);
+			p += 4;
+			continue;
+		}
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+
+				newnode.i.magic = cnv_e16 (node->i.magic);
+				newnode.i.nodetype = cnv_e16 (node->i.nodetype);
+				newnode.i.totlen = cnv_e32 (node->i.totlen);
+				newnode.i.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.i.ino = cnv_e32 (node->i.ino);
+				newnode.i.version = cnv_e32 (node->i.version);
+				mode.v32 = node->i.mode.m;
+				mode = cnv_e32 (mode);
+				newnode.i.mode.m = mode.v32;
+				newnode.i.uid = cnv_e16 (node->i.uid);
+				newnode.i.gid = cnv_e16 (node->i.gid);
+				newnode.i.isize = cnv_e32 (node->i.isize);
+				newnode.i.atime = cnv_e32 (node->i.atime);
+				newnode.i.mtime = cnv_e32 (node->i.mtime);
+				newnode.i.ctime = cnv_e32 (node->i.ctime);
+				newnode.i.offset = cnv_e32 (node->i.offset);
+				newnode.i.csize = cnv_e32 (node->i.csize);
+				newnode.i.dsize = cnv_e32 (node->i.dsize);
+				newnode.i.compr = node->i.compr;
+				newnode.i.usercompr = node->i.usercompr;
+				newnode.i.flags = cnv_e16 (node->i.flags);
+				if (recalccrc) {
+					len = je32_to_cpu(node->i.csize);
+					newnode.i.data_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), len));
+				} else
+					newnode.i.data_crc = cnv_e32 (node->i.data_crc);
+
+				newnode.i.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8));
+
+				write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_inode));
+				write_nocheck (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) -  sizeof (struct jffs2_raw_inode)));
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				newnode.d.magic = cnv_e16 (node->d.magic);
+				newnode.d.nodetype = cnv_e16 (node->d.nodetype);
+				newnode.d.totlen = cnv_e32 (node->d.totlen);
+				newnode.d.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.d.pino = cnv_e32 (node->d.pino);
+				newnode.d.version = cnv_e32 (node->d.version);
+				newnode.d.ino = cnv_e32 (node->d.ino);
+				newnode.d.mctime = cnv_e32 (node->d.mctime);
+				newnode.d.nsize = node->d.nsize;
+				newnode.d.type = node->d.type;
+				newnode.d.unused[0] = node->d.unused[0];
+				newnode.d.unused[1] = node->d.unused[1];
+				newnode.d.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
+				if (recalccrc)
+					newnode.d.name_crc = cpu_to_e32 ( mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize));
+				else
+					newnode.d.name_crc = cnv_e32 (node->d.name_crc);
+
+				write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_dirent));
+				write_nocheck (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_dirent)));
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				newnode.x.magic = cnv_e16 (node->x.magic);
+				newnode.x.nodetype = cnv_e16 (node->x.nodetype);
+				newnode.x.totlen = cnv_e32 (node->x.totlen);
+				newnode.x.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+				newnode.x.xid = cnv_e32 (node->x.xid);
+				newnode.x.version = cnv_e32 (node->x.version);
+				newnode.x.xprefix = node->x.xprefix;
+				newnode.x.name_len = node->x.name_len;
+				newnode.x.value_len = cnv_e16 (node->x.value_len);
+				if (recalccrc)
+					newnode.x.data_crc = cpu_to_e32 (mtd_crc32 (0, p + sizeof (struct jffs2_raw_xattr), node->x.name_len + je16_to_cpu (node->x.value_len) + 1));
+				else
+					newnode.x.data_crc = cnv_e32 (node->x.data_crc);
+				newnode.x.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xattr) - sizeof (newnode.x.node_crc)));
+
+				write_nocheck (fd, &newnode, sizeof (struct jffs2_raw_xattr));
+				write_nocheck (fd, p + sizeof (struct jffs2_raw_xattr), PAD (je32_to_cpu (node->d.totlen) -  sizeof (struct jffs2_raw_xattr)));
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				newnode.r.magic = cnv_e16 (node->r.magic);
+				newnode.r.nodetype = cnv_e16 (node->r.nodetype);
+				newnode.r.totlen = cnv_e32 (node->r.totlen);
+				newnode.r.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - sizeof (newnode.r.hdr_crc)));
+				newnode.r.ino = cnv_e32 (node->r.ino);
+				newnode.r.xid = cnv_e32 (node->r.xid);
+				newnode.r.xseqno = cnv_e32 (node->r.xseqno);
+				newnode.r.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_xref) - sizeof (newnode.r.node_crc)));
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+			case JFFS2_NODETYPE_PADDING:
+				newnode.u.magic = cnv_e16 (node->u.magic);
+				newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+				newnode.u.totlen = cnv_e32 (node->u.totlen);
+				newnode.u.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+
+				write_nocheck (fd, &newnode, sizeof (struct jffs2_unknown_node));
+				len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node));
+				if (len > 0)
+					write_nocheck (fd, p + sizeof (struct jffs2_unknown_node), len);
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_SUMMARY : {
+											  struct jffs2_sum_marker *sm_ptr;
+											  int i,sum_len;
+											  int counter = 0;
+
+											  newnode.s.magic = cnv_e16 (node->s.magic);
+											  newnode.s.nodetype = cnv_e16 (node->s.nodetype);
+											  newnode.s.totlen = cnv_e32 (node->s.totlen);
+											  newnode.s.hdr_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+											  newnode.s.sum_num = cnv_e32 (node->s.sum_num);
+											  newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
+											  newnode.s.padded = cnv_e32 (node->s.padded);
+
+											  newnode.s.node_crc = cpu_to_e32 (mtd_crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8));
+
+											  // summary header
+											  p += sizeof (struct jffs2_raw_summary);
+
+											  // summary data
+											  sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker);
+
+											  for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
+												  union jffs2_sum_flash *fl_ptr;
+
+												  fl_ptr = (union jffs2_sum_flash *) p;
+
+												  switch (je16_to_cpu (fl_ptr->u.nodetype)) {
+													  case JFFS2_NODETYPE_INODE:
+
+														  fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
+														  fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
+														  fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
+														  fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
+														  fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
+														  p += sizeof (struct jffs2_sum_inode_flash);
+														  counter += sizeof (struct jffs2_sum_inode_flash);
+														  break;
+
+													  case JFFS2_NODETYPE_DIRENT:
+														  fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
+														  fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
+														  fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
+														  fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
+														  fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
+														  fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
+														  p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+														  counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+														  break;
+
+													  case JFFS2_NODETYPE_XATTR:
+														  fl_ptr->x.nodetype = cnv_e16 (fl_ptr->x.nodetype);
+														  fl_ptr->x.xid = cnv_e32 (fl_ptr->x.xid);
+														  fl_ptr->x.version = cnv_e32 (fl_ptr->x.version);
+														  fl_ptr->x.offset = cnv_e32 (fl_ptr->x.offset);
+														  fl_ptr->x.totlen = cnv_e32 (fl_ptr->x.totlen);
+														  p += sizeof (struct jffs2_sum_xattr_flash);
+														  counter += sizeof (struct jffs2_sum_xattr_flash);
+														  break;
+
+													  case JFFS2_NODETYPE_XREF:
+														  fl_ptr->r.nodetype = cnv_e16 (fl_ptr->r.nodetype);
+														  fl_ptr->r.offset = cnv_e32 (fl_ptr->r.offset);
+														  p += sizeof (struct jffs2_sum_xref_flash);
+														  counter += sizeof (struct jffs2_sum_xref_flash);
+														  break;
+
+													  default :
+														  printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
+														  exit(EXIT_FAILURE);
+														  break;
+												  }
+
+											  }
+
+											  //pad
+											  p += sum_len - counter;
+
+											  // summary marker
+											  sm_ptr = (struct jffs2_sum_marker *) p;
+											  sm_ptr->offset = cnv_e32 (sm_ptr->offset);
+											  sm_ptr->magic = cnv_e32 (sm_ptr->magic);
+											  p += sizeof (struct jffs2_sum_marker);
+
+											  // generate new crc on sum data
+											  newnode.s.sum_crc = cpu_to_e32 ( mtd_crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary),
+														  je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary)));
+
+											  // write out new node header
+											  write_nocheck(fd, &newnode, sizeof (struct jffs2_raw_summary));
+											  // write out new summary data
+											  write_nocheck(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
+
+											  break;
+										  }
+
+			case 0xffff:
+										  write_nocheck (fd, p, 4);
+										  p += 4;
+										  break;
+
+			default:
+										  printf ("Unknown node type: 0x%04x at 0x%08zx, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen));
+										  p += PAD(je32_to_cpu (node->u.totlen));
+
+		}
+	}
+
+	close (fd);
+
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+	int fd;
+
+	process_options(argc, argv);
+
+	/* Open the input file */
+	if ((fd = open(img, O_RDONLY)) == -1) {
+		perror("open input file");
+		exit(EXIT_FAILURE);
+	}
+
+	// get image length
+	imglen = lseek(fd, 0, SEEK_END);
+	lseek (fd, 0, SEEK_SET);
+
+	data = malloc (imglen);
+	if (!data) {
+		perror("out of memory");
+		close (fd);
+		exit(EXIT_FAILURE);
+	}
+
+	if (datsize && oobsize) {
+		int  idx = 0;
+		long len = imglen;
+		uint8_t oob[oobsize];
+		printf ("Peeling data out of combined data/oob image\n");
+		while (len) {
+			// read image data
+			read_nocheck (fd, &data[idx], datsize);
+			read_nocheck (fd, oob, oobsize);
+			idx += datsize;
+			imglen -= oobsize;
+			len -= datsize + oobsize;
+		}
+
+	} else {
+		// read image data
+		read_nocheck (fd, data, imglen);
+	}
+	// Close the input file
+	close(fd);
+
+	if (dumpcontent)
+		do_dumpcontent ();
+
+	if (convertendian)
+		do_endianconvert ();
+
+	// free memory
+	free (data);
+
+	// Return happy
+	exit (EXIT_SUCCESS);
+}

+ 914 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/jffs2reader.c

@@ -0,0 +1,914 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * jffs2reader v0.0.18 A jffs2 image reader
+ *
+ * Copyright (c) 2001 Jari Kirma <Jari.Kirma@hut.fi>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the author 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.
+ *
+ *
+ *********
+ *  This code was altered September 2001
+ *  Changes are Copyright (c) Erik Andersen <andersen@codepoet.org>
+ *
+ * In compliance with (2) above, this is hereby marked as an altered
+ * version of this software.  It has been altered as follows:
+ *      *) Listing a directory now mimics the behavior of 'ls -l'
+ *      *) Support for recursive listing has been added
+ *      *) Without options, does a recursive 'ls' on the whole filesystem
+ *      *) option parsing now uses getopt()
+ *      *) Now uses printf, and error messages go to stderr.
+ *      *) The copyright notice has been cleaned up and reformatted
+ *      *) The code has been reformatted
+ *      *) Several twisty code paths have been fixed so I can understand them.
+ *  -Erik, 1 September 2001
+ *
+ *      *) Made it show major/minor numbers for device nodes
+ *      *) Made it show symlink targets
+ *  -Erik, 13 September 2001
+ */
+
+
+/*
+TODO:
+
+- Add CRC checking code to places marked with XXX.
+- Add support for other node compression types.
+
+- Test with real life images.
+- Maybe port into bootloader.
+ */
+
+/*
+BUGS:
+
+- Doesn't check CRC checksums.
+ */
+
+#define PROGRAM_NAME "jffs2reader"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <zlib.h>
+
+#include "mtd/jffs2-user.h"
+#include "common.h"
+
+static struct option long_opt[] = {
+	{"help", 0, NULL, 'h'},
+	{"version", 0, NULL, 'V'},
+	{NULL, 0, NULL, 0},
+};
+
+static const char *short_opt = "rd:f:tVh";
+
+#define SCRATCH_SIZE (5*1024*1024)
+
+/* macro to avoid "lvalue required as left operand of assignment" error */
+#define ADD_BYTES(p, n)		((p) = (typeof(p))((char *)(p) + (n)))
+
+#define DIRENT_INO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->ino) : 0)
+#define DIRENT_PINO(dirent) ((dirent) !=NULL ? je32_to_cpu((dirent)->pino) : 0)
+
+struct dir {
+	struct dir *next;
+	uint8_t type;
+	uint8_t nsize;
+	uint32_t ino;
+	char name[256];
+};
+
+int target_endian = __BYTE_ORDER;
+
+static struct jffs2_raw_inode *find_raw_inode(char *, size_t, uint32_t);
+
+static void lsdir(char *, size_t, const char *, int, int);
+
+/* writes file node into buffer, to the proper position. */
+/* reading all valid nodes in version order reconstructs the file. */
+
+/*
+   b       - buffer
+   bsize   - buffer size
+   rsize   - result size
+   n       - node
+ */
+
+static void putblock(char *b, size_t bsize, size_t * rsize,
+		struct jffs2_raw_inode *n)
+{
+	uLongf dlen = je32_to_cpu(n->dsize);
+
+	if (je32_to_cpu(n->isize) > bsize || (je32_to_cpu(n->offset) + dlen) > bsize)
+		errmsg_die("File does not fit into buffer!");
+
+	if (*rsize < je32_to_cpu(n->isize))
+		bzero(b + *rsize, je32_to_cpu(n->isize) - *rsize);
+
+	switch (n->compr) {
+		case JFFS2_COMPR_ZLIB:
+			uncompress((Bytef *) b + je32_to_cpu(n->offset), &dlen,
+					(Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
+					(uLongf) je32_to_cpu(n->csize));
+			break;
+
+		case JFFS2_COMPR_NONE:
+			memcpy(b + je32_to_cpu(n->offset),
+					((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
+			break;
+
+		case JFFS2_COMPR_ZERO:
+			bzero(b + je32_to_cpu(n->offset), dlen);
+			break;
+
+			/* [DYN]RUBIN support required! */
+
+		default:
+			errmsg_die("Unsupported compression method!");
+	}
+
+	*rsize = je32_to_cpu(n->isize);
+}
+
+/* adds/removes directory node into dir struct. */
+/* reading all valid nodes in version order reconstructs the directory. */
+
+/*
+   dd      - directory struct being processed
+   n       - node
+
+   return value: directory struct value replacing dd
+ */
+
+static struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n)
+{
+	struct dir *o, *d, *p;
+
+	o = dd;
+
+	if (je32_to_cpu(n->ino)) {
+		if (dd == NULL) {
+			d = xmalloc(sizeof(struct dir));
+			d->type = n->type;
+			memcpy(d->name, n->name, n->nsize);
+			d->nsize = n->nsize;
+			d->ino = je32_to_cpu(n->ino);
+			d->next = NULL;
+
+			return d;
+		}
+
+		while (1) {
+			if (n->nsize == dd->nsize &&
+					!memcmp(n->name, dd->name, n->nsize)) {
+				dd->type = n->type;
+				dd->ino = je32_to_cpu(n->ino);
+
+				return o;
+			}
+
+			if (dd->next == NULL) {
+				dd->next = xmalloc(sizeof(struct dir));
+				dd->next->type = n->type;
+				memcpy(dd->next->name, n->name, n->nsize);
+				dd->next->nsize = n->nsize;
+				dd->next->ino = je32_to_cpu(n->ino);
+				dd->next->next = NULL;
+
+				return o;
+			}
+
+			dd = dd->next;
+		}
+	} else {
+		if (dd == NULL)
+			return NULL;
+
+		if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) {
+			d = dd->next;
+			free(dd);
+			return d;
+		}
+
+		while (1) {
+			p = dd;
+			dd = dd->next;
+
+			if (dd == NULL)
+				return o;
+
+			if (n->nsize == dd->nsize &&
+					!memcmp(n->name, dd->name, n->nsize)) {
+				p->next = dd->next;
+				free(dd);
+
+				return o;
+			}
+		}
+	}
+}
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+	0, 0, S_ISUID,
+	0, 0, S_ISGID,
+	0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+	S_IRUSR, S_IWUSR, S_IXUSR,
+	S_IRGRP, S_IWGRP, S_IXGRP,
+	S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[] = "rwxrwxrwx";
+static const char MODE0[] = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+static const char *mode_string(int mode)
+{
+	static char buf[12];
+
+	int i;
+
+	buf[0] = TYPECHAR(mode);
+	for (i = 0; i < 9; i++) {
+		if (mode & SBIT[i])
+			buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+		else
+			buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+	}
+	return buf;
+}
+
+/* prints contents of directory structure */
+
+/*
+   d       - dir struct
+ */
+
+static void printdir(char *o, size_t size, struct dir *d, const char *path,
+					 int recurse, int want_ctime)
+{
+	char m;
+	char *filetime;
+	time_t age;
+	struct jffs2_raw_inode *ri;
+	jint32_t mode;
+
+	if (!path)
+		return;
+	if (strlen(path) == 1 && *path == '/')
+		path++;
+
+	while (d != NULL) {
+		switch (d->type) {
+			case DT_REG:
+				m = ' ';
+				break;
+
+			case DT_FIFO:
+				m = '|';
+				break;
+
+			case DT_CHR:
+				m = ' ';
+				break;
+
+			case DT_BLK:
+				m = ' ';
+				break;
+
+			case DT_DIR:
+				m = '/';
+				break;
+
+			case DT_LNK:
+				m = ' ';
+				break;
+
+			case DT_SOCK:
+				m = '=';
+				break;
+
+			default:
+				m = '?';
+		}
+		ri = find_raw_inode(o, size, d->ino);
+		if (!ri) {
+			warnmsg("bug: raw_inode missing!");
+			d = d->next;
+			continue;
+		}
+
+		filetime = ctime((const time_t *) &(ri->ctime));
+		age = time(NULL) - je32_to_cpu(ri->ctime);
+		mode.v32 = ri->mode.m;
+		printf("%s %-4d %-8d %-8d ", mode_string(je32_to_cpu(mode)),
+				1, je16_to_cpu(ri->uid), je16_to_cpu(ri->gid));
+		if ( d->type==DT_BLK || d->type==DT_CHR ) {
+			dev_t rdev;
+			size_t devsize;
+			putblock((char*)&rdev, sizeof(rdev), &devsize, ri);
+			printf("%4d, %3d ", major(rdev), minor(rdev));
+		} else {
+			printf("%9ld ", (long)je32_to_cpu(ri->dsize));
+		}
+		d->name[d->nsize]='\0';
+		if (want_ctime) {
+			if (age < 3600L * 24 * 365 / 2 && age > -15 * 60)
+				/* hh:mm if less than 6 months old */
+				printf("%6.6s %5.5s ", filetime + 4, filetime + 11);
+			else
+				printf("%6.6s %4.4s ", filetime + 4, filetime + 20);
+		}
+		printf("%s/%s%c", path, d->name, m);
+		if (d->type == DT_LNK) {
+			char symbuf[1024];
+			size_t symsize;
+			putblock(symbuf, sizeof(symbuf), &symsize, ri);
+			symbuf[symsize] = 0;
+			printf(" -> %s", symbuf);
+		}
+		printf("\n");
+
+		if (d->type == DT_DIR && recurse) {
+			char *tmp;
+			tmp = xmalloc(BUFSIZ);
+			sprintf(tmp, "%s/%s", path, d->name);
+			lsdir(o, size, tmp, recurse, want_ctime);	/* Go recursive */
+			free(tmp);
+		}
+
+		d = d->next;
+	}
+}
+
+/* frees memory used by directory structure */
+
+/*
+   d       - dir struct
+ */
+
+static void freedir(struct dir *d)
+{
+	struct dir *t;
+
+	while (d != NULL) {
+		t = d->next;
+		free(d);
+		d = t;
+	}
+}
+
+/* collects directory/file nodes in version order. */
+
+/*
+   f       - file flag.
+   if zero, collect file, compare ino to inode
+   otherwise, collect directory, compare ino to parent inode
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - inode to compare against. see f.
+
+   return value: a jffs2_raw_inode that corresponds the the specified
+   inode, or NULL
+ */
+
+static struct jffs2_raw_inode *find_raw_inode(char *o, size_t size,
+											  uint32_t ino)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+	union jffs2_node_union *lr;	/* last block position */
+	union jffs2_node_union *mp = NULL;	/* minimum position */
+
+	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+	vmin = 0;					/* next to read */
+	vmax = ~((uint32_t) 0);		/* last to read */
+	vmint = ~((uint32_t) 0);
+	vmaxt = 0;					/* found maximum */
+	vcur = 0;					/* XXX what is smallest version number used? */
+	/* too low version number can easily result excess log rereading */
+
+	n = (union jffs2_node_union *) o;
+	lr = n;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_INODE &&
+				je32_to_cpu(n->i.ino) == ino && (v = je32_to_cpu(n->i.version)) > vcur) {
+				/* XXX crc check */
+
+				if (vmaxt < v)
+					vmaxt = v;
+				if (vmint > v) {
+					vmint = v;
+					mp = n;
+				}
+
+				if (v == (vcur + 1))
+					return (&(n->i));
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
+
+		if (lr == n) {			/* whole loop since last read */
+			vmax = vmaxt;
+			vmin = vmint;
+			vmint = ~((uint32_t) 0);
+
+			if (vcur < vmax && vcur < vmin)
+				return (&(mp->i));
+		}
+	} while (vcur < vmax);
+
+	return NULL;
+}
+
+/* collects dir struct for selected inode */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   pino    - inode of the specified directory
+   d       - input directory structure
+
+   return value: result directory structure, replaces d.
+ */
+
+static struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+	union jffs2_node_union *lr;	/* last block position */
+	union jffs2_node_union *mp = NULL;	/* minimum position */
+
+	uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+	vmin = 0;					/* next to read */
+	vmax = ~((uint32_t) 0);		/* last to read */
+	vmint = ~((uint32_t) 0);
+	vmaxt = 0;					/* found maximum */
+	vcur = 0;					/* XXX what is smallest version number used? */
+	/* too low version number can easily result excess log rereading */
+
+	n = (union jffs2_node_union *) o;
+	lr = n;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
+				je32_to_cpu(n->d.pino) == ino && (v = je32_to_cpu(n->d.version)) > vcur) {
+				/* XXX crc check */
+
+				if (vmaxt < v)
+					vmaxt = v;
+				if (vmint > v) {
+					vmint = v;
+					mp = n;
+				}
+
+				if (v == (vcur + 1)) {
+					d = putdir(d, &(n->d));
+
+					lr = n;
+					vcur++;
+					vmint = ~((uint32_t) 0);
+				}
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			n = (union jffs2_node_union *) o;	/* we're at the end, rewind to the beginning */
+
+		if (lr == n) {			/* whole loop since last read */
+			vmax = vmaxt;
+			vmin = vmint;
+			vmint = ~((uint32_t) 0);
+
+			if (vcur < vmax && vcur < vmin) {
+				d = putdir(d, &(mp->d));
+
+				lr = n =
+					(union jffs2_node_union *) (((char *) mp) +
+							((je32_to_cpu(mp->u.totlen) + 3) & ~3));
+
+				vcur = vmin;
+			}
+		}
+	} while (vcur < vmax);
+
+	return d;
+}
+
+
+
+/* resolve dirent based on criteria */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - if zero, ignore,
+   otherwise compare against dirent inode
+   pino    - if zero, ingore,
+   otherwise compare against parent inode
+   and use name and nsize as extra criteria
+   name    - name of wanted dirent, used if pino!=0
+   nsize   - length of name of wanted dirent, used if pino!=0
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+static struct jffs2_raw_dirent *resolvedirent(char *o, size_t size,
+		uint32_t ino, uint32_t pino,
+		char *name, uint8_t nsize)
+{
+	/* aligned! */
+	union jffs2_node_union *n;
+	union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+
+	struct jffs2_raw_dirent *dd = NULL;
+
+	uint32_t vmax, v;
+
+	if (!pino && ino <= 1)
+		return dd;
+
+	vmax = 0;
+
+	n = (union jffs2_node_union *) o;
+
+	do {
+		while (n < e && je16_to_cpu(n->u.magic) != JFFS2_MAGIC_BITMASK)
+			ADD_BYTES(n, 4);
+
+		if (n < e && je16_to_cpu(n->u.magic) == JFFS2_MAGIC_BITMASK) {
+			if (je16_to_cpu(n->u.nodetype) == JFFS2_NODETYPE_DIRENT &&
+					(!ino || je32_to_cpu(n->d.ino) == ino) &&
+					(v = je32_to_cpu(n->d.version)) > vmax &&
+					(!pino || (je32_to_cpu(n->d.pino) == pino &&
+							   nsize == n->d.nsize &&
+							   !memcmp(name, n->d.name, nsize)))) {
+				/* XXX crc check */
+
+				if (vmax < v) {
+					vmax = v;
+					dd = &(n->d);
+				}
+			}
+
+			ADD_BYTES(n, ((je32_to_cpu(n->u.totlen) + 3) & ~3));
+		} else
+			return dd;
+	} while (1);
+}
+
+/* resolve name under certain parent inode to dirent */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   pino    - requested parent inode
+   name    - name of wanted dirent
+   nsize   - length of name of wanted dirent
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+static struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino,
+		char *name, uint8_t nsize)
+{
+	return resolvedirent(o, size, 0, pino, name, nsize);
+}
+
+/* resolve inode to dirent */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - compare against dirent inode
+
+   return value: pointer to relevant dirent structure in
+   filesystem image or NULL
+ */
+
+static struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino)
+{
+	return resolvedirent(o, size, ino, 0, NULL, 0);
+}
+
+/* resolve slash-style path into dirent and inode.
+   slash as first byte marks absolute path (root=inode 1).
+   . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - root inode, used if path is relative
+   p       - path to be resolved
+   inos    - result inode, zero if failure
+   recc    - recursion count, to detect symlink loops
+
+   return value: pointer to dirent struct in file system image.
+   note that root directory doesn't have dirent struct
+   (return value is NULL), but it has inode (*inos=1)
+ */
+
+static struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino,
+		const char *p, uint32_t * inos, int recc)
+{
+	struct jffs2_raw_dirent *dir = NULL;
+
+	int d = 1;
+	uint32_t tino;
+
+	char *next;
+
+	char *path, *pp;
+
+	char symbuf[1024];
+	size_t symsize;
+
+	if (recc > 16) {
+		/* probably symlink loop */
+		*inos = 0;
+		return NULL;
+	}
+
+	pp = path = xstrdup(p);
+
+	if (*path == '/') {
+		path++;
+		ino = 1;
+	}
+
+	if (ino > 1) {
+		dir = resolveinode(o, size, ino);
+
+		ino = DIRENT_INO(dir);
+	}
+
+	next = path - 1;
+
+	while (ino && next != NULL && next[1] != 0 && d) {
+		path = next + 1;
+		next = strchr(path, '/');
+
+		if (next != NULL)
+			*next = 0;
+
+		if (*path == '.' && path[1] == 0)
+			continue;
+		if (*path == '.' && path[1] == '.' && path[2] == 0) {
+			if (DIRENT_PINO(dir) == 1) {
+				ino = 1;
+				dir = NULL;
+			} else {
+				dir = resolveinode(o, size, DIRENT_PINO(dir));
+				ino = DIRENT_INO(dir);
+			}
+
+			continue;
+		}
+
+		dir = resolvename(o, size, ino, path, (uint8_t) strlen(path));
+
+		if (DIRENT_INO(dir) == 0 ||
+				(next != NULL &&
+				 !(dir->type == DT_DIR || dir->type == DT_LNK))) {
+			free(pp);
+
+			*inos = 0;
+
+			return NULL;
+		}
+
+		if (dir->type == DT_LNK) {
+			struct jffs2_raw_inode *ri;
+			ri = find_raw_inode(o, size, DIRENT_INO(dir));
+			putblock(symbuf, sizeof(symbuf), &symsize, ri);
+			symbuf[symsize] = 0;
+
+			tino = ino;
+			ino = 0;
+
+			dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc);
+
+			if (dir != NULL && next != NULL &&
+					!(dir->type == DT_DIR || dir->type == DT_LNK)) {
+				free(pp);
+
+				*inos = 0;
+				return NULL;
+			}
+		}
+		if (dir != NULL)
+			ino = DIRENT_INO(dir);
+	}
+
+	free(pp);
+
+	*inos = ino;
+
+	return dir;
+}
+
+/* resolve slash-style path into dirent and inode.
+   slash as first byte marks absolute path (root=inode 1).
+   . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   ino     - root inode, used if path is relative
+   p       - path to be resolved
+   inos    - result inode, zero if failure
+
+   return value: pointer to dirent struct in file system image.
+   note that root directory doesn't have dirent struct
+   (return value is NULL), but it has inode (*inos=1)
+ */
+
+static struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino,
+		const char *p, uint32_t * inos)
+{
+	return resolvepath0(o, size, ino, p, inos, 0);
+}
+
+/* lists files on directory specified by path */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   p       - path to be resolved
+ */
+
+static void lsdir(char *o, size_t size, const char *path, int recurse,
+				  int want_ctime)
+{
+	struct jffs2_raw_dirent *dd;
+	struct dir *d = NULL;
+
+	uint32_t ino;
+
+	dd = resolvepath(o, size, 1, path, &ino);
+
+	if (ino == 0 ||
+			(dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR))
+		errmsg_die("%s: No such file or directory", path);
+
+	d = collectdir(o, size, ino, d);
+	printdir(o, size, d, path, recurse, want_ctime);
+	freedir(d);
+}
+
+/* writes file specified by path to the buffer */
+
+/*
+   o       - filesystem image pointer
+   size    - size of filesystem image
+   p       - path to be resolved
+   b       - file buffer
+   bsize   - file buffer size
+   rsize   - file result size
+ */
+
+static void catfile(char *o, size_t size, char *path, char *b, size_t bsize,
+					size_t * rsize)
+{
+	struct jffs2_raw_dirent *dd;
+	struct jffs2_raw_inode *ri;
+	uint32_t ino;
+
+	dd = resolvepath(o, size, 1, path, &ino);
+
+	if (ino == 0)
+		errmsg_die("%s: No such file or directory", path);
+
+	if (dd == NULL || dd->type != DT_REG)
+		errmsg_die("%s: Not a regular file", path);
+
+	ri = find_raw_inode(o, size, ino);
+	putblock(b, bsize, rsize, ri);
+
+	write_nocheck(1, b, *rsize);
+}
+
+/* usage example */
+
+int main(int argc, char **argv)
+{
+	int fd, opt, c, recurse = 0, want_ctime = 0;
+	struct stat st;
+
+	char *scratch, *dir = NULL, *file = NULL;
+	size_t ssize = 0;
+
+	char *buf;
+
+	while ((opt = getopt_long(argc, argv, short_opt, long_opt, &c)) > 0) {
+		switch (opt) {
+			case 'd':
+				dir = optarg;
+				break;
+			case 'f':
+				file = optarg;
+				break;
+			case 'r':
+				recurse++;
+				break;
+			case 't':
+				want_ctime++;
+				break;
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+			default:
+				fprintf(stderr,
+						"Usage: %s <image> [-d|-f] < path >\n",
+						PROGRAM_NAME);
+				exit(opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
+		}
+	}
+
+	fd = open(argv[optind], O_RDONLY);
+	if (fd == -1)
+		sys_errmsg_die("%s", argv[optind]);
+
+	if (fstat(fd, &st))
+		sys_errmsg_die("%s", argv[optind]);
+
+	buf = xmalloc((size_t) st.st_size);
+
+	if (read(fd, buf, st.st_size) != (ssize_t) st.st_size)
+		sys_errmsg_die("%s", argv[optind]);
+
+	if (dir)
+		lsdir(buf, st.st_size, dir, recurse, want_ctime);
+
+	if (file) {
+		scratch = xmalloc(SCRATCH_SIZE);
+
+		catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
+		free(scratch);
+	}
+
+	if (!dir && !file)
+		lsdir(buf, st.st_size, "/", 1, want_ctime);
+
+
+	free(buf);
+	exit(EXIT_SUCCESS);
+}

+ 268 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/mkfs.jffs2.1

@@ -0,0 +1,268 @@
+.TH MKFS.JFFS2 1
+.SH NAME
+mkfs.jffs2 \- Create a JFFS2 file system image from directory
+.SH SYNOPSIS
+.B mkfs.jffs2
+[
+.B -p,--pad[=SIZE]
+]
+[
+.B -r,-d,--root
+.I directory
+]
+[
+.B -s,--pagesize=SIZE
+]
+[
+.B -e,--eraseblock=SIZE
+]
+[
+.B -c,--cleanmarker=SIZE
+]
+[
+.B -n,--no-cleanmarkers
+]
+[
+.B -o,--output
+.I image.jffs2
+]
+[
+.B -l,--little-endian
+]
+[
+.B -b,--big-endian
+]
+[
+.B -D,--devtable=FILE
+]
+[
+.B -f,--faketime
+]
+[
+.B -q,--squash
+]
+[
+.B -U,--squash-uids
+]
+[
+.B -P,--squash-perms
+]
+[
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -y,--compressor-priority=PRIORITY:NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
+.B -h,--help
+]
+[
+.B -v,--verbose
+]
+[
+.B -V,--version
+]
+[
+.B -i,--incremental
+.I image.jffs2
+]
+
+.SH DESCRIPTION
+The program
+.B mkfs.jffs2
+creates a JFFS2 (Second Journalling Flash File System) file system
+image and writes the resulting image to the file specified by the
+.B -o
+option or by default to the standard output, unless the standard
+output is a terminal device in which case mkfs.jffs2 will abort.
+
+The file system image is created using the files and directories
+contained in the directory specified by the option
+.B -r
+or the present directory, if the
+.B -r
+option is not specified.
+
+Each block of the files to be placed into the file system image
+are compressed using one of the available compressors depending
+on the selected compression mode.
+
+File systems are created with the same endianness as the host,
+unless the
+.B -b
+or
+.B -l
+options are specified.  JFFS2 driver in the 2.4 Linux kernel only
+supported images having the same endianness as the CPU. As of 2.5.48,
+the kernel can be changed with a #define to accept images of the
+non-native endianness. Full bi-endian support in the kernel is not
+planned.
+
+It is unlikely that JFFS2 images are useful except in conjuction
+with the MTD (Memory Technology Device) drivers in the Linux
+kernel, since the JFFS2 file system driver in the kernel requires
+MTD devices.
+.SH OPTIONS
+Options that take SIZE arguments can be specified as either
+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000).
+.TP
+.B -p, --pad[=SIZE]
+Pad output to SIZE bytes with 0xFF.  If SIZE is not specified,
+the output is padded to the end of the final erase block.
+.TP
+.B -r, -d, --root=DIR
+Build file system from directory DIR.  The default is the current
+directory.
+.TP
+.B -s, --pagesize=SIZE
+Use page size SIZE.  The default is 4 KiB.  This size is the
+maximum size of a data node.  Set according to target system's memory
+management page size (NOTE: this is NOT related to NAND page size).
+.TP
+.B -e, --eraseblock=SIZE
+Use erase block size SIZE.  The default is 64 KiB.  If you use a erase
+block size different than the erase block size of the target MTD
+device, JFFS2 may not perform optimally. If the SIZE specified is
+below 4096, the units are assumed to be KiB.
+.TP
+.B -c, --cleanmarker=SIZE
+Write \'CLEANMARKER\' nodes with the size specified. It is not
+normally appropriate to specify a size other than the default 12
+bytes.
+.TP
+.B -n, --no-cleanmarkers
+Do not write \'CLEANMARKER\' nodes to the beginning of each erase
+block. This option can be useful for creating JFFS2 images for
+use on NAND flash, and for creating images which are to be used
+on a variety of hardware with differing eraseblock sizes.
+.TP
+.B -o, --output=FILE
+Write JFFS2 image to file FILE.  Default is the standard output.
+.TP
+.B -l, --little-endian
+Create a little-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -b, --big-endian
+Create a big-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -D, --devtable=FILE
+Use the named FILE as a device table file, for including devices and
+changing permissions in the created image when the user does not have
+appropriate permissions to create them on the file system used as
+source.
+.TP
+.B -f, --faketime
+Change all file timestamps to \'0\' for regression testing.
+.TP
+.B -q, --squash
+Squash permissions and owners, making all files be owned by root and
+removing write permission for \'group\' and \'other\'.
+.TP
+.B -U, --squash-uids
+Squash owners making all files be owned by root.
+.TP
+.B -P, --squash-perms
+Squash permissions, removing write permission for \'group\' and \'other\'.
+.TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
+.B -m, --compression-mode=MODE
+Set the default compression mode. The default mode is
+.B priority
+which tries the compressors in a predefinied order and chooses the first
+successful one. The alternatives are:
+.B none
+(mkfs will not compress) and
+.B size
+(mkfs will try all compressor and chooses the one which have the smallest result).
+.TP
+.B -x, --disable-compressor=NAME
+Disable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -X, --enable-compressor=NAME
+Enable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -y, --compressor-priority=PRIORITY:NAME
+Set the priority of a compressor. Use
+.B -L
+to see the list of the available compressors and their default priority.
+Priorities are used by priority compression mode.
+.TP
+.B -L, --list-compressors
+Show the list of the available compressors and their states.
+.TP
+.B -t, --test-compression
+Call decompress after every compress - and compare the result with the original data -, and
+some other check.
+.TP
+.B -h, --help
+Display help text.
+.TP
+.B -v, --verbose
+Verbose operation.
+.TP
+.B -V, --version
+Display version information.
+.TP
+.B -i, --incremental=FILE
+Generate an appendage image for FILE. If FILE is written to flash and flash
+is appended with the output, then it seems as if it was one thing.
+
+.SH LIMITATIONS
+The format and grammar of the device table file does not allow it to
+create symbolic links when the symbolic links are not already present
+in the root working directory.
+
+However, symbolic links may be specified in the device table file
+using the \fIl\fR type for the purposes of setting their permissions
+and ownership.
+.SH BUGS
+JFFS2 limits device major and minor numbers to 8 bits each.  Some
+consider this a bug.
+
+.B mkfs.jffs2
+does not properly handle hard links in the input directory structure.
+Currently, hard linked files will be expanded to multiple identical
+files in the output image.
+.SH AUTHORS
+David Woodhouse
+.br
+Manual page written by David Schleef <ds@schleef.org>
+.SH SEE ALSO
+.BR mkfs (8),
+.BR mkfs.jffs (1),
+.BR fakeroot (1)

+ 1811 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/mkfs.jffs2.c

@@ -0,0 +1,1811 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Build a JFFS2 image in a file, from a given directory tree.
+ *
+ * Copyright 2001, 2002 Red Hat, Inc.
+ *           2001 David A. Schleef <ds@lineo.com>
+ *           2002 Axis Communications AB
+ *           2001, 2002 Erik Andersen <andersen@codepoet.org>
+ *           2004 University of Szeged, Hungary
+ *           2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Cross-endian support added by David Schleef <ds@schleef.org>.
+ *
+ * Major architectural rewrite by Erik Andersen <andersen@codepoet.org>
+ * to allow support for making hard links (though hard links support is
+ * not yet implemented), and for munging file permissions and ownership
+ * on the fly using --faketime, --squash, --devtable.   And I plugged a
+ * few memory leaks, adjusted the error handling and fixed some little
+ * nits here and there.
+ *
+ * I also added a sample device table file.  See device_table.txt
+ *  -Erik, September 2001
+ *
+ * Cleanmarkers support added by Axis Communications AB
+ *
+ * Rewritten again.  Cleanly separated host and target filsystem
+ * activities (mainly so I can reuse all the host handling stuff as I
+ * rewrite other mkfs utils).  Added a verbose option to list types
+ * and attributes as files are added to the file system.  Major cleanup
+ * and scrubbing of the code so it can be read, understood, and
+ * modified by mere mortals.
+ *
+ *  -Erik, November 2002
+ */
+
+#define PROGRAM_NAME "mkfs.jffs2"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#ifndef WITHOUT_XATTR
+#include <sys/xattr.h>
+#include <sys/acl.h>
+#endif
+#include <byteswap.h>
+#include <crc32.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#include "rbtree.h"
+#include "common.h"
+
+/* Do not use the weird XPG version of basename */
+#undef basename
+
+//#define DMALLOC
+//#define mkfs_debug_msg    errmsg
+#define mkfs_debug_msg(a...)	{ }
+
+#define PAD(x) (((x)+3)&~3)
+
+struct filesystem_entry {
+	char *name;					/* Name of this directory (think basename) */
+	char *path;					/* Path of this directory (think dirname) */
+	char *fullname;				/* Full name of this directory (i.e. path+name) */
+	char *hostname;				/* Full path to this file on the host filesystem */
+	uint32_t ino;				/* Inode number of this file in JFFS2 */
+	struct stat sb;				/* Stores directory permissions and whatnot */
+	char *link;					/* Target a symlink points to. */
+	struct filesystem_entry *parent;	/* Parent directory */
+	struct filesystem_entry *prev;	/* Only relevant to non-directories */
+	struct filesystem_entry *next;	/* Only relevant to non-directories */
+	struct filesystem_entry *files;	/* Only relevant to directories */
+	struct rb_node hardlink_rb;
+};
+
+struct rb_root hardlinks;
+static int out_fd = -1;
+static int in_fd = -1;
+static char default_rootdir[] = ".";
+static char *rootdir = default_rootdir;
+static int verbose = 0;
+static int squash_uids = 0;
+static int squash_perms = 0;
+static int fake_times = 0;
+int target_endian = __BYTE_ORDER;
+
+static uint32_t find_hardlink(struct filesystem_entry *e)
+{
+	struct filesystem_entry *f;
+	struct rb_node **n = &hardlinks.rb_node;
+	struct rb_node *parent = NULL;
+
+	while (*n) {
+		parent = *n;
+		f = rb_entry(parent, struct filesystem_entry, hardlink_rb);
+
+		if ((f->sb.st_dev < e->sb.st_dev) ||
+		    (f->sb.st_dev == e->sb.st_dev &&
+		     f->sb.st_ino < e->sb.st_ino))
+			n = &parent->rb_left;
+		else if ((f->sb.st_dev > e->sb.st_dev) ||
+			 (f->sb.st_dev == e->sb.st_dev &&
+			  f->sb.st_ino > e->sb.st_ino)) {
+			n = &parent->rb_right;
+		} else
+			return f->ino;
+	}
+
+	rb_link_node(&e->hardlink_rb, parent, n);
+	rb_insert_color(&e->hardlink_rb, &hardlinks);
+	return 0;
+}
+
+static char *xreadlink(const char *path)
+{
+	static const int GROWBY = 80; /* how large we will grow strings by */
+
+	char *buf = NULL;
+	int bufsize = 0, readsize = 0;
+
+	do {
+		buf = xrealloc(buf, bufsize += GROWBY);
+		readsize = readlink(path, buf, bufsize); /* 1st try */
+		if (readsize == -1) {
+			sys_errmsg("%s:%s", PROGRAM_NAME, path);
+			free(buf);
+			return NULL;
+		}
+	}
+	while (bufsize < readsize + 1);
+
+	buf[readsize] = '\0';
+
+	return buf;
+}
+static FILE *xfopen(const char *path, const char *mode)
+{
+	FILE *fp;
+	if ((fp = fopen(path, mode)) == NULL)
+		sys_errmsg_die("%s", path);
+	return fp;
+}
+
+static struct filesystem_entry *find_filesystem_entry(
+		struct filesystem_entry *dir, char *fullname, uint32_t type)
+{
+	struct filesystem_entry *e = dir;
+
+	if (S_ISDIR(dir->sb.st_mode)) {
+		/* If this is the first call, and we actually want this
+		 * directory, then return it now */
+		if (strcmp(fullname, e->fullname) == 0)
+			return e;
+
+		e = dir->files;
+	}
+	while (e) {
+		if (S_ISDIR(e->sb.st_mode)) {
+			int len = strlen(e->fullname);
+
+			/* Check if we are a parent of the correct path */
+			if (strncmp(e->fullname, fullname, len) == 0) {
+				/* Is this an _exact_ match? */
+				if (strcmp(fullname, e->fullname) == 0) {
+					return (e);
+				}
+				/* Looks like we found a parent of the correct path */
+				if (fullname[len] == '/') {
+					if (e->files) {
+						return (find_filesystem_entry (e, fullname, type));
+					} else {
+						return NULL;
+					}
+				}
+			}
+		} else {
+			if (strcmp(fullname, e->fullname) == 0) {
+				return (e);
+			}
+		}
+		e = e->next;
+	}
+	return (NULL);
+}
+
+static struct filesystem_entry *add_host_filesystem_entry(const char *name,
+		const char *path, unsigned long uid, unsigned long gid,
+		unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
+{
+	int status;
+	char *tmp;
+	struct stat sb;
+	time_t timestamp = time(NULL);
+	struct filesystem_entry *entry;
+
+	memset(&sb, 0, sizeof(struct stat));
+	status = lstat(path, &sb);
+
+	if (status >= 0) {
+		/* It is ok for some types of files to not exit on disk (such as
+		 * device nodes), but if they _do_ exist the specified mode had
+		 * better match the actual file or strange things will happen.... */
+		if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
+			errmsg_die ("%s: file type does not match specified type!", path);
+		}
+		timestamp = sb.st_mtime;
+	} else {
+		/* If this is a regular file, it _must_ exist on disk */
+		if ((mode & S_IFMT) == S_IFREG) {
+			errmsg_die("%s: does not exist!", path);
+		}
+	}
+
+	/* Squash all permissions so files are owned by root, all
+	 * timestamps are _right now_, and file permissions
+	 * have group and other write removed */
+	if (squash_uids) {
+		uid = gid = 0;
+	}
+	if (squash_perms) {
+		if (!S_ISLNK(mode)) {
+			mode &= ~(S_IWGRP | S_IWOTH);
+			mode &= ~(S_ISUID | S_ISGID);
+		}
+	}
+	if (fake_times) {
+		timestamp = 0;
+	}
+
+	entry = xcalloc(1, sizeof(struct filesystem_entry));
+
+	entry->hostname = xstrdup(path);
+	entry->fullname = xstrdup(name);
+	tmp = xstrdup(name);
+	entry->name = xstrdup(basename(tmp));
+	free(tmp);
+	tmp = xstrdup(name);
+	entry->path = xstrdup(dirname(tmp));
+	free(tmp);
+
+	entry->sb.st_ino = sb.st_ino;
+	entry->sb.st_dev = sb.st_dev;
+	entry->sb.st_nlink = sb.st_nlink;
+
+	entry->sb.st_uid = uid;
+	entry->sb.st_gid = gid;
+	entry->sb.st_mode = mode;
+	entry->sb.st_rdev = rdev;
+	entry->sb.st_atime = entry->sb.st_ctime =
+		entry->sb.st_mtime = timestamp;
+	if (S_ISREG(mode)) {
+		entry->sb.st_size = sb.st_size;
+	}
+	if (S_ISLNK(mode)) {
+		entry->link = xreadlink(path);
+		entry->sb.st_size = strlen(entry->link);
+	}
+
+	/* This happens only for root */
+	if (!parent)
+		return (entry);
+
+	/* Hook the file into the parent directory */
+	entry->parent = parent;
+	if (!parent->files) {
+		parent->files = entry;
+	} else {
+		struct filesystem_entry *prev;
+		for (prev = parent->files; prev->next; prev = prev->next);
+		prev->next = entry;
+		entry->prev = prev;
+	}
+
+	return (entry);
+}
+
+static struct filesystem_entry *recursive_add_host_directory(
+		struct filesystem_entry *parent, const char *targetpath,
+		const char *hostpath)
+{
+	int i, n;
+	struct stat sb;
+	char *hpath, *tpath;
+	struct dirent *dp, **namelist;
+	struct filesystem_entry *entry;
+
+
+	if (lstat(hostpath, &sb)) {
+		sys_errmsg_die("%s", hostpath);
+	}
+
+	entry = add_host_filesystem_entry(targetpath, hostpath,
+			sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
+
+	n = scandir(hostpath, &namelist, 0, alphasort);
+	if (n < 0) {
+		sys_errmsg_die("opening directory %s", hostpath);
+	}
+
+	for (i=0; i<n; i++)
+	{
+		dp = namelist[i];
+		if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
+					(dp->d_name[1] == '.' &&  dp->d_name[2] == 0)))
+		{
+			free(dp);
+			continue;
+		}
+
+		xasprintf(&hpath, "%s/%s", hostpath, dp->d_name);
+		if (lstat(hpath, &sb)) {
+			sys_errmsg_die("%s", hpath);
+		}
+		if (strcmp(targetpath, "/") == 0) {
+			xasprintf(&tpath, "%s%s", targetpath, dp->d_name);
+		} else {
+			xasprintf(&tpath, "%s/%s", targetpath, dp->d_name);
+		}
+
+		switch (sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				recursive_add_host_directory(entry, tpath, hpath);
+				break;
+
+			case S_IFREG:
+			case S_IFSOCK:
+			case S_IFIFO:
+			case S_IFLNK:
+			case S_IFCHR:
+			case S_IFBLK:
+				add_host_filesystem_entry(tpath, hpath, sb.st_uid,
+						sb.st_gid, sb.st_mode, sb.st_rdev, entry);
+				break;
+
+			default:
+				errmsg("Unknown file type %o for %s", sb.st_mode, hpath);
+				break;
+		}
+		free(dp);
+		free(hpath);
+		free(tpath);
+	}
+	free(namelist);
+	return (entry);
+}
+
+/* the GNU C library has a wonderful scanf("%as", string) which will
+   allocate the string with the right size, good to avoid buffer overruns.
+   the following macros use it if available or use a hacky workaround...
+ */
+
+#ifdef __GNUC__
+#if __STDC_VERSION__ >= 199901L
+#define SCANF_PREFIX "m"
+#else
+#define SCANF_PREFIX "a"
+#endif
+#define SCANF_STRING(s) (&s)
+#define GETCWD_SIZE 0
+#else
+#define SCANF_PREFIX "511"
+#define SCANF_STRING(s) (s = xmalloc(512))
+#define GETCWD_SIZE -1
+inline int snprintf(char *str, size_t n, const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vsprintf(str, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+#endif
+
+/*  device table entries take the form of:
+	<path>	<type> <mode>	<uid>	<gid>	<major>	<minor>	<start>	<inc>	<count>
+	/dev/mem     c    640       0       0         1       1       0     0         -
+
+	type can be one of:
+	f	A regular file
+	d	Directory
+	c	Character special device file
+	b	Block special device file
+	p	Fifo (named pipe)
+
+	I don't bother with symlinks (permissions are irrelevant), hard
+	links (special cases of regular files), or sockets (why bother).
+
+	Regular files must exist in the target root directory.  If a char,
+	block, fifo, or directory does not exist, it will be created.
+ */
+static int interpret_table_entry(struct filesystem_entry *root, char *line)
+{
+	char *hostpath;
+	char type, *name = NULL, *tmp, *dir;
+	unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+	unsigned long start = 0, increment = 1, count = 0;
+	struct filesystem_entry *parent, *entry;
+
+	if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
+				SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
+				&start, &increment, &count) < 0)
+	{
+		return 1;
+	}
+
+	if (!strcmp(name, "/")) {
+		errmsg_die("Device table entries require absolute paths");
+	}
+
+	xasprintf(&hostpath, "%s%s", rootdir, name);
+
+	/* Check if this file already exists... */
+	switch (type) {
+		case 'd':
+			mode |= S_IFDIR;
+			break;
+		case 'f':
+			mode |= S_IFREG;
+			break;
+		case 'p':
+			mode |= S_IFIFO;
+			break;
+		case 'c':
+			mode |= S_IFCHR;
+			break;
+		case 'b':
+			mode |= S_IFBLK;
+			break;
+		case 'l':
+			mode |= S_IFLNK;
+			break;
+		default:
+			errmsg_die("Unsupported file type '%c'", type);
+	}
+	entry = find_filesystem_entry(root, name, mode);
+	if (entry && !(count > 0 && (type == 'c' || type == 'b'))) {
+		/* Ok, we just need to fixup the existing entry
+		 * and we will be all done... */
+		entry->sb.st_uid = uid;
+		entry->sb.st_gid = gid;
+		entry->sb.st_mode = mode;
+		if (major && minor) {
+			entry->sb.st_rdev = makedev(major, minor);
+		}
+	} else {
+		/* If parent is NULL (happens with device table entries),
+		 * try and find our parent now) */
+		tmp = xstrdup(name);
+		dir = dirname(tmp);
+		parent = find_filesystem_entry(root, dir, S_IFDIR);
+		free(tmp);
+		if (parent == NULL) {
+			errmsg ("skipping device_table entry '%s': no parent directory!", name);
+			free(name);
+			free(hostpath);
+			return 1;
+		}
+
+		switch (type) {
+			case 'd':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'f':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'p':
+				add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+				break;
+			case 'c':
+			case 'b':
+				if (count > 0) {
+					dev_t rdev;
+					unsigned long i;
+					char *dname, *hpath;
+
+					for (i = start; i < (start + count); i++) {
+						xasprintf(&dname, "%s%lu", name, i);
+						xasprintf(&hpath, "%s/%s%lu", rootdir, name, i);
+						rdev = makedev(major, minor + (i - start) * increment);
+						add_host_filesystem_entry(dname, hpath, uid, gid,
+								mode, rdev, parent);
+						free(dname);
+						free(hpath);
+					}
+				} else {
+					dev_t rdev = makedev(major, minor);
+					add_host_filesystem_entry(name, hostpath, uid, gid,
+							mode, rdev, parent);
+				}
+				break;
+			default:
+				errmsg_die("Unsupported file type '%c'", type);
+		}
+	}
+	free(name);
+	free(hostpath);
+	return 0;
+}
+
+static int parse_device_table(struct filesystem_entry *root, FILE * file)
+{
+	char *line;
+	int status = 0;
+	size_t length = 0;
+
+	/* Turn off squash, since we must ensure that values
+	 * entered via the device table are not squashed */
+	squash_uids = 0;
+	squash_perms = 0;
+
+	/* Looks ok so far.  The general plan now is to read in one
+	 * line at a time, check for leading comment delimiters ('#'),
+	 * then try and parse the line as a device table.  If we fail
+	 * to parse things, try and help the poor fool to fix their
+	 * device table with a useful error msg... */
+	line = NULL;
+	while (getline(&line, &length, file) != -1) {
+		/* First trim off any whitespace */
+		int len = strlen(line);
+
+		/* trim trailing whitespace */
+		while (len > 0 && isspace(line[len - 1]))
+			line[--len] = '\0';
+		/* trim leading whitespace */
+		memmove(line, &line[strspn(line, " \n\r\t\v")], len);
+
+		/* How long are we after trimming? */
+		len = strlen(line);
+
+		/* If this is NOT a comment line, try to interpret it */
+		if (len && *line != '#') {
+			if (interpret_table_entry(root, line))
+				status = 1;
+		}
+
+		free(line);
+		line = NULL;
+	}
+	fclose(file);
+
+	return status;
+}
+
+static void cleanup(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e, *prev;
+
+	e = dir->files;
+	while (e) {
+		if (e->name)
+			free(e->name);
+		if (e->path)
+			free(e->path);
+		if (e->fullname)
+			free(e->fullname);
+		e->next = NULL;
+		e->name = NULL;
+		e->path = NULL;
+		e->fullname = NULL;
+		e->prev = NULL;
+		prev = e;
+		if (S_ISDIR(e->sb.st_mode)) {
+			cleanup(e);
+		}
+		e = e->next;
+		free(prev);
+	}
+}
+
+/* Here is where we do the actual creation of the file system */
+#include "mtd/jffs2-user.h"
+
+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
+#ifndef JFFS2_MAX_SYMLINK_LEN
+#define JFFS2_MAX_SYMLINK_LEN 254
+#endif
+
+static uint32_t ino = 0;
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static int out_ofs = 0;
+static int erase_block_size = 65536;
+static int pad_fs_size = 0;
+static int add_cleanmarkers = 1;
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static unsigned char ffbuf[16] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/* We set this at start of main() using sysconf(), -1 means we don't know */
+/* When building an fs for non-native systems, use --pagesize=SIZE option */
+int page_size = -1;
+
+#include "compr.h"
+
+static void full_write(int fd, const void *buf, int len)
+{
+	int ret;
+
+	while (len > 0) {
+		ret = write(fd, buf, len);
+
+		if (ret < 0)
+			sys_errmsg_die("write");
+
+		if (ret == 0)
+			sys_errmsg_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+		out_ofs += ret;
+	}
+}
+
+static void padblock(void)
+{
+	while (out_ofs % erase_block_size) {
+		full_write(out_fd, ffbuf, min(sizeof(ffbuf),
+					erase_block_size - (out_ofs % erase_block_size)));
+	}
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(out_fd, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(out_fd, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword(void)
+{
+	if (out_ofs % 4) {
+		full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
+	}
+}
+
+static inline void pad_block_if_less_than(int req)
+{
+	if (add_cleanmarkers) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+	if ((out_ofs % erase_block_size) + req > erase_block_size) {
+		padblock();
+	}
+	if (add_cleanmarkers) {
+		if ((out_ofs % erase_block_size) == 0) {
+			full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+static void write_dirent(struct filesystem_entry *e)
+{
+	char *name = e->name;
+	struct jffs2_raw_dirent rd;
+	struct stat *statbuf = &(e->sb);
+	static uint32_t version = 0;
+
+	memset(&rd, 0, sizeof(rd));
+
+	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+	rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
+	rd.hdr_crc = cpu_to_je32(mtd_crc32(0, &rd,
+				sizeof(struct jffs2_unknown_node) - 4));
+	rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1);
+	rd.version = cpu_to_je32(version++);
+	rd.ino = cpu_to_je32(e->ino);
+	rd.mctime = cpu_to_je32(statbuf->st_mtime);
+	rd.nsize = strlen(name);
+	rd.type = IFTODT(statbuf->st_mode);
+	//rd.unused[0] = 0;
+	//rd.unused[1] = 0;
+	rd.node_crc = cpu_to_je32(mtd_crc32(0, &rd, sizeof(rd) - 8));
+	rd.name_crc = cpu_to_je32(mtd_crc32(0, name, strlen(name)));
+
+	pad_block_if_less_than(sizeof(rd) + rd.nsize);
+	full_write(out_fd, &rd, sizeof(rd));
+	full_write(out_fd, name, rd.nsize);
+	padword();
+}
+
+static unsigned int write_regular_file(struct filesystem_entry *e)
+{
+	int fd, len;
+	uint32_t ver;
+	unsigned int offset;
+	unsigned char *buf, *cbuf, *wbuf;
+	struct jffs2_raw_inode ri;
+	struct stat *statbuf;
+	unsigned int totcomp = 0;
+
+	statbuf = &(e->sb);
+	if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
+		errmsg("Skipping file \"%s\" too large.", e->path);
+		return -1;
+	}
+	fd = open(e->hostname, O_RDONLY);
+	if (fd == -1) {
+		sys_errmsg_die("%s: open file", e->hostname);
+	}
+
+	e->ino = ++ino;
+	mkfs_debug_msg("writing file '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) e->ino,
+			(unsigned long) e->parent->ino);
+	write_dirent(e);
+
+	buf = xmalloc(page_size);
+	cbuf = NULL;
+
+	ver = 0;
+	offset = 0;
+
+	memset(&ri, 0, sizeof(ri));
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+
+	while ((len = read(fd, buf, page_size))) {
+		unsigned char *tbuf = buf;
+
+		if (len < 0) {
+			sys_errmsg_die("read");
+		}
+
+		while (len) {
+			uint32_t dsize, space;
+			uint16_t compression;
+
+			pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
+
+			dsize = len;
+			space =
+				erase_block_size - (out_ofs % erase_block_size) -
+				sizeof(ri);
+			if (space > dsize)
+				space = dsize;
+
+			compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
+
+			ri.compr = compression & 0xff;
+			ri.usercompr = (compression >> 8) & 0xff;
+
+			if (ri.compr) {
+				wbuf = cbuf;
+			} else {
+				wbuf = tbuf;
+				dsize = space;
+			}
+
+			ri.totlen = cpu_to_je32(sizeof(ri) + space);
+			ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+						&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+			ri.version = cpu_to_je32(++ver);
+			ri.offset = cpu_to_je32(offset);
+			ri.csize = cpu_to_je32(space);
+			ri.dsize = cpu_to_je32(dsize);
+			ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+			ri.data_crc = cpu_to_je32(mtd_crc32(0, wbuf, space));
+
+			full_write(out_fd, &ri, sizeof(ri));
+			totcomp += sizeof(ri);
+			full_write(out_fd, wbuf, space);
+			totcomp += space;
+			padword();
+
+			if (tbuf != cbuf) {
+				free(cbuf);
+				cbuf = NULL;
+			}
+
+			tbuf += dsize;
+			len -= dsize;
+			offset += dsize;
+
+		}
+	}
+	if (!je32_to_cpu(ri.version)) {
+		/* Was empty file */
+		pad_block_if_less_than(sizeof(ri));
+
+		ri.version = cpu_to_je32(++ver);
+		ri.totlen = cpu_to_je32(sizeof(ri));
+		ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+					&ri, sizeof(struct jffs2_unknown_node) - 4));
+		ri.csize = cpu_to_je32(0);
+		ri.dsize = cpu_to_je32(0);
+		ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+
+		full_write(out_fd, &ri, sizeof(ri));
+		padword();
+	}
+	free(buf);
+	close(fd);
+	return totcomp;
+}
+
+static void write_symlink(struct filesystem_entry *e)
+{
+	int len;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	mkfs_debug_msg("writing symlink '%s'  ino=%lu  parent_ino=%lu",
+			e->name, (unsigned long) e->ino,
+			(unsigned long) e->parent->ino);
+	write_dirent(e);
+
+	len = strlen(e->link);
+	if (len > JFFS2_MAX_SYMLINK_LEN) {
+		errmsg("symlink too large. Truncated to %d chars.",
+				JFFS2_MAX_SYMLINK_LEN);
+		len = JFFS2_MAX_SYMLINK_LEN;
+	}
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + len);
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(len);
+	ri.dsize = cpu_to_je32(len);
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(mtd_crc32(0, e->link, len));
+
+	pad_block_if_less_than(sizeof(ri) + len);
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, e->link, len);
+	padword();
+}
+
+static void write_pipe(struct filesystem_entry *e)
+{
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	if (S_ISDIR(statbuf->st_mode)) {
+		mkfs_debug_msg("writing dir '%s'  ino=%lu  parent_ino=%lu",
+				e->name, (unsigned long) e->ino,
+				(unsigned long) (e->parent) ? e->parent->ino : 1);
+	}
+	write_dirent(e);
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri));
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(0);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(0);
+	ri.dsize = cpu_to_je32(0);
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(0);
+
+	pad_block_if_less_than(sizeof(ri));
+	full_write(out_fd, &ri, sizeof(ri));
+	padword();
+}
+
+static void write_special_file(struct filesystem_entry *e)
+{
+	jint16_t kdev;
+	struct stat *statbuf;
+	struct jffs2_raw_inode ri;
+
+	statbuf = &(e->sb);
+	e->ino = ++ino;
+	write_dirent(e);
+
+	kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
+			minor(statbuf->st_rdev));
+
+	memset(&ri, 0, sizeof(ri));
+
+	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+	ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
+	ri.hdr_crc = cpu_to_je32(mtd_crc32(0,
+				&ri, sizeof(struct jffs2_unknown_node) - 4));
+
+	ri.ino = cpu_to_je32(e->ino);
+	ri.mode = cpu_to_jemode(statbuf->st_mode);
+	ri.uid = cpu_to_je16(statbuf->st_uid);
+	ri.gid = cpu_to_je16(statbuf->st_gid);
+	ri.atime = cpu_to_je32(statbuf->st_atime);
+	ri.ctime = cpu_to_je32(statbuf->st_ctime);
+	ri.mtime = cpu_to_je32(statbuf->st_mtime);
+	ri.isize = cpu_to_je32(statbuf->st_size);
+	ri.version = cpu_to_je32(1);
+	ri.csize = cpu_to_je32(sizeof(kdev));
+	ri.dsize = cpu_to_je32(sizeof(kdev));
+	ri.node_crc = cpu_to_je32(mtd_crc32(0, &ri, sizeof(ri) - 8));
+	ri.data_crc = cpu_to_je32(mtd_crc32(0, &kdev, sizeof(kdev)));
+
+	pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
+	full_write(out_fd, &ri, sizeof(ri));
+	full_write(out_fd, &kdev, sizeof(kdev));
+	padword();
+}
+
+#ifndef WITHOUT_XATTR
+typedef struct xattr_entry {
+	struct xattr_entry *next;
+	uint32_t xid;
+	int xprefix;
+	char *xname;
+	char *xvalue;
+	int name_len;
+	int value_len;
+} xattr_entry_t;
+
+#define XATTR_BUFFER_SIZE		(64 * 1024)	/* 64KB */
+static uint32_t enable_xattr = 0;
+static uint32_t highest_xid = 0;
+static uint32_t highest_xseqno = 0;
+
+static struct {
+	int xprefix;
+	const char *string;
+	int length;
+} xprefix_tbl[] = {
+	{ JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
+	{ JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+	{ JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
+	{ JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
+	{ JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
+	{ 0, NULL, 0 }
+};
+
+static void formalize_posix_acl(void *xvalue, int *value_len)
+{
+	struct posix_acl_xattr_header *pacl_header;
+	struct posix_acl_xattr_entry *pent, *plim;
+	struct jffs2_acl_header *jacl_header;
+	struct jffs2_acl_entry *jent;
+	struct jffs2_acl_entry_short *jent_s;
+	char buffer[XATTR_BUFFER_SIZE];
+	int offset = 0;
+
+	pacl_header = xvalue;;
+	pent = pacl_header->a_entries;
+	plim = xvalue + *value_len;
+
+	jacl_header = (struct jffs2_acl_header *)buffer;
+	offset += sizeof(struct jffs2_acl_header);
+	jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+
+	while (pent < plim) {
+		switch(le16_to_cpu(pent->e_tag)) {
+			case ACL_USER_OBJ:
+			case ACL_GROUP_OBJ:
+			case ACL_MASK:
+			case ACL_OTHER:
+				jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
+				offset += sizeof(struct jffs2_acl_entry_short);
+				jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+				jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+				break;
+			case ACL_USER:
+			case ACL_GROUP:
+				jent = (struct jffs2_acl_entry *)(buffer + offset);
+				offset += sizeof(struct jffs2_acl_entry);
+				jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+				jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+				jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
+				break;
+			default:
+				printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
+				exit(1);
+		}
+		pent++;
+	}
+	if (offset > *value_len) {
+		printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
+				offset, *value_len);
+		exit(EXIT_FAILURE);
+	}
+	memcpy(xvalue, buffer, offset);
+	*value_len = offset;
+}
+
+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	xattr_entry_t *xe;
+	struct jffs2_raw_xattr rx;
+	int name_len;
+
+	/* create xattr entry */
+	name_len = strlen(xname);
+	xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
+	xe->next = NULL;
+	xe->xid = ++highest_xid;
+	xe->xprefix = xprefix;
+	xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
+	xe->xvalue = xe->xname + name_len + 1;
+	xe->name_len = name_len;
+	xe->value_len = value_len;
+	strcpy(xe->xname, xname);
+	memcpy(xe->xvalue, xvalue, value_len);
+
+	/* write xattr node */
+	memset(&rx, 0, sizeof(rx));
+	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+	rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
+	rx.hdr_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+	rx.xid = cpu_to_je32(xe->xid);
+	rx.version = cpu_to_je32(1);	/* initial version */
+	rx.xprefix = xprefix;
+	rx.name_len = xe->name_len;
+	rx.value_len = cpu_to_je16(xe->value_len);
+	rx.data_crc = cpu_to_je32(mtd_crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+	rx.node_crc = cpu_to_je32(mtd_crc32(0, &rx, sizeof(rx) - 4));
+
+	pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+	full_write(out_fd, &rx, sizeof(rx));
+	full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
+	padword();
+
+	return xe;
+}
+
+#define XATTRENTRY_HASHSIZE	57
+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	static xattr_entry_t **xentry_hash = NULL;
+	xattr_entry_t *xe;
+	int index, name_len;
+
+	/* create hash table */
+	if (!xentry_hash)
+		xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
+
+	if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
+			|| xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
+		formalize_posix_acl(xvalue, &value_len);
+
+	name_len = strlen(xname);
+	index = (mtd_crc32(0, xname, name_len) ^ mtd_crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
+	for (xe = xentry_hash[index]; xe; xe = xe->next) {
+		if (xe->xprefix == xprefix
+				&& xe->value_len == value_len
+				&& !strcmp(xe->xname, xname)
+				&& !memcmp(xe->xvalue, xvalue, value_len))
+			break;
+	}
+	if (!xe) {
+		xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
+		xe->next = xentry_hash[index];
+		xentry_hash[index] = xe;
+	}
+	return xe;
+}
+
+static void write_xattr_entry(struct filesystem_entry *e)
+{
+	struct jffs2_raw_xref ref;
+	struct xattr_entry *xe;
+	char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
+	char *xname;
+	const char *prefix_str;
+	int i, xprefix, prefix_len;
+	int list_sz, offset, name_len, value_len;
+
+	if (!enable_xattr)
+		return;
+
+	list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
+	if (list_sz < 0) {
+		if (verbose)
+			printf("llistxattr('%s') = %d : %s\n",
+					e->hostname, errno, strerror(errno));
+		return;
+	}
+
+	for (offset = 0; offset < list_sz; offset += name_len) {
+		xname = xlist + offset;
+		name_len = strlen(xname) + 1;
+
+		for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
+			prefix_str = xprefix_tbl[i].string;
+			prefix_len = xprefix_tbl[i].length;
+			if (prefix_str[prefix_len - 1] == '.') {
+				if (!strncmp(xname, prefix_str, prefix_len - 1))
+					break;
+			} else {
+				if (!strcmp(xname, prefix_str))
+					break;
+			}
+		}
+		if (!xprefix) {
+			if (verbose)
+				printf("%s: xattr '%s' is not supported.\n",
+						e->hostname, xname);
+			continue;
+		}
+		if ((enable_xattr & (1 << xprefix)) == 0)
+			continue;
+
+		value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
+		if (value_len < 0) {
+			if (verbose)
+				printf("lgetxattr('%s', '%s') = %d : %s\n",
+						e->hostname, xname, errno, strerror(errno));
+			continue;
+		}
+		xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
+		if (!xe) {
+			if (verbose)
+				printf("%s : xattr '%s' was ignored.\n",
+						e->hostname, xname);
+			continue;
+		}
+
+		memset(&ref, 0, sizeof(ref));
+		ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+		ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+		ref.totlen = cpu_to_je32(sizeof(ref));
+		ref.hdr_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
+		ref.ino = cpu_to_je32(e->ino);
+		ref.xid = cpu_to_je32(xe->xid);
+		ref.xseqno = cpu_to_je32(highest_xseqno += 2);
+		ref.node_crc = cpu_to_je32(mtd_crc32(0, &ref, sizeof(ref) - 4));
+
+		pad_block_if_less_than(sizeof(ref));
+		full_write(out_fd, &ref, sizeof(ref));
+		padword();
+	}
+}
+
+#else /* WITHOUT_XATTR */
+#define write_xattr_entry(x)
+#endif
+
+static void recursive_populate_directory(struct filesystem_entry *dir)
+{
+	struct filesystem_entry *e;
+	unsigned int wrote;
+
+	if (verbose) {
+		printf("%s\n", dir->fullname);
+	}
+	write_xattr_entry(dir);		/* for '/' */
+
+	e = dir->files;
+	while (e) {
+		if (e->sb.st_nlink >= 1 &&
+		    (e->ino = find_hardlink(e))) {
+
+			write_dirent(e);
+			if (verbose) {
+				printf("\tL %04o %9lu             %5d:%-3d %s\n",
+				       e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino,
+				       (int) (e->sb.st_uid), (int) (e->sb.st_gid),
+				       e->name);
+			}
+		} else switch (e->sb.st_mode & S_IFMT) {
+			case S_IFDIR:
+				if (verbose) {
+					printf("\td %04o %9lld             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
+							(int) (e->sb.st_uid), (int) (e->sb.st_gid),
+							e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFSOCK:
+				if (verbose) {
+					printf("\ts %04o %9lld             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFIFO:
+				if (verbose) {
+					printf("\tp %04o %9lld             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				write_pipe(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFCHR:
+				if (verbose) {
+					printf("\tc %04o %4d,%4d             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFBLK:
+				if (verbose) {
+					printf("\tb %04o %4d,%4d             %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+							minor(e->sb.st_rdev), (int) e->sb.st_uid,
+							(int) e->sb.st_gid, e->name);
+				}
+				write_special_file(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFLNK:
+				if (verbose) {
+					printf("\tl %04o %9lld             %5d:%-3d %s -> %s\n",
+							e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
+							e->link);
+				}
+				write_symlink(e);
+				write_xattr_entry(e);
+				break;
+			case S_IFREG:
+				wrote = write_regular_file(e);
+				write_xattr_entry(e);
+				if (verbose) {
+					printf("\tf %04o %9lld (%9u) %5d:%-3d %s\n",
+							e->sb.st_mode & ~S_IFMT, (long long)e->sb.st_size, wrote,
+							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+				}
+				break;
+			default:
+				errmsg("Unknown mode %o for %s", e->sb.st_mode,
+						e->fullname);
+				break;
+		}
+		e = e->next;
+	}
+
+	e = dir->files;
+	while (e) {
+		if (S_ISDIR(e->sb.st_mode)) {
+			if (e->files) {
+				recursive_populate_directory(e);
+			} else if (verbose) {
+				printf("%s\n", e->fullname);
+			}
+		}
+		e = e->next;
+	}
+}
+
+static void create_target_filesystem(struct filesystem_entry *root)
+{
+	cleanmarker.magic    = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen   = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc  = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+
+	if (ino == 0)
+		ino = 1;
+
+	root->ino = 1;
+	recursive_populate_directory(root);
+
+	if (pad_fs_size == -1) {
+		padblock();
+	} else {
+		if (pad_fs_size && add_cleanmarkers){
+			padblock();
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+				pad(cleanmarker_size - sizeof(cleanmarker));
+				padblock();
+			}
+		} else {
+			while (out_ofs < pad_fs_size) {
+				full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
+			}
+
+		}
+	}
+}
+
+static struct option long_options[] = {
+	{"pad", 2, NULL, 'p'},
+	{"root", 1, NULL, 'r'},
+	{"pagesize", 1, NULL, 's'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"output", 1, NULL, 'o'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"big-endian", 0, NULL, 'b'},
+	{"little-endian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"squash", 0, NULL, 'q'},
+	{"squash-uids", 0, NULL, 'U'},
+	{"squash-perms", 0, NULL, 'P'},
+	{"faketime", 0, NULL, 'f'},
+	{"devtable", 1, NULL, 'D'},
+	{"compression-mode", 1, NULL, 'm'},
+	{"disable-compressor", 1, NULL, 'x'},
+	{"enable-compressor", 1, NULL, 'X'},
+	{"test-compression", 0, NULL, 't'},
+	{"compressor-priority", 1, NULL, 'y'},
+	{"incremental", 1, NULL, 'i'},
+#ifndef WITHOUT_XATTR
+	{"with-xattr", 0, NULL, 1000 },
+	{"with-selinux", 0, NULL, 1001 },
+	{"with-posix-acl", 0, NULL, 1002 },
+#endif
+	{NULL, 0, NULL, 0}
+};
+
+static const char helptext[] =
+"Usage: mkfs.jffs2 [OPTIONS]\n"
+"Make a JFFS2 file system image from an existing directory tree\n\n"
+"Options:\n"
+"  -p, --pad[=SIZE]        Pad output to SIZE bytes with 0xFF. If SIZE is\n"
+"                          not specified, the output is padded to the end of\n"
+"                          the final erase block\n"
+"  -r, -d, --root=DIR      Build file system from directory DIR (default: cwd)\n"
+"  -s, --pagesize=SIZE     Use page size (max data node size) SIZE.\n"
+"                          Set according to target system's memory management\n"
+"                          page size (default: 4KiB)\n"
+"  -e, --eraseblock=SIZE   Use erase block size SIZE (default: 64KiB)\n"
+"  -c, --cleanmarker=SIZE  Size of cleanmarker (default 12)\n"
+"  -m, --compr-mode=MODE   Select compression mode (default: priority)\n"
+"  -x, --disable-compressor=COMPRESSOR_NAME\n"
+"                          Disable a compressor\n"
+"  -X, --enable-compressor=COMPRESSOR_NAME\n"
+"                          Enable a compressor\n"
+"  -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
+"                          Set the priority of a compressor\n"
+"  -L, --list-compressors  Show the list of the available compressors\n"
+"  -t, --test-compression  Call decompress and compare with the original (for test)\n"
+"  -n, --no-cleanmarkers   Don't add a cleanmarker to every eraseblock\n"
+"  -o, --output=FILE       Output to FILE (default: stdout)\n"
+"  -l, --little-endian     Create a little-endian filesystem\n"
+"  -b, --big-endian        Create a big-endian filesystem\n"
+"  -D, --devtable=FILE     Use the named FILE as a device table file\n"
+"  -f, --faketime          Change all file times to '0' for regression testing\n"
+"  -q, --squash            Squash permissions and owners making all files be owned by root\n"
+"  -U, --squash-uids       Squash owners making all files be owned by root\n"
+"  -P, --squash-perms      Squash permissions on all files\n"
+#ifndef WITHOUT_XATTR
+"      --with-xattr        stuff all xattr entries into image\n"
+"      --with-selinux      stuff only SELinux Labels into jffs2 image\n"
+"      --with-posix-acl    stuff only POSIX ACL entries into jffs2 image\n"
+#endif
+"  -h, --help              Display this help text\n"
+"  -v, --verbose           Verbose operation\n"
+"  -V, --version           Display version information\n"
+"  -i, --incremental=FILE  Parse FILE and generate appendage output for it\n\n";
+
+static int load_next_block(void) {
+
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+
+	if(verbose)
+		printf("Load next block : %d bytes read\n",ret);
+
+	return ret;
+}
+
+static void process_buffer(int inp_size) {
+	uint8_t		*p = file_buffer;
+	union jffs2_node_union 	*node;
+	uint16_t	type;
+	int		bitchbitmask = 0;
+	int		obsolete;
+
+	char	name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08zx, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else
+			obsolete = 0;
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE:
+				if(verbose)
+					printf ("%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+							je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+							je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				if ( je32_to_cpu (node->i.ino) > ino )
+					ino = je32_to_cpu (node->i.ino);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				if(verbose)
+					printf ("%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+							je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+							node->d.nsize, name);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				if (verbose) {
+					printf ("%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				if (verbose) {
+					printf ("%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				if (verbose) {
+					printf ("%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+							obsolete ? "Obsolete" : "",
+							p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+static void parse_image(void){
+	int ret;
+
+	file_buffer = xmalloc(erase_block_size);
+
+	while ((ret = load_next_block())) {
+		process_buffer(ret);
+	}
+
+	if (file_buffer)
+		free(file_buffer);
+
+	close(in_fd);
+}
+
+int main(int argc, char **argv)
+{
+	int c, opt;
+	char *cwd;
+	struct stat sb;
+	FILE *devtable = NULL;
+	struct filesystem_entry *root;
+	char *compr_name = NULL;
+	int compr_prior  = -1;
+	int warn_page_size = 0;
+
+	page_size = sysconf(_SC_PAGESIZE);
+	if (page_size < 0) /* System doesn't know so ... */
+		page_size = 4096; /* ... we make an educated guess */
+	if (page_size != 4096)
+		warn_page_size = 1; /* warn user if page size not 4096 */
+
+	jffs2_compressors_init();
+
+	while ((opt = getopt_long(argc, argv,
+					"D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
+	{
+		switch (opt) {
+			case 'D':
+				devtable = xfopen(optarg, "r");
+				if (fstat(fileno(devtable), &sb) < 0)
+					sys_errmsg_die("%s", optarg);
+				if (sb.st_size < 10)
+					errmsg_die("%s: not a proper device table file", optarg);
+				break;
+
+			case 'r':
+			case 'd':	/* for compatibility with mkfs.jffs, genext2fs, etc... */
+				if (rootdir != default_rootdir) {
+					errmsg_die("root directory specified more than once");
+				}
+				rootdir = xstrdup(optarg);
+				break;
+
+			case 's':
+				page_size = strtol(optarg, NULL, 0);
+				warn_page_size = 0; /* set by user, so don't need to warn */
+				break;
+
+			case 'o':
+				if (out_fd != -1) {
+					errmsg_die("output filename specified more than once");
+				}
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1) {
+					sys_errmsg_die("open output file");
+				}
+				break;
+
+			case 'q':
+				squash_uids = 1;
+				squash_perms = 1;
+				break;
+
+			case 'U':
+				squash_uids = 1;
+				break;
+
+			case 'P':
+				squash_perms = 1;
+				break;
+
+			case 'f':
+				fake_times = 1;
+				break;
+
+			case 'h':
+				puts(helptext);
+				exit(EXIT_SUCCESS);
+			case '?':
+				puts(helptext);
+				exit(EXIT_FAILURE);
+
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+
+			case 'e': {
+						  char *next;
+						  unsigned units = 0;
+						  erase_block_size = strtol(optarg, &next, 0);
+						  if (!erase_block_size)
+							  errmsg_die("Unrecognisable erase size\n");
+
+						  if (*next) {
+							  if (!strcmp(next, "KiB")) {
+								  units = 1024;
+							  } else if (!strcmp(next, "MiB")) {
+								  units = 1024 * 1024;
+							  } else {
+								  errmsg_die("Unknown units in erasesize\n");
+							  }
+						  } else {
+							  if (erase_block_size < 0x1000)
+								  units = 1024;
+							  else
+								  units = 1;
+						  }
+						  erase_block_size *= units;
+
+						  /* If it's less than 8KiB, they're not allowed */
+						  if (erase_block_size < 0x2000) {
+							  fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+									  erase_block_size);
+							  erase_block_size = 0x2000;
+						  }
+						  break;
+					  }
+
+			case 'l':
+					  target_endian = __LITTLE_ENDIAN;
+					  break;
+
+			case 'b':
+					  target_endian = __BIG_ENDIAN;
+					  break;
+
+			case 'p':
+					  if (optarg)
+						  pad_fs_size = strtol(optarg, NULL, 0);
+					  else
+						  pad_fs_size = -1;
+					  break;
+			case 'n':
+					  add_cleanmarkers = 0;
+					  break;
+			case 'c':
+					  cleanmarker_size = strtol(optarg, NULL, 0);
+					  if (cleanmarker_size < sizeof(cleanmarker)) {
+						  errmsg_die("cleanmarker size must be >= 12");
+					  }
+					  if (cleanmarker_size >= erase_block_size) {
+						  errmsg_die("cleanmarker size must be < eraseblock size");
+					  }
+					  break;
+			case 'm':
+					  if (jffs2_set_compression_mode_name(optarg)) {
+						  errmsg_die("Unknown compression mode %s", optarg);
+					  }
+					  break;
+			case 'x':
+					  if (jffs2_disable_compressor_name(optarg)) {
+						  errmsg_die("Unknown compressor name %s",optarg);
+					  }
+					  break;
+			case 'X':
+					  if (jffs2_enable_compressor_name(optarg)) {
+						  errmsg_die("Unknown compressor name %s",optarg);
+					  }
+					  break;
+			case 'L':
+					  errmsg_die("\n%s",jffs2_list_compressors());
+					  break;
+			case 't':
+					  jffs2_compression_check_set(1);
+					  break;
+			case 'y':
+					  compr_name = xmalloc(strlen(optarg));
+					  sscanf(optarg,"%d:%s",&compr_prior,compr_name);
+					  if ((compr_prior>=0)&&(compr_name)) {
+						  if (jffs2_set_compressor_priority(compr_name, compr_prior))
+							  exit(EXIT_FAILURE);
+					  }
+					  else {
+						  errmsg_die("Cannot parse %s",optarg);
+					  }
+					  free(compr_name);
+					  break;
+			case 'i':
+					  if (in_fd != -1) {
+						  errmsg_die("(incremental) filename specified more than once");
+					  }
+					  in_fd = open(optarg, O_RDONLY);
+					  if (in_fd == -1) {
+						  sys_errmsg_die("cannot open (incremental) file");
+					  }
+					  break;
+#ifndef WITHOUT_XATTR
+			case 1000:	/* --with-xattr  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_USER)
+						  | (1 << JFFS2_XPREFIX_SECURITY)
+						  | (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
+						  | (1 << JFFS2_XPREFIX_TRUSTED);
+					  break;
+			case 1001:	/*  --with-selinux  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
+					  break;
+			case 1002:	/*  --with-posix-acl  */
+					  enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						  | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
+					  break;
+#endif
+		}
+	}
+	if (warn_page_size) {
+		errmsg("Page size for this system is by default %d", page_size);
+		errmsg("Use the --pagesize=SIZE option if this is not what you want");
+	}
+	if (out_fd == -1) {
+		if (isatty(1)) {
+			errmsg_die("%s", helptext);
+		}
+		out_fd = 1;
+	}
+
+	if (chdir(rootdir))
+		sys_errmsg_die("%s", rootdir);
+
+	if (!(cwd = getcwd(0, GETCWD_SIZE)))
+		sys_errmsg_die("getcwd failed");
+
+	if(in_fd != -1)
+		parse_image();
+
+	root = recursive_add_host_directory(NULL, "/", cwd);
+
+	if (devtable)
+		parse_device_table(root, devtable);
+
+	create_target_filesystem(root);
+
+	cleanup(root);
+
+	if (rootdir != default_rootdir)
+		free(rootdir);
+
+	close(out_fd);
+
+	if (verbose) {
+		char *s = jffs2_stats();
+		fprintf(stderr,"\n\n%s",s);
+		free(s);
+	}
+	if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
+		fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
+	}
+
+	jffs2_compressors_exit();
+
+	return 0;
+}

+ 390 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/rbtree.c

@@ -0,0 +1,390 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@infradead.org>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  linux/lib/rbtree.c
+*/
+
+#include <stdlib.h>
+#include "rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *right = node->rb_right;
+	struct rb_node *parent = rb_parent(node);
+
+	if ((node->rb_right = right->rb_left))
+		rb_set_parent(right->rb_left, node);
+	right->rb_left = node;
+
+	rb_set_parent(right, parent);
+
+	if (parent)
+	{
+		if (node == parent->rb_left)
+			parent->rb_left = right;
+		else
+			parent->rb_right = right;
+	}
+	else
+		root->rb_node = right;
+	rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *left = node->rb_left;
+	struct rb_node *parent = rb_parent(node);
+
+	if ((node->rb_left = left->rb_right))
+		rb_set_parent(left->rb_right, node);
+	left->rb_right = node;
+
+	rb_set_parent(left, parent);
+
+	if (parent)
+	{
+		if (node == parent->rb_right)
+			parent->rb_right = left;
+		else
+			parent->rb_left = left;
+	}
+	else
+		root->rb_node = left;
+	rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *parent, *gparent;
+
+	while ((parent = rb_parent(node)) && rb_is_red(parent))
+	{
+		gparent = rb_parent(parent);
+
+		if (parent == gparent->rb_left)
+		{
+			{
+				register struct rb_node *uncle = gparent->rb_right;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_right == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_left(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_right(gparent, root);
+		} else {
+			{
+				register struct rb_node *uncle = gparent->rb_left;
+				if (uncle && rb_is_red(uncle))
+				{
+					rb_set_black(uncle);
+					rb_set_black(parent);
+					rb_set_red(gparent);
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_left == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_right(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			rb_set_black(parent);
+			rb_set_red(gparent);
+			__rb_rotate_left(gparent, root);
+		}
+	}
+
+	rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+			     struct rb_root *root)
+{
+	struct rb_node *other;
+
+	while ((!node || rb_is_black(node)) && node != root->rb_node)
+	{
+		if (parent->rb_left == node)
+		{
+			other = parent->rb_right;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_left(parent, root);
+				other = parent->rb_right;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_right || rb_is_black(other->rb_right))
+				{
+					struct rb_node *o_left;
+					if ((o_left = other->rb_left))
+						rb_set_black(o_left);
+					rb_set_red(other);
+					__rb_rotate_right(other, root);
+					other = parent->rb_right;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				if (other->rb_right)
+					rb_set_black(other->rb_right);
+				__rb_rotate_left(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+		else
+		{
+			other = parent->rb_left;
+			if (rb_is_red(other))
+			{
+				rb_set_black(other);
+				rb_set_red(parent);
+				__rb_rotate_right(parent, root);
+				other = parent->rb_left;
+			}
+			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+			    (!other->rb_right || rb_is_black(other->rb_right)))
+			{
+				rb_set_red(other);
+				node = parent;
+				parent = rb_parent(node);
+			}
+			else
+			{
+				if (!other->rb_left || rb_is_black(other->rb_left))
+				{
+					register struct rb_node *o_right;
+					if ((o_right = other->rb_right))
+						rb_set_black(o_right);
+					rb_set_red(other);
+					__rb_rotate_left(other, root);
+					other = parent->rb_left;
+				}
+				rb_set_color(other, rb_color(parent));
+				rb_set_black(parent);
+				if (other->rb_left)
+					rb_set_black(other->rb_left);
+				__rb_rotate_right(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+	}
+	if (node)
+		rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *child, *parent;
+	int color;
+
+	if (!node->rb_left)
+		child = node->rb_right;
+	else if (!node->rb_right)
+		child = node->rb_left;
+	else
+	{
+		struct rb_node *old = node, *left;
+
+		node = node->rb_right;
+		while ((left = node->rb_left) != NULL)
+			node = left;
+		child = node->rb_right;
+		parent = rb_parent(node);
+		color = rb_color(node);
+
+		if (child)
+			rb_set_parent(child, parent);
+		if (parent == old) {
+			parent->rb_right = child;
+			parent = node;
+		} else
+			parent->rb_left = child;
+
+		node->rb_parent_color = old->rb_parent_color;
+		node->rb_right = old->rb_right;
+		node->rb_left = old->rb_left;
+
+		if (rb_parent(old))
+		{
+			if (rb_parent(old)->rb_left == old)
+				rb_parent(old)->rb_left = node;
+			else
+				rb_parent(old)->rb_right = node;
+		} else
+			root->rb_node = node;
+
+		rb_set_parent(old->rb_left, node);
+		if (old->rb_right)
+			rb_set_parent(old->rb_right, node);
+		goto color;
+	}
+
+	parent = rb_parent(node);
+	color = rb_color(node);
+
+	if (child)
+		rb_set_parent(child, parent);
+	if (parent)
+	{
+		if (parent->rb_left == node)
+			parent->rb_left = child;
+		else
+			parent->rb_right = child;
+	}
+	else
+		root->rb_node = child;
+
+ color:
+	if (color == RB_BLACK)
+		__rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_right)
+		n = n->rb_right;
+	return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+	struct rb_node *parent;
+
+	if (rb_parent(node) == node)
+		return NULL;
+
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right;
+		while (node->rb_left)
+			node=node->rb_left;
+		return node;
+	}
+
+	/* No right-hand children.  Everything down and left is
+	   smaller than us, so any 'next' node must be in the general
+	   direction of our parent. Go up the tree; any time the
+	   ancestor is a right-hand child of its parent, keep going
+	   up. First time it's a left-hand child of its parent, said
+	   parent is our 'next' node. */
+	while ((parent = rb_parent(node)) && node == parent->rb_right)
+		node = parent;
+
+	return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+	struct rb_node *parent;
+
+	if (rb_parent(node) == node)
+		return NULL;
+
+	/* If we have a left-hand child, go down and then right as far
+	   as we can. */
+	if (node->rb_left) {
+		node = node->rb_left;
+		while (node->rb_right)
+			node=node->rb_right;
+		return node;
+	}
+
+	/* No left-hand children. Go up till we find an ancestor which
+	   is a right-hand child of its parent */
+	while ((parent = rb_parent(node)) && node == parent->rb_left)
+		node = parent;
+
+	return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+		     struct rb_root *root)
+{
+	struct rb_node *parent = rb_parent(victim);
+
+	/* Set the surrounding nodes to point to the replacement */
+	if (parent) {
+		if (victim == parent->rb_left)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else {
+		root->rb_node = new;
+	}
+	if (victim->rb_left)
+		rb_set_parent(victim->rb_left, new);
+	if (victim->rb_right)
+		rb_set_parent(victim->rb_right, new);
+
+	/* Copy the pointers/colour from the victim to the replacement */
+	*new = *victim;
+}

+ 171 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/rbtree.h

@@ -0,0 +1,171 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  linux/include/linux/rbtree.h
+
+  To use rbtrees you'll have to implement your own insert and search cores.
+  This will avoid us to use callbacks and to drop drammatically performances.
+  I know it's not the cleaner way,  but in C (not in C++) to get
+  performances and genericity...
+
+  Some example of insert and search follows here. The search is a plain
+  normal search over an ordered tree. The insert instead must be implemented
+  int two steps: as first thing the code must insert the element in
+  order as a red leaf in the tree, then the support library function
+  rb_insert_color() must be called. Such function will do the
+  not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+						 unsigned long offset)
+{
+	struct rb_node * n = inode->i_rb_page_cache.rb_node;
+	struct page * page;
+
+	while (n)
+	{
+		page = rb_entry(n, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			n = n->rb_left;
+		else if (offset > page->offset)
+			n = n->rb_right;
+		else
+			return page;
+	}
+	return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+						   unsigned long offset,
+						   struct rb_node * node)
+{
+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+	struct rb_node * parent = NULL;
+	struct page * page;
+
+	while (*p)
+	{
+		parent = *p;
+		page = rb_entry(parent, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			p = &(*p)->rb_left;
+		else if (offset > page->offset)
+			p = &(*p)->rb_right;
+		else
+			return page;
+	}
+
+	rb_link_node(node, parent, p);
+
+	return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+						 unsigned long offset,
+						 struct rb_node * node)
+{
+	struct page * ret;
+	if ((ret = __rb_insert_page_cache(inode, offset, node)))
+		goto out;
+	rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+	return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+
+struct rb_node
+{
+	unsigned long  rb_parent_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+    /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+	struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r)   ((r)->rb_parent_color & 1)
+#define rb_is_red(r)   (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_ROOT	(struct rb_root) { NULL, }
+
+/* Newer gcc versions take care of exporting this */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define	rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)
+#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+			    struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent_color = (unsigned long )parent;
+	node->rb_left = node->rb_right = NULL;
+
+	*rb_link = node;
+}
+
+#endif	/* _LINUX_RBTREE_H */

+ 177 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/summary.h

@@ -0,0 +1,177 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->dirty_size += _x; \
+	jeb->free_size -= _x ; jeb->dirty_size += _x; \
+}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->used_size += _x; \
+	jeb->free_size -= _x ; jeb->used_size += _x; \
+}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->wasted_size += _x; \
+	jeb->free_size -= _x ; jeb->wasted_size += _x; \
+}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+	c->free_size -= _x; c->unchecked_size += _x; \
+	jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+}while(0)
+
+#define BLK_STATE_ALLFF		0
+#define BLK_STATE_CLEAN		1
+#define BLK_STATE_PARTDIRTY	2
+#define BLK_STATE_CLEANMARKER	3
+#define BLK_STATE_ALLDIRTY	4
+#define BLK_STATE_BADBLOCK	5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+	jint16_t nodetype;	/* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_flash
+{
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_flash
+{
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_XATR */
+	jint32_t xid;		/* xattr identifier */
+	jint32_t version;	/* version number */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen;	/* node length */
+} __attribute__((packed));
+
+struct jffs2_sum_xref_flash
+{
+	jint16_t nodetype;	/* == JFFS2_NODETYPE_XREF */
+	jint32_t offset;	/* offset on jeb */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+	struct jffs2_sum_unknown_flash u;
+	struct jffs2_sum_inode_flash i;
+	struct jffs2_sum_dirent_flash d;
+	struct jffs2_sum_xattr_flash x;
+	struct jffs2_sum_xref_flash r;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;
+	jint32_t xid;
+	jint32_t version;
+	jint32_t offset;
+	jint32_t totlen;
+} __attribute__((packed));
+
+struct jffs2_sum_xref_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;
+	jint32_t offset;
+} __attribute__((packed));
+
+union jffs2_sum_mem
+{
+	struct jffs2_sum_unknown_mem u;
+	struct jffs2_sum_inode_mem i;
+	struct jffs2_sum_dirent_mem d;
+	struct jffs2_sum_xattr_mem x;
+	struct jffs2_sum_xref_mem r;
+};
+
+struct jffs2_summary
+{
+	uint32_t sum_size;
+	uint32_t sum_num;
+	uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list_head;
+	union jffs2_sum_mem *sum_list_tail;
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;	/* offset of the summary node in the jeb */
+	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
+
+#endif

+ 873 - 0
EVSE/GPL/mtd-utils-2.1.2/jffsX-utils/sumtool.c

@@ -0,0 +1,873 @@
+/*
+ *  sumtool.c
+ *
+ *  Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
+ *                     University of Szeged, Hungary
+ *                2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Overview:
+ *   This is a utility insert summary information into JFFS2 image for
+ *   faster mount time
+ *
+ */
+
+#define PROGRAM_NAME "sumtool"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <crc32.h>
+#include "summary.h"
+#include "common.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0;				/* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1;		/* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1;	/* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0;		/* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; 		/* buffer for inodes */
+static unsigned int data_ofs = 0;	 	/* inode buffer offset */
+
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0;		/* position in the buffer */
+
+int target_endian = __BYTE_ORDER;
+
+static struct option long_options[] = {
+	{"output", 1, NULL, 'o'},
+	{"input", 1, NULL, 'i'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"bigendian", 0, NULL, 'b'},
+	{"littleendian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"pad", 0, NULL, 'p'},
+	{NULL, 0, NULL, 0}
+};
+
+static const char helptext[] =
+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+"Options:\n"
+"  -e, --eraseblock=SIZE     Use erase block size SIZE (default: 64KiB)\n"
+"                            (usually 16KiB on NAND)\n"
+"  -c, --cleanmarker=SIZE    Size of cleanmarker (default 12).\n"
+"                            (usually 16 bytes on NAND, and will be set to\n"
+"                            this value if left at the default 12). Will be\n"
+"                            stored in OOB after each physical page composing\n"
+"                            a physical eraseblock.\n"
+"  -n, --no-cleanmarkers     Don't add a cleanmarker to every eraseblock\n"
+"  -o, --output=FILE         Output to FILE \n"
+"  -i, --input=FILE          Input from FILE \n"
+"  -b, --bigendian           Image is big endian\n"
+"  -l  --littleendian        Image is little endian\n"
+"  -h, --help                Display this help text\n"
+"  -v, --verbose             Verbose operation\n"
+"  -V, --version             Display version information\n"
+"  -p, --pad                 Pad the OUTPUT with 0xFF to the end of the final\n"
+"                            eraseblock\n\n";
+
+
+static unsigned char ffbuf[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+static void setup_cleanmarker(void)
+{
+	cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+static void process_options (int argc, char **argv)
+{
+	int opt,c;
+
+	while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+		switch (opt) {
+			case 'o':
+				if (out_fd != -1)
+					errmsg_die("output filename specified more than once");
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1)
+					sys_errmsg_die("open output file");
+				break;
+
+			case 'i':
+				if (in_fd != -1)
+					errmsg_die("input filename specified more than once");
+				in_fd = open(optarg, O_RDONLY);
+				if (in_fd == -1)
+					sys_errmsg_die("open input file");
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'h':
+				puts(helptext);
+				exit(EXIT_SUCCESS);
+			case '?':
+				puts(helptext);
+				exit(EXIT_FAILURE);
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+
+			case 'e': {
+						  char *next;
+						  unsigned units = 0;
+						  erase_block_size = strtol(optarg, &next, 0);
+						  if (!erase_block_size)
+							  errmsg_die("Unrecognisable erase size\n");
+
+						  if (*next) {
+							  if (!strcmp(next, "KiB")) {
+								  units = 1024;
+							  } else if (!strcmp(next, "MiB")) {
+								  units = 1024 * 1024;
+							  } else {
+								  errmsg_die("Unknown units in erasesize\n");
+							  }
+						  } else {
+							  if (erase_block_size < 0x1000)
+								  units = 1024;
+							  else
+								  units = 1;
+						  }
+						  erase_block_size *= units;
+
+						  /* If it's less than 8KiB, they're not allowed */
+						  if (erase_block_size < 0x2000) {
+							  warnmsg("Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+									erase_block_size);
+							  erase_block_size = 0x2000;
+						  }
+						  break;
+					  }
+
+			case 'n':
+					  add_cleanmarkers = 0;
+					  break;
+			case 'c':
+					  cleanmarker_size = strtol(optarg, NULL, 0);
+
+					  if (cleanmarker_size < sizeof(cleanmarker)) {
+						  errmsg_die("cleanmarker size must be >= 12");
+					  }
+					  if (cleanmarker_size >= erase_block_size) {
+						  errmsg_die("cleanmarker size must be < eraseblock size");
+					  }
+
+					  use_input_cleanmarker_size = 0;
+					  found_cleanmarkers = 1;
+					  setup_cleanmarker();
+
+					  break;
+			case 'p':
+					  padto = 1;
+					  break;
+		}
+	}
+}
+
+
+static void init_buffers(void)
+{
+	data_buffer = xmalloc(erase_block_size);
+	file_buffer = xmalloc(erase_block_size);
+}
+
+static void init_sumlist(void)
+{
+	sum_collected = xzalloc(sizeof(*sum_collected));
+}
+
+static void clean_buffers(void)
+{
+	free(data_buffer);
+	free(file_buffer);
+}
+
+static void clean_sumlist(void)
+{
+	union jffs2_sum_mem *temp;
+
+	if (sum_collected) {
+
+		while (sum_collected->sum_list_head) {
+			temp = sum_collected->sum_list_head;
+			sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+			free(temp);
+			sum_collected->sum_num--;
+		}
+
+		if (sum_collected->sum_num != 0)
+			warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+		free(sum_collected);
+	}
+}
+
+static int load_next_block(void)
+{
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+	file_ofs = 0;
+
+	bareverbose(verbose, "Load next block : %d bytes read\n", ret);
+
+	return ret;
+}
+
+static void write_buff_to_file(void)
+{
+	int ret;
+	int len = data_ofs;
+
+	uint8_t *buf = NULL;
+
+	buf = data_buffer;
+	while (len > 0) {
+		ret = write(out_fd, buf, len);
+
+		if (ret < 0)
+			sys_errmsg_die("write");
+
+		if (ret == 0)
+			sys_errmsg_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+	}
+
+	data_ofs = 0;
+}
+
+static void dump_sum_records(void)
+{
+
+	struct jffs2_raw_summary isum;
+	struct jffs2_sum_marker *sm;
+	union jffs2_sum_mem *temp;
+	jint32_t offset;
+	jint32_t *tpage;
+	void *wpage;
+	int datasize, infosize, padsize;
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+	if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+		return;
+
+	datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_raw_summary) + datasize;
+	padsize = erase_block_size - data_ofs - infosize;
+	infosize += padsize; datasize += padsize;
+	offset = cpu_to_je32(data_ofs);
+
+	tpage = xmalloc(datasize);
+
+	memset(tpage, 0xff, datasize);
+	memset(&isum, 0, sizeof(isum));
+
+	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	isum.totlen = cpu_to_je32(infosize);
+	isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+	isum.padded = cpu_to_je32(0);
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+	} else {
+		isum.cln_mkr = cpu_to_je32(0);
+	}
+
+	isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+	wpage = tpage;
+
+	while (sum_collected->sum_num) {
+		switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE : {
+											struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+											sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+											sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+											sino_ptr->version = sum_collected->sum_list_head->i.version;
+											sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+											sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+											wpage += JFFS2_SUMMARY_INODE_SIZE;
+											break;
+										}
+
+			case JFFS2_NODETYPE_DIRENT : {
+											 struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+											 sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+											 sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+											 sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+											 sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+											 sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+											 sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+											 sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+											 sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+											 memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+													 sum_collected->sum_list_head->d.nsize);
+
+											 wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+											 break;
+										 }
+
+			case JFFS2_NODETYPE_XATTR: {
+										   struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+										   sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
+										   sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
+										   sxattr_ptr->version = sum_collected->sum_list_head->x.version;
+										   sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
+										   sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
+
+										   wpage += JFFS2_SUMMARY_XATTR_SIZE;
+										   break;
+									   }
+
+			case JFFS2_NODETYPE_XREF: {
+										  struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+										  sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
+										  sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
+
+										  wpage += JFFS2_SUMMARY_XREF_SIZE;
+										  break;
+									  }
+
+			default : {
+						  warnmsg("Unknown node type!\n");
+					  }
+		}
+
+		temp = sum_collected->sum_list_head;
+		sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+		free(temp);
+
+		sum_collected->sum_num--;
+	}
+
+	sum_collected->sum_size = 0;
+	sum_collected->sum_num = 0;
+	sum_collected->sum_list_tail = NULL;
+
+	wpage += padsize;
+
+	sm = wpage;
+	sm->offset = offset;
+	sm->magic = magic;
+
+	isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
+	isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
+
+	full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+	full_write(data_buffer + data_ofs, tpage, datasize);
+
+	free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+	memcpy(target_buff, buf, len);
+	data_ofs += len;
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(data_buffer + data_ofs, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword(void)
+{
+	if (data_ofs % 4)
+		full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+	int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+	datasize += (4 - (datasize % 4)) % 4;
+
+	if (data_ofs + req > erase_block_size - datasize) {
+		dump_sum_records();
+		write_buff_to_file();
+	}
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		if (!data_ofs) {
+			full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+static void flush_buffers(void)
+{
+
+	if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+		if (data_ofs != cleanmarker_size) {	/* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data  */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* else just write out inode data */
+				if (padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	} else { /* NO CLEANMARKER */
+		if (data_ofs != 0) { /* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* Else just write out inode data */
+				if(padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	}
+}
+
+static int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+	if (!sum_collected->sum_list_head)
+		sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+	if (sum_collected->sum_list_tail)
+		sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+	sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+	switch (je16_to_cpu(item->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE:
+			sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_DIRENT:
+			sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_XATTR:
+			sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_XREF:
+			sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		default:
+			errmsg_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+	}
+	return 0;
+}
+
+static void add_sum_inode_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_inode_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->i.nodetype;
+	temp->inode = node->i.ino;
+	temp->version = node->i.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->i.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+static void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_dirent_mem *temp = xmalloc(sizeof(*temp) + node->d.nsize);
+
+	temp->nodetype = node->d.nodetype;
+	temp->totlen = node->d.totlen;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->pino = node->d.pino;
+	temp->version = node->d.version;
+	temp->ino = node->d.ino;
+	temp->nsize = node->d.nsize;
+	temp->type = node->d.type;
+	temp->next = NULL;
+
+	memcpy(temp->name,node->d.name,node->d.nsize);
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+static void add_sum_xattr_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_xattr_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->x.nodetype;
+	temp->xid = node->x.xid;
+	temp->version = node->x.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->x.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+static void add_sum_xref_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_xref_mem *temp = xmalloc(sizeof(*temp));
+
+	temp->nodetype = node->r.nodetype;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+static void write_dirent_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+	add_sum_dirent_mem(node);
+	full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+	padword();
+}
+
+
+static void write_inode_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+	add_sum_inode_mem(node);	/* Add inode summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen));	/* Write out the inode to inode_buffer */
+	padword();
+}
+
+static void write_xattr_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
+	add_sum_xattr_mem(node);	/* Add xdatum summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
+	padword();
+}
+
+static void write_xref_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
+	add_sum_xref_mem(node);		/* Add xref summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
+	padword();
+}
+
+static void create_summed_image(int inp_size)
+{
+	uint8_t *p = file_buffer;
+	union jffs2_node_union *node;
+	uint32_t crc, length;
+	uint16_t type;
+	int bitchbitmask = 0;
+	int obsolete;
+	char name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+			if (!bitchbitmask++)
+				warnmsg("Wrong bitmask  at  0x%08zx, 0x%04x\n",
+					p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else {
+			obsolete = 0;
+		}
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			warnmsg("Wrong hdr_crc  at  0x%08zx, 0x%08x instead of 0x%08x\n",
+				p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+			case JFFS2_NODETYPE_INODE:
+				bareverbose(verbose,
+					"%8s Inode      node at 0x%08zx, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+					je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
+					je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					warnmsg("Wrong data_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				write_inode_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				bareverbose(verbose,
+					"%8s Dirent     node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+					je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
+					node->d.nsize, name);
+
+				crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					warnmsg("Wrong node_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					warnmsg("Wrong name_crc at  0x%08zx, 0x%08x instead of 0x%08x\n",
+						p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				write_dirent_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XATTR:
+				if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
+					obsolete = 1;
+				bareverbose(verbose,
+					"%8s Xdatum     node at 0x%08zx, totlen 0x%08x, #xid  %5u, version %5u\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->x.totlen),
+					je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
+				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
+				if (crc != je32_to_cpu(node->x.node_crc)) {
+					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+				length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
+				crc = mtd_crc32(0, node->x.data, length);
+				if (crc != je32_to_cpu(node->x.data_crc)) {
+					warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
+					p += PAD(je32_to_cpu (node->x.totlen));
+					continue;
+				}
+
+				write_xattr_to_buff(node);
+				p += PAD(je32_to_cpu (node->x.totlen));
+				break;
+
+			case JFFS2_NODETYPE_XREF:
+				if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
+					obsolete = 1;
+				bareverbose(verbose,
+					"%8s Xref       node at 0x%08zx, totlen 0x%08x, #ino  %5u, xid     %5u\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu(node->r.totlen),
+					je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
+				crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
+				if (crc != je32_to_cpu(node->r.node_crc)) {
+					warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
+							p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
+					p += PAD(je32_to_cpu (node->r.totlen));
+					continue;
+				}
+
+				write_xref_to_buff(node);
+				p += PAD(je32_to_cpu (node->r.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				bareverbose(verbose,
+					"%8s Cleanmarker     at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+
+				if (!found_cleanmarkers) {
+					found_cleanmarkers = 1;
+
+					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+						cleanmarker_size = je32_to_cpu (node->u.totlen);
+						setup_cleanmarker();
+					}
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				bareverbose(verbose,
+					"%8s Padding    node at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				bareverbose(verbose,
+					"%8s Unknown    node at 0x%08zx, totlen 0x%08x\n",
+					obsolete ? "Obsolete" : "",
+					p - file_buffer, je32_to_cpu (node->u.totlen));
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	process_options(argc,argv);
+
+	if ((in_fd == -1) || (out_fd == -1)) {
+		if(in_fd != -1)
+			close(in_fd);
+		if(out_fd != -1)
+			close(out_fd);
+		fprintf(stderr, "%s", helptext);
+		errmsg_die("You must specify input and output files!\n");
+	}
+
+	init_buffers();
+	init_sumlist();
+
+	while ((ret = load_next_block())) {
+		create_summed_image(ret);
+	}
+
+	flush_buffers();
+	clean_buffers();
+	clean_sumlist();
+
+	if (in_fd != -1)
+		close(in_fd);
+	if (out_fd != -1)
+		close(out_fd);
+
+	return 0;
+}

+ 20 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/LICENSE.libiniparser

@@ -0,0 +1,20 @@
+Copyright (c) 2000-2007 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.

+ 30 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/Makemodule.am

@@ -0,0 +1,30 @@
+libmtd_a_SOURCES = \
+	lib/libmtd.c \
+	lib/libfec.c \
+	lib/common.c \
+	lib/libcrc32.c \
+	lib/libmtd_legacy.c \
+	lib/libmtd_int.h
+
+libmissing_a_SOURCES = \
+	lib/execinfo.c
+
+libubi_a_SOURCES = \
+	lib/libubi.c \
+	lib/libubi_int.h
+
+libubigen_a_SOURCES = \
+	lib/libubigen.c
+
+libscan_a_SOURCES = \
+	lib/libscan.c
+
+libiniparser_a_SOURCES = \
+	lib/libiniparser.c \
+	lib/dictionary.c
+
+EXTRA_DIST += lib/LICENSE.libiniparser
+
+noinst_LIBRARIES += libmtd.a libmissing.a
+noinst_LIBRARIES += libubi.a libubigen.a libscan.a
+noinst_LIBRARIES += libiniparser.a

+ 164 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/common.c

@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains various common stuff.
+ *
+ * Authors: Artem Bityutskiy
+ *          Adrian Hunter
+ */
+
+#define PROGRAM_NAME "mtd-utils"
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "common.h"
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+	if (!str)
+		return 1;
+
+	/* Remove spaces before the specifier */
+	while (*str == ' ' || *str == '\t')
+		str += 1;
+
+	if (!strcmp(str, "KiB"))
+		return 1024;
+	if (!strcmp(str, "MiB"))
+		return 1024 * 1024;
+	if (!strcmp(str, "GiB"))
+		return 1024 * 1024 * 1024;
+
+	return -1;
+}
+
+/**
+ * util_get_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+long long util_get_bytes(const char *str)
+{
+	char *endp;
+	long long bytes = strtoull(str, &endp, 0);
+
+	if (endp == str || bytes < 0) {
+		fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
+		return -1;
+	}
+
+	if (*endp != '\0') {
+		int mult = get_multiplier(endp);
+
+		if (mult == -1) {
+			fprintf(stderr, "bad size specifier: \"%s\" - "
+			        "should be 'KiB', 'MiB' or 'GiB'\n", endp);
+			return -1;
+		}
+		bytes *= mult;
+	}
+
+	return bytes;
+}
+
+/**
+ * util_print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+void util_print_bytes(long long bytes, int bracket)
+{
+	const char *p;
+	int GiB = 1024 * 1024 * 1024;
+	int MiB = 1024 * 1024;
+	int KiB = 1024;
+
+	if (bracket)
+		p = " (";
+	else
+		p = ", ";
+
+	printf("%lld bytes", bytes);
+
+	if (bytes > GiB)
+		printf("%s%lld.%lld GiB", p,
+		       bytes / GiB, bytes % GiB / (GiB / 10));
+	else if (bytes > MiB)
+		printf("%s%lld.%lld MiB", p,
+		        bytes / MiB, bytes % MiB / (MiB / 10));
+	else if (bytes > KiB && bytes != 0)
+		printf("%s%lld.%lld KiB", p,
+		        bytes / KiB, bytes % KiB / (KiB / 10));
+	else
+		return;
+
+	if (bracket)
+		printf(")");
+}
+
+/**
+ * util_srand - randomly seed the standard pseudo-random generator.
+ *
+ * This helper function seeds the standard libc pseudo-random generator with a
+ * more or less random value to make sure the 'rand()' call does not return the
+ * same sequence every time UBI utilities run. Returns zero in case of success
+ * and a %-1 in case of error.
+ */
+int util_srand(void)
+{
+	struct timeval tv;
+	struct timezone tz;
+	unsigned int seed;
+
+	/*
+	 * Just assume that a combination of the PID + current time is a
+	 * reasonably random number.
+	 */
+	if (gettimeofday(&tv, &tz))
+		return -1;
+
+	seed = (unsigned int)tv.tv_sec;
+	seed += (unsigned int)tv.tv_usec;
+	seed *= getpid();
+	seed %= RAND_MAX;
+	srand(seed);
+	return 0;
+}

+ 405 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/dictionary.c

@@ -0,0 +1,405 @@
+/*-------------------------------------------------------------------------*/
+/**
+   @file	dictionary.c
+   @author	N. Devillard
+   @date	Sep 2007
+   @version	$Revision: 1.27 $
+   @brief	Implements a dictionary for string variables.
+
+   This module implements a simple dictionary object, i.e. a list
+   of string/string associations. This object is useful to store e.g.
+   informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+	$Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
+	$Revision: 1.27 $
+*/
+/*---------------------------------------------------------------------------
+   								Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ	1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ	128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY    ((char*)-1)
+
+/*---------------------------------------------------------------------------
+  							Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+    void * newptr ;
+
+    newptr = calloc(2*size, 1);
+    if (newptr==NULL) {
+        return NULL ;
+    }
+    memcpy(newptr, ptr, size);
+    free(ptr);
+    return newptr ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Duplicate a string
+  @param    s String to duplicate
+  @return   Pointer to a newly allocated string, to be freed with free()
+
+  This is a replacement for strdup(). This implementation is provided
+  for systems that do not have it.
+ */
+/*--------------------------------------------------------------------------*/
+static char * xstrdup(char * s)
+{
+    char * t ;
+    if (!s)
+        return NULL ;
+    t = malloc(strlen(s)+1) ;
+    if (t) {
+        strcpy(t,s);
+    }
+    return t ;
+}
+
+/*---------------------------------------------------------------------------
+  							Function codes
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Compute the hash key for a string.
+  @param	key		Character string to use for key.
+  @return	1 unsigned int on at least 32 bits.
+
+  This hash function has been taken from an Article in Dr Dobbs Journal.
+  This is normally a collision-free function, distributing keys evenly.
+  The key is stored anyway in the struct so that collision can be avoided
+  by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key)
+{
+	int			len ;
+	unsigned	hash ;
+	int			i ;
+
+	len = strlen(key);
+	for (hash=0, i=0 ; i<len ; i++) {
+		hash += (unsigned)key[i] ;
+		hash += (hash<<10);
+		hash ^= (hash>>6) ;
+	}
+	hash += (hash <<3);
+	hash ^= (hash >>11);
+	hash += (hash <<15);
+	return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Create a new dictionary object.
+  @param	size	Optional initial size of the dictionary.
+  @return	1 newly allocated dictionary objet.
+
+  This function allocates a new dictionary object of given size and returns
+  it. If you do not know in advance (roughly) the number of entries in the
+  dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size)
+{
+	dictionary	*	d ;
+
+	/* If no size was specified, allocate space for DICTMINSZ */
+	if (size<DICTMINSZ) size=DICTMINSZ ;
+
+	if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+		return NULL;
+	}
+	d->size = size ;
+	d->val  = (char **)calloc(size, sizeof(char*));
+	d->key  = (char **)calloc(size, sizeof(char*));
+	d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+	return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Delete a dictionary object
+  @param	d	dictionary object to deallocate.
+  @return	void
+
+  Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+	int		i ;
+
+	if (d==NULL) return ;
+	for (i=0 ; i<d->size ; i++) {
+		if (d->key[i]!=NULL)
+			free(d->key[i]);
+		if (d->val[i]!=NULL)
+			free(d->val[i]);
+	}
+	free(d->val);
+	free(d->key);
+	free(d->hash);
+	free(d);
+	return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Get a value from a dictionary.
+  @param	d		dictionary object to search.
+  @param	key		Key to look for in the dictionary.
+  @param    def     Default value to return if key not found.
+  @return	1 pointer to internally allocated character string.
+
+  This function locates a key in a dictionary and returns a pointer to its
+  value, or the passed 'def' pointer if no such key can be found in
+  dictionary. The returned character pointer points to data internal to the
+  dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def)
+{
+	unsigned	hash ;
+	int			i ;
+
+	hash = dictionary_hash(key);
+	for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        /* Compare hash */
+		if (hash==d->hash[i]) {
+            /* Compare string, to avoid hash collisions */
+            if (!strcmp(key, d->key[i])) {
+				return d->val[i] ;
+			}
+		}
+	}
+	return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set a value in a dictionary.
+  @param    d       dictionary object to modify.
+  @param    key     Key to modify or add.
+  @param    val     Value to add.
+  @return   int     0 if Ok, anything else otherwise
+
+  If the given key is found in the dictionary, the associated value is
+  replaced by the provided one. If the key cannot be found in the
+  dictionary, it is added to it.
+
+  It is Ok to provide a NULL value for val, but NULL values for the dictionary
+  or the key are considered as errors: the function will return immediately
+  in such a case.
+
+  Notice that if you dictionary_set a variable to NULL, a call to
+  dictionary_get will return a NULL value: the variable will be found, and
+  its value (NULL) is returned. In other words, setting the variable
+  content to NULL is equivalent to deleting the variable from the
+  dictionary. It is not possible (in this implementation) to have a key in
+  the dictionary without value.
+
+  This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, char * key, char * val)
+{
+	int			i ;
+	unsigned	hash ;
+
+	if (d==NULL || key==NULL) return -1 ;
+
+	/* Compute hash for this key */
+	hash = dictionary_hash(key) ;
+	/* Find if value is already in dictionary */
+	if (d->n>0) {
+		for (i=0 ; i<d->size ; i++) {
+            if (d->key[i]==NULL)
+                continue ;
+			if (hash==d->hash[i]) { /* Same hash value */
+				if (!strcmp(key, d->key[i])) {	 /* Same key */
+					/* Found a value: modify and return */
+					if (d->val[i]!=NULL)
+						free(d->val[i]);
+                    d->val[i] = val ? xstrdup(val) : NULL ;
+                    /* Value has been modified: return */
+					return 0 ;
+				}
+			}
+		}
+	}
+	/* Add a new value */
+	/* See if dictionary needs to grow */
+	if (d->n==d->size) {
+
+		/* Reached maximum size: reallocate dictionary */
+		d->val  = (char **)mem_double(d->val,  d->size * sizeof(char*)) ;
+		d->key  = (char **)mem_double(d->key,  d->size * sizeof(char*)) ;
+		d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+        if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
+            /* Cannot grow dictionary */
+            return -1 ;
+        }
+		/* Double size */
+		d->size *= 2 ;
+	}
+
+    /* Insert key in the first empty slot */
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL) {
+            /* Add key here */
+            break ;
+        }
+    }
+	/* Copy key */
+	d->key[i]  = xstrdup(key);
+    d->val[i]  = val ? xstrdup(val) : NULL ;
+	d->hash[i] = hash;
+	d->n ++ ;
+	return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Delete a key in a dictionary
+  @param	d		dictionary object to modify.
+  @param	key		Key to remove.
+  @return   void
+
+  This function deletes a key in a dictionary. Nothing is done if the
+  key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key)
+{
+	unsigned	hash ;
+	int			i ;
+
+	if (key == NULL) {
+		return;
+	}
+
+	hash = dictionary_hash(key);
+	for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        /* Compare hash */
+		if (hash==d->hash[i]) {
+            /* Compare string, to avoid hash collisions */
+            if (!strcmp(key, d->key[i])) {
+                /* Found key */
+                break ;
+			}
+		}
+	}
+    if (i>=d->size)
+        /* Key not found */
+        return ;
+
+    free(d->key[i]);
+    d->key[i] = NULL ;
+    if (d->val[i]!=NULL) {
+        free(d->val[i]);
+        d->val[i] = NULL ;
+    }
+    d->hash[i] = 0 ;
+    d->n -- ;
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Dump a dictionary to an opened file pointer.
+  @param	d	Dictionary to dump
+  @param	f	Opened file pointer.
+  @return	void
+
+  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+  output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out)
+{
+	int		i ;
+
+	if (d==NULL || out==NULL) return ;
+	if (d->n<1) {
+		fprintf(out, "empty dictionary\n");
+		return ;
+	}
+	for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]) {
+            fprintf(out, "%20s\t[%s]\n",
+                    d->key[i],
+                    d->val[i] ? d->val[i] : "UNDEF");
+        }
+	}
+	return ;
+}
+
+
+/* Test code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+	dictionary	*	d ;
+	char	*	val ;
+	int			i ;
+	char		cval[90] ;
+
+	/* Allocate dictionary */
+	printf("allocating...\n");
+	d = dictionary_new(0);
+
+	/* Set values in dictionary */
+	printf("setting %d values...\n", NVALS);
+	for (i=0 ; i<NVALS ; i++) {
+		sprintf(cval, "%04d", i);
+		dictionary_set(d, cval, "salut");
+	}
+	printf("getting %d values...\n", NVALS);
+	for (i=0 ; i<NVALS ; i++) {
+		sprintf(cval, "%04d", i);
+		val = dictionary_get(d, cval, DICT_INVALID_KEY);
+		if (val==DICT_INVALID_KEY) {
+			printf("cannot get value for key [%s]\n", cval);
+		}
+	}
+    printf("unsetting %d values...\n", NVALS);
+	for (i=0 ; i<NVALS ; i++) {
+		sprintf(cval, "%04d", i);
+		dictionary_unset(d, cval);
+	}
+    if (d->n != 0) {
+        printf("error deleting values\n");
+    }
+	printf("deallocating...\n");
+	dictionary_del(d);
+	return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */

+ 28 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/execinfo.c

@@ -0,0 +1,28 @@
+#include "libmissing.h"
+
+#ifndef HAVE_EXECINFO_H
+#define PROGRAM_NAME "libmissing"
+#include "common.h"
+
+int backtrace(void **buffer, int size)
+{
+	void *addr = __builtin_return_address(0);
+	(void)buffer; (void)size;
+
+	errmsg("backtrace() is not implemented. Called from %p", addr);
+	return 0;
+}
+
+char **backtrace_symbols(void *const *buffer, int size)
+{
+	(void)buffer; (void)size;
+	errmsg("backtrace_symbols() is not implemented");
+	return NULL;
+}
+
+void backtrace_symbols_fd(void *const *buffer, int size, int fd)
+{
+	(void)buffer; (void)size; (void)fd;
+	errmsg("backtrace_symbols_fd() is not implemented");
+}
+#endif /* !HAVE_EXECINFO_H */

+ 105 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libcrc32.c

@@ -0,0 +1,105 @@
+/*
+ *  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
+ */
+
+#include <stdint.h>
+#include "crc32.h"
+
+static const uint32_t 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
+};
+
+uint32_t mtd_crc32(uint32_t val, const void *ss, int len)
+{
+	const unsigned char *s = ss;
+
+	while (--len >= 0)
+		val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+	return val;
+}

+ 904 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libfec.c

@@ -0,0 +1,904 @@
+/*
+ * fec.c -- forward error correction based on Vandermonde matrices
+ * 980624
+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
+ *
+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
+ *
+ * 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 AUTHORS ``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 AUTHORS
+ * 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.
+ */
+
+/*
+ * The following parameter defines how many bits are used for
+ * field elements. The code supports any value from 2 to 16
+ * but fastest operation is achieved with 8 bit elements
+ * This is the only parameter you may want to change.
+ */
+#ifndef GF_BITS
+#define GF_BITS  8	/* code over GF(2**GF_BITS) - change to suit */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libfec.h"
+
+/*
+ * stuff used for testing purposes only
+ */
+
+#ifdef	TEST
+#define DEB(x)
+#define DDB(x) x
+#define	DEBUG	0	/* minimal debugging */
+#ifdef	MSDOS
+#include <time.h>
+struct timeval {
+    unsigned long ticks;
+};
+#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
+#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
+#else /* typically, unix systems */
+#include <sys/time.h>
+#define DIFF_T(a,b) \
+	(1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
+#endif
+
+#define TICK(t) \
+	{struct timeval x ; \
+	gettimeofday(&x, NULL) ; \
+	t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
+	}
+#define TOCK(t) \
+	{ unsigned long t1 ; TICK(t1) ; \
+	  if (t1 < t) t = 256000000 + t1 - t ; \
+	  else t = t1 - t ; \
+	  if (t == 0) t = 1 ;}
+
+unsigned long ticks[10];	/* vars for timekeeping */
+#else
+#define DEB(x)
+#define DDB(x)
+#define TICK(x)
+#define TOCK(x)
+#endif /* TEST */
+
+/*
+ * You should not need to change anything beyond this point.
+ * The first part of the file implements linear algebra in GF.
+ *
+ * gf is the type used to store an element of the Galois Field.
+ * Must constain at least GF_BITS bits.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium. We use int whenever have to deal with an
+ * index, since they are generally faster.
+ */
+#if (GF_BITS < 2  && GF_BITS >16)
+#error "GF_BITS must be 2 .. 16"
+#endif
+#if (GF_BITS <= 8)
+typedef unsigned char gf;
+#else
+typedef unsigned short gf;
+#endif
+
+#define	GF_SIZE ((1 << GF_BITS) - 1)	/* powers of \alpha */
+
+/*
+ * Primitive polynomials - see Lin & Costello, Appendix A,
+ * and  Lee & Messerschmitt, p. 453.
+ */
+static const char *allPp[] = {    /* GF_BITS	polynomial		*/
+    NULL,		    /*  0	no code			*/
+    NULL,		    /*  1	no code			*/
+    "111",		    /*  2	1+x+x^2			*/
+    "1101",		    /*  3	1+x+x^3			*/
+    "11001",		    /*  4	1+x+x^4			*/
+    "101001",		    /*  5	1+x^2+x^5		*/
+    "1100001",		    /*  6	1+x+x^6			*/
+    "10010001",		    /*  7	1 + x^3 + x^7		*/
+    "101110001",	    /*  8	1+x^2+x^3+x^4+x^8	*/
+    "1000100001",	    /*  9	1+x^4+x^9		*/
+    "10010000001",	    /* 10	1+x^3+x^10		*/
+    "101000000001",	    /* 11	1+x^2+x^11		*/
+    "1100101000001",	    /* 12	1+x+x^4+x^6+x^12	*/
+    "11011000000001",	    /* 13	1+x+x^3+x^4+x^13	*/
+    "110000100010001",	    /* 14	1+x+x^6+x^10+x^14	*/
+    "1100000000000001",	    /* 15	1+x+x^15		*/
+    "11010000000010001"	    /* 16	1+x+x^3+x^12+x^16	*/
+};
+
+
+/*
+ * To speed up computations, we have tables for logarithm, exponent
+ * and inverse of a number. If GF_BITS <= 8, we use a table for
+ * multiplication as well (it takes 64K, no big deal even on a PDA,
+ * especially because it can be pre-initialized an put into a ROM!),
+ * otherwhise we use a table of logarithms.
+ * In any case the macro gf_mul(x,y) takes care of multiplications.
+ */
+
+static gf gf_exp[2*GF_SIZE];	/* index->poly form conversion table	*/
+static int gf_log[GF_SIZE + 1];	/* Poly->index form conversion table	*/
+static gf inverse[GF_SIZE+1];	/* inverse of field elem.		*/
+				/* inv[\alpha**i]=\alpha**(GF_SIZE-i-1)	*/
+
+/*
+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
+ * without a slow divide.
+ */
+static inline gf
+modnn(int x)
+{
+    while (x >= GF_SIZE) {
+	x -= GF_SIZE;
+	x = (x >> GF_BITS) + (x & GF_SIZE);
+    }
+    return x;
+}
+
+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
+
+/*
+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
+ * faster to use a multiplication table.
+ *
+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
+ * many numbers by the same constant. In this case the first
+ * call sets the constant, and others perform the multiplications.
+ * A value related to the multiplication is held in a local variable
+ * declared with USE_GF_MULC . See usage in addmul1().
+ */
+#if (GF_BITS <= 8)
+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
+
+#define gf_mul(x,y) gf_mul_table[x][y]
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
+
+static void
+init_mul_table(void)
+{
+    int i, j;
+    for (i=0; i< GF_SIZE+1; i++)
+	for (j=0; j< GF_SIZE+1; j++)
+	    gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
+
+    for (j=0; j< GF_SIZE+1; j++)
+	    gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
+}
+#else	/* GF_BITS > 8 */
+static inline gf
+gf_mul(x,y)
+{
+    if ( (x) == 0 || (y)==0 ) return 0;
+
+    return gf_exp[gf_log[x] + gf_log[y] ] ;
+}
+#define init_mul_table()
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
+#endif
+
+/*
+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
+ * Lookup tables:
+ *     index->polynomial form		gf_exp[] contains j= \alpha^i;
+ *     polynomial form -> index form	gf_log[ j = \alpha^i ] = i
+ * \alpha=x is the primitive element of GF(2^m)
+ *
+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
+ * multiplication of two numbers can be resolved without calling modnn
+ */
+
+/*
+ * i use malloc so many times, it is easier to put checks all in
+ * one place.
+ */
+static void *
+my_malloc(int sz, const char *err_string)
+{
+    void *p = malloc( sz );
+    if (p == NULL) {
+	fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
+	exit(1) ;
+    }
+    return p ;
+}
+
+#define NEW_GF_MATRIX(rows, cols) \
+    (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
+
+/*
+ * initialize the data structures used for computations in GF.
+ */
+static void
+generate_gf(void)
+{
+    int i;
+    gf mask;
+    const char *Pp =  allPp[GF_BITS] ;
+
+    mask = 1;	/* x ** 0 = 1 */
+    gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
+    /*
+     * first, generate the (polynomial representation of) powers of \alpha,
+     * which are stored in gf_exp[i] = \alpha ** i .
+     * At the same time build gf_log[gf_exp[i]] = i .
+     * The first GF_BITS powers are simply bits shifted to the left.
+     */
+    for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
+	gf_exp[i] = mask;
+	gf_log[gf_exp[i]] = i;
+	/*
+	 * If Pp[i] == 1 then \alpha ** i occurs in poly-repr
+	 * gf_exp[GF_BITS] = \alpha ** GF_BITS
+	 */
+	if ( Pp[i] == '1' )
+	    gf_exp[GF_BITS] ^= mask;
+    }
+    /*
+     * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
+     * compute its inverse.
+     */
+    gf_log[gf_exp[GF_BITS]] = GF_BITS;
+    /*
+     * Poly-repr of \alpha ** (i+1) is given by poly-repr of
+     * \alpha ** i shifted left one-bit and accounting for any
+     * \alpha ** GF_BITS term that may occur when poly-repr of
+     * \alpha ** i is shifted.
+     */
+    mask = 1 << (GF_BITS - 1 ) ;
+    for (i = GF_BITS + 1; i < GF_SIZE; i++) {
+	if (gf_exp[i - 1] >= mask)
+	    gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
+	else
+	    gf_exp[i] = gf_exp[i - 1] << 1;
+	gf_log[gf_exp[i]] = i;
+    }
+    /*
+     * log(0) is not defined, so use a special value
+     */
+    gf_log[0] =	GF_SIZE ;
+    /* set the extended gf_exp values for fast multiply */
+    for (i = 0 ; i < GF_SIZE ; i++)
+	gf_exp[i + GF_SIZE] = gf_exp[i] ;
+
+    /*
+     * again special cases. 0 has no inverse. This used to
+     * be initialized to GF_SIZE, but it should make no difference
+     * since noone is supposed to read from here.
+     */
+    inverse[0] = 0 ;
+    inverse[1] = 1;
+    for (i=2; i<=GF_SIZE; i++)
+	inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
+}
+
+/*
+ * Various linear algebra operations that i use often.
+ */
+
+/*
+ * addmul() computes dst[] = dst[] + c * src[]
+ * This is used often, so better optimize it! Currently the loop is
+ * unrolled 16 times, a good value for 486 and pentium-class machines.
+ * The case c=0 is also optimized, whereas c=1 is not. These
+ * calls are unfrequent in my typical apps so I did not bother.
+ *
+ * Note that gcc on
+ */
+#define addmul(dst, src, c, sz) \
+    if (c != 0) addmul1(dst, src, c, sz)
+
+#define UNROLL 16 /* 1, 4, 8, 16 */
+static void
+addmul1(gf *dst1, gf *src1, gf c, int sz)
+{
+    USE_GF_MULC ;
+    register gf *dst = dst1, *src = src1 ;
+    gf *lim = &dst[sz - UNROLL + 1] ;
+
+    GF_MULC0(c) ;
+
+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
+    for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
+	GF_ADDMULC( dst[0] , src[0] );
+	GF_ADDMULC( dst[1] , src[1] );
+	GF_ADDMULC( dst[2] , src[2] );
+	GF_ADDMULC( dst[3] , src[3] );
+#if (UNROLL > 4)
+	GF_ADDMULC( dst[4] , src[4] );
+	GF_ADDMULC( dst[5] , src[5] );
+	GF_ADDMULC( dst[6] , src[6] );
+	GF_ADDMULC( dst[7] , src[7] );
+#endif
+#if (UNROLL > 8)
+	GF_ADDMULC( dst[8] , src[8] );
+	GF_ADDMULC( dst[9] , src[9] );
+	GF_ADDMULC( dst[10] , src[10] );
+	GF_ADDMULC( dst[11] , src[11] );
+	GF_ADDMULC( dst[12] , src[12] );
+	GF_ADDMULC( dst[13] , src[13] );
+	GF_ADDMULC( dst[14] , src[14] );
+	GF_ADDMULC( dst[15] , src[15] );
+#endif
+    }
+#endif
+    lim += UNROLL - 1 ;
+    for (; dst < lim; dst++, src++ )		/* final components */
+	GF_ADDMULC( *dst , *src );
+}
+
+/*
+ * computes C = AB where A is n*k, B is k*m, C is n*m
+ */
+static void
+matmul(gf *a, gf *b, gf *c, int n, int k, int m)
+{
+    int row, col, i ;
+
+    for (row = 0; row < n ; row++) {
+	for (col = 0; col < m ; col++) {
+	    gf *pa = &a[ row * k ];
+	    gf *pb = &b[ col ];
+	    gf acc = 0 ;
+	    for (i = 0; i < k ; i++, pa++, pb += m )
+		acc ^= gf_mul( *pa, *pb ) ;
+	    c[ row * m + col ] = acc ;
+	}
+    }
+}
+
+#ifdef DEBUG
+/*
+ * returns 1 if the square matrix is identiy
+ * (only for test)
+ */
+static int
+is_identity(gf *m, int k)
+{
+    int row, col ;
+    for (row=0; row<k; row++)
+	for (col=0; col<k; col++)
+	    if ( (row==col && *m != 1) ||
+		 (row!=col && *m != 0) )
+		 return 0 ;
+	    else
+		m++ ;
+    return 1 ;
+}
+#endif /* debug */
+
+/*
+ * invert_mat() takes a matrix and produces its inverse
+ * k is the size of the matrix.
+ * (Gauss-Jordan, adapted from Numerical Recipes in C)
+ * Return non-zero if singular.
+ */
+DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
+static int
+invert_mat(gf *src, int k)
+{
+    gf c, *p ;
+    int irow, icol, row, col, i, ix ;
+
+    int error = 1 ;
+    int *indxc = my_malloc(k*sizeof(int), "indxc");
+    int *indxr = my_malloc(k*sizeof(int), "indxr");
+    int *ipiv = my_malloc(k*sizeof(int), "ipiv");
+    gf *id_row = NEW_GF_MATRIX(1, k);
+    gf *temp_row = NEW_GF_MATRIX(1, k);
+
+    memset(id_row, '\0', k*sizeof(gf));
+    DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
+    /*
+     * ipiv marks elements already used as pivots.
+     */
+    for (i = 0; i < k ; i++)
+	ipiv[i] = 0 ;
+
+    for (col = 0; col < k ; col++) {
+	gf *pivot_row ;
+	/*
+	 * Zeroing column 'col', look for a non-zero element.
+	 * First try on the diagonal, if it fails, look elsewhere.
+	 */
+	irow = icol = -1 ;
+	if (ipiv[col] != 1 && src[col*k + col] != 0) {
+	    irow = col ;
+	    icol = col ;
+	    goto found_piv ;
+	}
+	for (row = 0 ; row < k ; row++) {
+	    if (ipiv[row] != 1) {
+		for (ix = 0 ; ix < k ; ix++) {
+		    DEB( pivloops++ ; )
+		    if (ipiv[ix] == 0) {
+			if (src[row*k + ix] != 0) {
+			    irow = row ;
+			    icol = ix ;
+			    goto found_piv ;
+			}
+		    } else if (ipiv[ix] > 1) {
+			fprintf(stderr, "singular matrix\n");
+			goto fail ;
+		    }
+		}
+	    }
+	}
+	if (icol == -1) {
+	    fprintf(stderr, "XXX pivot not found!\n");
+	    goto fail ;
+	}
+found_piv:
+	++(ipiv[icol]) ;
+	/*
+	 * swap rows irow and icol, so afterwards the diagonal
+	 * element will be correct. Rarely done, not worth
+	 * optimizing.
+	 */
+	if (irow != icol) {
+	    for (ix = 0 ; ix < k ; ix++ ) {
+		SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
+	    }
+	}
+	indxr[col] = irow ;
+	indxc[col] = icol ;
+	pivot_row = &src[icol*k] ;
+	c = pivot_row[icol] ;
+	if (c == 0) {
+	    fprintf(stderr, "singular matrix 2\n");
+	    goto fail ;
+	}
+	if (c != 1 ) { /* otherwhise this is a NOP */
+	    /*
+	     * this is done often , but optimizing is not so
+	     * fruitful, at least in the obvious ways (unrolling)
+	     */
+	    DEB( pivswaps++ ; )
+	    c = inverse[ c ] ;
+	    pivot_row[icol] = 1 ;
+	    for (ix = 0 ; ix < k ; ix++ )
+		pivot_row[ix] = gf_mul(c, pivot_row[ix] );
+	}
+	/*
+	 * from all rows, remove multiples of the selected row
+	 * to zero the relevant entry (in fact, the entry is not zero
+	 * because we know it must be zero).
+	 * (Here, if we know that the pivot_row is the identity,
+	 * we can optimize the addmul).
+	 */
+	id_row[icol] = 1;
+	if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
+	    for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
+		if (ix != icol) {
+		    c = p[icol] ;
+		    p[icol] = 0 ;
+		    addmul(p, pivot_row, c, k );
+		}
+	    }
+	}
+	id_row[icol] = 0;
+    } /* done all columns */
+    for (col = k-1 ; col >= 0 ; col-- ) {
+	if (indxr[col] <0 || indxr[col] >= k)
+	    fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
+	else if (indxc[col] <0 || indxc[col] >= k)
+	    fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
+	else
+	if (indxr[col] != indxc[col] ) {
+	    for (row = 0 ; row < k ; row++ ) {
+		SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
+	    }
+	}
+    }
+    error = 0 ;
+fail:
+    free(indxc);
+    free(indxr);
+    free(ipiv);
+    free(id_row);
+    free(temp_row);
+    return error ;
+}
+
+/*
+ * fast code for inverting a vandermonde matrix.
+ * XXX NOTE: It assumes that the matrix
+ * is not singular and _IS_ a vandermonde matrix. Only uses
+ * the second column of the matrix, containing the p_i's.
+ *
+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
+ * largely revised for my purposes.
+ * p = coefficients of the matrix (p_i)
+ * q = values of the polynomial (known)
+ */
+
+static int
+invert_vdm(gf *src, int k)
+{
+    int i, j, row, col ;
+    gf *b, *c, *p;
+    gf t, xx ;
+
+    if (k == 1) 	/* degenerate case, matrix must be p^0 = 1 */
+	return 0 ;
+    /*
+     * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
+     * b holds the coefficient for the matrix inversion
+     */
+    c = NEW_GF_MATRIX(1, k);
+    b = NEW_GF_MATRIX(1, k);
+
+    p = NEW_GF_MATRIX(1, k);
+
+    for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
+	c[i] = 0 ;
+	p[i] = src[j] ;    /* p[i] */
+    }
+    /*
+     * construct coeffs. recursively. We know c[k] = 1 (implicit)
+     * and start P_0 = x - p_0, then at each stage multiply by
+     * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
+     * After k steps we are done.
+     */
+    c[k-1] = p[0] ;	/* really -p(0), but x = -x in GF(2^m) */
+    for (i = 1 ; i < k ; i++ ) {
+	gf p_i = p[i] ; /* see above comment */
+	for (j = k-1  - ( i - 1 ) ; j < k-1 ; j++ )
+	    c[j] ^= gf_mul( p_i, c[j+1] ) ;
+	c[k-1] ^= p_i ;
+    }
+
+    for (row = 0 ; row < k ; row++ ) {
+	/*
+	 * synthetic division etc.
+	 */
+	xx = p[row] ;
+	t = 1 ;
+	b[k-1] = 1 ; /* this is in fact c[k] */
+	for (i = k-2 ; i >= 0 ; i-- ) {
+	    b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
+	    t = gf_mul(xx, t) ^ b[i] ;
+	}
+	for (col = 0 ; col < k ; col++ )
+	    src[col*k + row] = gf_mul(inverse[t], b[col] );
+    }
+    free(c) ;
+    free(b) ;
+    free(p) ;
+    return 0 ;
+}
+
+static int fec_initialized = 0 ;
+static void
+init_fec(void)
+{
+    TICK(ticks[0]);
+    generate_gf();
+    TOCK(ticks[0]);
+    DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
+    TICK(ticks[0]);
+    init_mul_table();
+    TOCK(ticks[0]);
+    DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
+    fec_initialized = 1 ;
+}
+
+/*
+ * This section contains the proper FEC encoding/decoding routines.
+ * The encoding matrix is computed starting with a Vandermonde matrix,
+ * and then transforming it into a systematic matrix.
+ */
+
+#define FEC_MAGIC	0xFECC0DEC
+
+struct fec_parms {
+    unsigned long magic ;
+    int k, n ;		/* parameters of the code */
+    gf *enc_matrix ;
+} ;
+#define COMP_FEC_MAGIC(fec) \
+	(((FEC_MAGIC ^ (fec)->k) ^ (fec)->n) ^ (unsigned long)((fec)->enc_matrix))
+
+void
+fec_free(struct fec_parms *p)
+{
+    if (p==NULL || p->magic != COMP_FEC_MAGIC(p)) {
+	fprintf(stderr, "bad parameters to fec_free\n");
+	return ;
+    }
+    free(p->enc_matrix);
+    free(p);
+}
+
+/*
+ * create a new encoder, returning a descriptor. This contains k,n and
+ * the encoding matrix.
+ */
+struct fec_parms *
+fec_new(int k, int n)
+{
+    int row, col ;
+    gf *p, *tmp_m ;
+
+    struct fec_parms *retval ;
+
+    if (fec_initialized == 0)
+	init_fec();
+
+    if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
+	fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
+		k, n, GF_SIZE );
+	return NULL ;
+    }
+    retval = my_malloc(sizeof(struct fec_parms), "new_code");
+    retval->k = k ;
+    retval->n = n ;
+    retval->enc_matrix = NEW_GF_MATRIX(n, k);
+    retval->magic = COMP_FEC_MAGIC(retval);
+    tmp_m = NEW_GF_MATRIX(n, k);
+    /*
+     * fill the matrix with powers of field elements, starting from 0.
+     * The first row is special, cannot be computed with exp. table.
+     */
+    tmp_m[0] = 1 ;
+    for (col = 1; col < k ; col++)
+	tmp_m[col] = 0 ;
+    for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
+	for ( col = 0 ; col < k ; col ++ )
+	    p[col] = gf_exp[modnn(row*col)];
+    }
+
+    /*
+     * quick code to build systematic matrix: invert the top
+     * k*k vandermonde matrix, multiply right the bottom n-k rows
+     * by the inverse, and construct the identity matrix at the top.
+     */
+    TICK(ticks[3]);
+    invert_vdm(tmp_m, k); /* much faster than invert_mat */
+    matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
+    /*
+     * the upper matrix is I so do not bother with a slow multiply
+     */
+    memset(retval->enc_matrix, '\0', k*k*sizeof(gf) );
+    for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
+	*p = 1 ;
+    free(tmp_m);
+    TOCK(ticks[3]);
+
+    DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
+	    ticks[3]);)
+    DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
+    return retval ;
+}
+
+/*
+ * fec_encode accepts as input pointers to n data packets of size sz,
+ * and produces as output a packet pointed to by fec, computed
+ * with index "index".
+ */
+void
+fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
+{
+    int i, k = code->k ;
+    gf *p ;
+
+    if (GF_BITS > 8)
+	sz /= 2 ;
+
+    if (index < k)
+         memcpy(fec, src[index], sz*sizeof(gf) ) ;
+    else if (index < code->n) {
+	p = &(code->enc_matrix[index*k] );
+	memset(fec, '\0', sz*sizeof(gf));
+	for (i = 0; i < k ; i++)
+	    addmul(fec, src[i], p[i], sz ) ;
+    } else
+	fprintf(stderr, "Invalid index %d (max %d)\n",
+	    index, code->n - 1 );
+}
+
+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz)
+{
+    int i, k = code->k ;
+    gf *p ;
+
+    if (GF_BITS > 8)
+	sz /= 2 ;
+
+    if (index < k)
+	    memcpy(fec, src + (index * sz), sz*sizeof(gf) ) ;
+    else if (index < code->n) {
+	p = &(code->enc_matrix[index*k] );
+	memset(fec, '\0', sz*sizeof(gf));
+	for (i = 0; i < k ; i++)
+	    addmul(fec, src + (i * sz), p[i], sz ) ;
+    } else
+	fprintf(stderr, "Invalid index %d (max %d)\n",
+	    index, code->n - 1 );
+}
+/*
+ * shuffle move src packets in their position
+ */
+static int
+shuffle(gf *pkt[], int index[], int k)
+{
+    int i;
+
+    for ( i = 0 ; i < k ; ) {
+	if (index[i] >= k || index[i] == i)
+	    i++ ;
+	else {
+	    /*
+	     * put pkt in the right position (first check for conflicts).
+	     */
+	    int c = index[i] ;
+
+	    if (index[c] == c) {
+		DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
+		return 1 ;
+	    }
+	    SWAP(index[i], index[c], int) ;
+	    SWAP(pkt[i], pkt[c], gf *) ;
+	}
+    }
+    DEB( /* just test that it works... */
+    for ( i = 0 ; i < k ; i++ ) {
+	if (index[i] < k && index[i] != i) {
+	    fprintf(stderr, "shuffle: after\n");
+	    for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
+	    fprintf(stderr, "\n");
+	    return 1 ;
+	}
+    }
+    )
+    return 0 ;
+}
+
+/*
+ * build_decode_matrix constructs the encoding matrix given the
+ * indexes. The matrix must be already allocated as
+ * a vector of k*k elements, in row-major order
+ */
+static gf *
+build_decode_matrix(struct fec_parms *code, int index[])
+{
+    int i , k = code->k ;
+    gf *p, *matrix = NEW_GF_MATRIX(k, k);
+
+    TICK(ticks[9]);
+    for (i = 0, p = matrix ; i < k ; i++, p += k ) {
+#if 1 /* this is simply an optimization, not very useful indeed */
+	if (index[i] < k) {
+	    memset(p, '\0', k*sizeof(gf) );
+	    p[i] = 1 ;
+	} else
+#endif
+	if (index[i] < code->n )
+	    memcpy(p,  &(code->enc_matrix[index[i]*k]), k*sizeof(gf) );
+	else {
+	    fprintf(stderr, "decode: invalid index %d (max %d)\n",
+		index[i], code->n - 1 );
+	    free(matrix) ;
+	    return NULL ;
+	}
+    }
+    TICK(ticks[9]);
+    if (invert_mat(matrix, k)) {
+	free(matrix);
+	matrix = NULL ;
+    }
+    TOCK(ticks[9]);
+    return matrix ;
+}
+
+/*
+ * fec_decode receives as input a vector of packets, the indexes of
+ * packets, and produces the correct vector as output.
+ *
+ * Input:
+ *	code: pointer to code descriptor
+ *	pkt:  pointers to received packets. They are modified
+ *	      to store the output packets (in place)
+ *	index: pointer to packet indexes (modified)
+ *	sz:    size of each packet
+ */
+int
+fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
+{
+    gf *m_dec ;
+    gf **new_pkt ;
+    int row, col , k = code->k ;
+
+    if (GF_BITS > 8)
+	sz /= 2 ;
+
+    if (shuffle(pkt, index, k))	/* error if true */
+	return 1 ;
+    m_dec = build_decode_matrix(code, index);
+
+    if (m_dec == NULL)
+	return 1 ; /* error */
+    /*
+     * do the actual decoding
+     */
+    new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" );
+    for (row = 0 ; row < k ; row++ ) {
+	if (index[row] >= k) {
+	    new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" );
+	    memset(new_pkt[row], '\0', sz * sizeof(gf) ) ;
+	    for (col = 0 ; col < k ; col++ )
+		addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
+	}
+    }
+    /*
+     * move pkts to their final destination
+     */
+    for (row = 0 ; row < k ; row++ ) {
+	if (index[row] >= k) {
+	    memcpy(pkt[row], new_pkt[row], sz*sizeof(gf));
+	    free(new_pkt[row]);
+	}
+    }
+    free(new_pkt);
+    free(m_dec);
+
+    return 0;
+}
+
+/*********** end of FEC code -- beginning of test code ************/
+
+#if (TEST || DEBUG)
+void
+test_gf(void)
+{
+    int i ;
+    /*
+     * test gf tables. Sufficiently tested...
+     */
+    for (i=0; i<= GF_SIZE; i++) {
+        if (gf_exp[gf_log[i]] != i)
+	    fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n",
+		i, gf_log[i], gf_exp[gf_log[i]]);
+
+        if (i != 0 && gf_mul(i, inverse[i]) != 1)
+	    fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n",
+		i, inverse[i], gf_mul(i, inverse[i]) );
+	if (gf_mul(0,i) != 0)
+	    fprintf(stderr, "bad mul table 0,%d\n",i);
+	if (gf_mul(i,0) != 0)
+	    fprintf(stderr, "bad mul table %d,0\n",i);
+    }
+}
+#endif /* TEST */

+ 606 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libiniparser.c

@@ -0,0 +1,606 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    iniparser.c
+   @author  N. Devillard
+   @date    Sep 2007
+   @version 3.0
+   @brief   Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*
+    $Id: iniparser.c,v 2.18 2008-01-03 18:35:39 ndevilla Exp $
+    $Revision: 2.18 $
+    $Date: 2008-01-03 18:35:39 $
+*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include <libiniparser.h>
+
+/*---------------------------- Defines -------------------------------------*/
+#define ASCIILINESZ         (1024)
+#define INI_INVALID_KEY     ((char*)-1)
+
+/*---------------------------------------------------------------------------
+                        Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+    LINE_UNPROCESSED,
+    LINE_ERROR,
+    LINE_EMPTY,
+    LINE_COMMENT,
+    LINE_SECTION,
+    LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Convert a string to lowercase.
+  @param	s	String to convert.
+  @return	ptr to statically allocated string.
+
+  This function returns a pointer to a statically allocated string
+  containing a lowercased version of the input string. Do not free
+  or modify the returned string! Since the returned string is statically
+  allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strlwc(const char * s)
+{
+    static char l[ASCIILINESZ+1];
+    int i ;
+
+    if (s==NULL) return NULL ;
+    memset(l, 0, ASCIILINESZ+1);
+    i=0 ;
+    while (s[i] && i<ASCIILINESZ) {
+        l[i] = (char)tolower((int)s[i]);
+        i++ ;
+    }
+    l[ASCIILINESZ]=(char)0;
+    return l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Remove blanks at the beginning and the end of a string.
+  @param	s	String to parse.
+  @return	ptr to statically allocated string.
+
+  This function returns a pointer to a statically allocated string,
+  which is identical to the input string, except that all blank
+  characters at the end and the beg. of the string have been removed.
+  Do not free or modify the returned string! Since the returned string
+  is statically allocated, it will be modified at each function call
+  (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strstrip(char * s)
+{
+    static char l[ASCIILINESZ+1];
+	char * last ;
+
+    if (s==NULL) return NULL ;
+
+	while (isspace((int)*s) && *s) s++;
+	memset(l, 0, ASCIILINESZ+1);
+	strcpy(l, s);
+	last = l + strlen(l);
+	while (last > l) {
+		if (!isspace((int)*(last-1)))
+			break ;
+		last -- ;
+	}
+	*last = (char)0;
+	return (char*)l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get number of sections in a dictionary
+  @param    d   Dictionary to examine
+  @return   int Number of sections found in dictionary
+
+  This function returns the number of sections found in a dictionary.
+  The test to recognize sections is done on the string stored in the
+  dictionary: a section name is given as "section" whereas a key is
+  stored as "section:key", thus the test looks for entries that do not
+  contain a colon.
+
+  This clearly fails in the case a section name contains a colon, but
+  this should simply be avoided.
+
+  This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(dictionary * d)
+{
+    int i ;
+    int nsec ;
+
+    if (d==NULL) return -1 ;
+    nsec=0 ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (strchr(d->key[i], ':')==NULL) {
+            nsec ++ ;
+        }
+    }
+    return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get name for section n in a dictionary.
+  @param    d   Dictionary to examine
+  @param    n   Section number (from 0 to nsec-1).
+  @return   Pointer to char string
+
+  This function locates the n-th section in a dictionary and returns
+  its name as a pointer to a string statically allocated inside the
+  dictionary. Do not free or modify the returned string!
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getsecname(dictionary * d, int n)
+{
+    int i ;
+    int foundsec ;
+
+    if (d==NULL || n<0) return NULL ;
+    foundsec=0 ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (strchr(d->key[i], ':')==NULL) {
+            foundsec++ ;
+            if (foundsec>n)
+                break ;
+        }
+    }
+    if (foundsec<=n) {
+        return NULL ;
+    }
+    return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump.
+  @param    f   Opened file pointer to dump to.
+  @return   void
+
+  This function prints out the contents of a dictionary, one element by
+  line, onto the provided file pointer. It is OK to specify @c stderr
+  or @c stdout as output files. This function is meant for debugging
+  purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+    int     i ;
+
+    if (d==NULL || f==NULL) return ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (d->val[i]!=NULL) {
+            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+        } else {
+            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+        }
+    }
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given dictionary into a loadable ini file.
+  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+    int     i, j ;
+    char    keym[ASCIILINESZ+1];
+    int     nsec ;
+    char *  secname ;
+    int     seclen ;
+
+    if (d==NULL || f==NULL) return ;
+
+    nsec = iniparser_getnsec(d);
+    if (nsec<1) {
+        /* No section in file: dump all keys as they are */
+        for (i=0 ; i<d->size ; i++) {
+            if (d->key[i]==NULL)
+                continue ;
+            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+        }
+        return ;
+    }
+    for (i=0 ; i<nsec ; i++) {
+        secname = iniparser_getsecname(d, i) ;
+        seclen  = (int)strlen(secname);
+        fprintf(f, "\n[%s]\n", secname);
+        sprintf(keym, "%s:", secname);
+        for (j=0 ; j<d->size ; j++) {
+            if (d->key[j]==NULL)
+                continue ;
+            if (!strncmp(d->key[j], keym, seclen+1)) {
+                fprintf(f,
+                        "%-30s = %s\n",
+                        d->key[j]+seclen+1,
+                        d->val[j] ? d->val[j] : "");
+            }
+        }
+    }
+    fprintf(f, "\n");
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    key     Key string to look for
+  @param    def     Default value to return if key not found.
+  @return   pointer to statically allocated character string
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the pointer passed as 'def' is returned.
+  The returned char pointer is pointing to a string allocated in
+  the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+    char * lc_key ;
+    char * sval ;
+
+    if (d==NULL || key==NULL)
+        return def ;
+
+    lc_key = strlwc(key);
+    sval = dictionary_get(d, lc_key, def);
+    return sval ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  "42"      ->  42
+  "042"     ->  34 (octal -> decimal)
+  "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+
+  Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+    char    *   str ;
+
+    str = iniparser_getstring(d, key, INI_INVALID_KEY);
+    if (str==INI_INVALID_KEY) return notfound ;
+    return (int)strtol(str, NULL, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a boolean
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  A true boolean is found if one of the following is matched:
+
+  - A string starting with 'y'
+  - A string starting with 'Y'
+  - A string starting with 't'
+  - A string starting with 'T'
+  - A string starting with '1'
+
+  A false boolean is found if one of the following is matched:
+
+  - A string starting with 'n'
+  - A string starting with 'N'
+  - A string starting with 'f'
+  - A string starting with 'F'
+  - A string starting with '0'
+
+  The notfound value returned if no boolean is identified, does not
+  necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+    char    *   c ;
+    int         ret ;
+
+    c = iniparser_getstring(d, key, INI_INVALID_KEY);
+    if (c==INI_INVALID_KEY) return notfound ;
+    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+        ret = 1 ;
+    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+        ret = 0 ;
+    } else {
+        ret = notfound ;
+    }
+    return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Finds out if a given entry exists in a dictionary
+  @param    ini     Dictionary to search
+  @param    entry   Name of the entry to look for
+  @return   integer 1 if entry exists, 0 otherwise
+
+  Finds out if a given entry exists in the dictionary. Since sections
+  are stored as keys with NULL associated values, this is the only way
+  of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(
+    dictionary  *   ini,
+    char        *   entry
+)
+{
+    int found=0 ;
+    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+        found = 1 ;
+    }
+    return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete an entry in a dictionary
+  @param    ini     Dictionary to modify
+  @param    entry   Entry to delete (entry name)
+  @return   void
+
+  If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry)
+{
+    dictionary_unset(ini, strlwc(entry));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief	Load a single line from an INI file
+  @param    input_line  Input line, may be concatenated multi-line input
+  @param    section     Output space to store section
+  @param    key         Output space to store key
+  @param    value       Output space to store value
+  @return   line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+    char * input_line,
+    char * section,
+    char * key,
+    char * value)
+{
+    line_status sta ;
+    char        line[ASCIILINESZ+1];
+    int         len ;
+
+    strcpy(line, strstrip(input_line));
+    len = (int)strlen(line);
+
+    sta = LINE_UNPROCESSED ;
+    if (len<1) {
+        /* Empty line */
+        sta = LINE_EMPTY ;
+    } else if (line[0]=='#') {
+        /* Comment line */
+        sta = LINE_COMMENT ;
+    } else if (line[0]=='[' && line[len-1]==']') {
+        /* Section name */
+        sscanf(line, "[%[^]]", section);
+        strcpy(section, strstrip(section));
+        strcpy(section, strlwc(section));
+        sta = LINE_SECTION ;
+    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
+           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
+           ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) {
+        /* Usual key=value, with or without comments */
+        strcpy(key, strstrip(key));
+        strcpy(key, strlwc(key));
+        strcpy(value, strstrip(value));
+        /*
+         * sscanf cannot handle '' or "" as empty values
+         * this is done here
+         */
+        if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
+            value[0]=0 ;
+        }
+        sta = LINE_VALUE ;
+    } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
+           ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
+        /*
+         * Special cases:
+         * key=
+         * key=;
+         * key=#
+         */
+        strcpy(key, strstrip(key));
+        strcpy(key, strlwc(key));
+        value[0]=0 ;
+        sta = LINE_VALUE ;
+    } else {
+        /* Generate syntax error */
+        sta = LINE_ERROR ;
+    }
+    return sta ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Parse an ini file and return an allocated dictionary object
+  @param    ininame Name of the ini file to read.
+  @return   Pointer to newly allocated dictionary
+
+  This is the parser for ini files. This function is called, providing
+  the name of the file to be read. It returns a dictionary object that
+  should not be accessed directly, but through accessor functions
+  instead.
+
+  The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+    FILE * in ;
+
+    char line    [ASCIILINESZ+1] ;
+    char section [ASCIILINESZ+1] ;
+    char key     [ASCIILINESZ+1] ;
+    char tmp     [ASCIILINESZ+1] ;
+    char val     [ASCIILINESZ+1] ;
+
+    int  last=0 ;
+    int  len ;
+    int  lineno=0 ;
+    int  errs=0;
+
+    dictionary * dict ;
+
+    if ((in=fopen(ininame, "r"))==NULL) {
+        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+        return NULL ;
+    }
+
+    dict = dictionary_new(0) ;
+    if (!dict) {
+        fclose(in);
+        return NULL ;
+    }
+
+    memset(line,    0, ASCIILINESZ);
+    memset(section, 0, ASCIILINESZ);
+    memset(key,     0, ASCIILINESZ);
+    memset(val,     0, ASCIILINESZ);
+    last=0 ;
+
+    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+        lineno++ ;
+        len = (int)strlen(line)-1;
+        /* Safety check against buffer overflows */
+        if (line[len]!='\n') {
+            fprintf(stderr,
+                    "iniparser: input line too long in %s (%d)\n",
+                    ininame,
+                    lineno);
+            dictionary_del(dict);
+            fclose(in);
+            return NULL ;
+        }
+        /* Get rid of \n and spaces at end of line */
+        while ((len>=0) &&
+                ((line[len]=='\n') || (isspace(line[len])))) {
+            line[len]=0 ;
+            len-- ;
+        }
+        /* Detect multi-line */
+        if (line[len]=='\\') {
+            /* Multi-line value */
+            last=len ;
+            continue ;
+        } else {
+            last=0 ;
+        }
+        switch (iniparser_line(line, section, key, val)) {
+            case LINE_EMPTY:
+            case LINE_COMMENT:
+            break ;
+
+            case LINE_SECTION:
+            errs = dictionary_set(dict, section, NULL);
+            break ;
+
+            case LINE_VALUE:
+            sprintf(tmp, "%s:%s", section, key);
+            errs = dictionary_set(dict, tmp, val) ;
+            break ;
+
+            case LINE_ERROR:
+            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
+                    ininame,
+                    lineno);
+            fprintf(stderr, "-> %s\n", line);
+            errs++ ;
+            break;
+
+            default:
+            break ;
+        }
+        memset(line, 0, ASCIILINESZ);
+        last=0;
+        if (errs<0) {
+            fprintf(stderr, "iniparser: memory allocation failure\n");
+            break ;
+        }
+    }
+    if (errs) {
+        dictionary_del(dict);
+        dict = NULL ;
+    }
+    fclose(in);
+    return dict ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Free all memory associated to an ini dictionary
+  @param    d Dictionary to free
+  @return   void
+
+  Free all memory associated to an ini dictionary.
+  It is mandatory to call this function before the dictionary object
+  gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+    dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */

+ 1356 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libmtd.c

@@ -0,0 +1,1356 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+
+#include "libmtd_int.h"
+#include "common.h"
+
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+	char *n;
+	size_t len1 = strlen(path);
+	size_t len2 = strlen(name);
+
+	n = xmalloc(len1 + len2 + 2);
+
+	memcpy(n, path, len1);
+	if (n[len1 - 1] != '/')
+		n[len1++] = '/';
+
+	memcpy(n + len1, name, len2 + 1);
+	return n;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+	int fd, rd, tmp, tmp1;
+
+	fd = open(file, O_RDONLY | O_CLOEXEC);
+	if (fd == -1)
+		return -1;
+
+	rd = read(fd, buf, buf_len);
+	if (rd == -1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+
+	if (rd == buf_len) {
+		errmsg("contents of \"%s\" is too long", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	((char *)buf)[rd] = '\0';
+
+	/* Make sure all data is read */
+	tmp1 = read(fd, &tmp, 1);
+	if (tmp1 == 1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+	if (tmp1) {
+		errmsg("file \"%s\" contains too much data (> %d bytes)",
+		       file, buf_len);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (close(fd)) {
+		sys_errmsg("close failed on \"%s\"", file);
+		return -1;
+	}
+
+	return rd;
+
+out_error:
+	close(fd);
+	return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of success, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+	int ret;
+	char buf[50];
+
+	ret = read_data(file, buf, 50);
+	if (ret < 0)
+		return ret;
+
+	ret = sscanf(buf, "%d:%d\n", major, minor);
+	if (ret != 2) {
+		errno = EINVAL;
+		return errmsg("\"%s\" does not have major:minor format", file);
+	}
+
+	if (*major < 0 || *minor < 0) {
+		errno = EINVAL;
+		return errmsg("bad major:minor %d:%d in \"%s\"",
+			      *major, *minor, file);
+	}
+
+	return 0;
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an MTD device.
+ * @lib: libmtd descriptor
+ * @mtd_num: MTD device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of success and %-1 in case of failure.
+ */
+static int dev_get_major(struct libmtd *lib, int mtd_num, int *major, int *minor)
+{
+	char file[strlen(lib->mtd_dev) + 50];
+
+	sprintf(file, lib->mtd_dev, mtd_num);
+	return read_major(file, major, minor);
+}
+
+/**
+ * dev_read_data - read data from an MTD device's sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int dev_read_data(const char *patt, int mtd_num, void *buf, int buf_len)
+{
+	char file[strlen(patt) + 100];
+
+	sprintf(file, patt, mtd_num);
+	return read_data(file, buf, buf_len);
+}
+
+/**
+ * read_hex_ll - read a hex 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as hexadecimal
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_hex_ll(const char *file, long long *value)
+{
+	int fd, rd;
+	char buf[50];
+
+	fd = open(file, O_RDONLY | O_CLOEXEC);
+	if (fd == -1)
+		return -1;
+
+	rd = read(fd, buf, sizeof(buf));
+	if (rd == -1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+	if (rd == sizeof(buf)) {
+		errmsg("contents of \"%s\" is too long", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+	buf[rd] = '\0';
+
+	*value = 0;
+	if (sscanf(buf, "%llx\n", value) != 1) {
+		errmsg("cannot read integer from \"%s\"\n", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (*value < 0) {
+		errmsg("negative value %lld in \"%s\"", *value, file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (close(fd))
+		return sys_errmsg("close failed on \"%s\"", file);
+
+	return 0;
+
+out_error:
+	close(fd);
+	return -1;
+}
+
+/**
+ * read_pos_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_pos_ll(const char *file, long long *value)
+{
+	int fd, rd;
+	char buf[50];
+	memset(buf, 0, 50);
+
+	fd = open(file, O_RDONLY | O_CLOEXEC);
+	if (fd == -1)
+		return -1;
+
+	rd = read(fd, buf, 50);
+	if (rd == -1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+	if (rd == 50) {
+		errmsg("contents of \"%s\" is too long", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	*value = 0;
+	if (sscanf(buf, "%lld\n", value) != 1) {
+		errmsg("cannot read integer from \"%s\"\n", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (*value < 0) {
+		errmsg("negative value %lld in \"%s\"", *value, file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (close(fd))
+		return sys_errmsg("close failed on \"%s\"", file);
+
+	return 0;
+
+out_error:
+	close(fd);
+	return -1;
+}
+
+/**
+ * read_hex_int - read an 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_hex_int(const char *file, int *value)
+{
+	long long res;
+
+	if (read_hex_ll(file, &res))
+		return -1;
+
+	/* Make sure the value has correct range */
+	if (res > INT_MAX || res < INT_MIN) {
+		errmsg("value %lld read from file \"%s\" is out of range",
+		       res, file);
+		errno = EINVAL;
+		return -1;
+	}
+
+	*value = res;
+	return 0;
+}
+
+/**
+ * read_pos_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_pos_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_pos_int(const char *file, int *value)
+{
+	long long res;
+
+	if (read_pos_ll(file, &res))
+		return -1;
+
+	/* Make sure the value is not too big */
+	if (res > INT_MAX) {
+		errmsg("value %lld read from file \"%s\" is out of range",
+		       res, file);
+		errno = EINVAL;
+		return -1;
+	}
+
+	*value = res;
+	return 0;
+}
+
+/**
+ * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_hex_int(const char *patt, int mtd_num, int *value)
+{
+	char file[strlen(patt) + 50];
+
+	sprintf(file, patt, mtd_num);
+	return read_hex_int(file, value);
+}
+
+/**
+ * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_pos_int(const char *patt, int mtd_num, int *value)
+{
+	char file[strlen(patt) + 50];
+
+	sprintf(file, patt, mtd_num);
+	return read_pos_int(file, value);
+}
+
+/**
+ * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file.
+ * @patt: file pattern to read from
+ * @mtd_num: MTD device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_pos_ll(const char *patt, int mtd_num, long long *value)
+{
+	char file[strlen(patt) + 50];
+
+	sprintf(file, patt, mtd_num);
+	return read_pos_ll(file, value);
+}
+
+/**
+ * type_str2int - convert MTD device type to integer.
+ * @str: MTD device type string to convert
+ *
+ * This function converts MTD device type string @str, read from sysfs, into an
+ * integer.
+ */
+static int type_str2int(const char *str)
+{
+	if (!strcmp(str, "nand"))
+		return MTD_NANDFLASH;
+	if (!strcmp(str, "mlc-nand"))
+		return MTD_MLCNANDFLASH;
+	if (!strcmp(str, "nor"))
+		return MTD_NORFLASH;
+	if (!strcmp(str, "rom"))
+		return MTD_ROM;
+	if (!strcmp(str, "absent"))
+		return MTD_ABSENT;
+	if (!strcmp(str, "dataflash"))
+		return MTD_DATAFLASH;
+	if (!strcmp(str, "ram"))
+		return MTD_RAM;
+	if (!strcmp(str, "ubi"))
+		return MTD_UBIVOLUME;
+	return -1;
+}
+
+/**
+ * dev_node2num - find MTD device number by its character device node.
+ * @lib: MTD library descriptor
+ * @node: name of the MTD device node
+ * @mtd_num: MTD device number is returned here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_node2num(struct libmtd *lib, const char *node, int *mtd_num)
+{
+	struct stat st;
+	int i, mjr, mnr;
+	struct mtd_info info;
+
+	if (stat(node, &st))
+		return sys_errmsg("cannot get information about \"%s\"", node);
+
+	if (!S_ISCHR(st.st_mode)) {
+		errmsg("\"%s\" is not a character device", node);
+		errno = EINVAL;
+		return -1;
+	}
+
+	mjr = major(st.st_rdev);
+	mnr = minor(st.st_rdev);
+
+	if (mtd_get_info((libmtd_t *)lib, &info))
+		return -1;
+
+	for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
+		int mjr1, mnr1, ret;
+
+		ret = dev_get_major(lib, i, &mjr1, &mnr1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			if (!errno)
+				break;
+			return -1;
+		}
+
+		if (mjr1 == mjr && mnr1 == mnr) {
+			errno = 0;
+			*mtd_num = i;
+			return 0;
+		}
+	}
+
+	errno = ENODEV;
+	return -1;
+}
+
+/**
+ * sysfs_is_supported - check whether the MTD sub-system supports MTD.
+ * @lib: MTD library descriptor
+ *
+ * The Linux kernel MTD subsystem gained sysfs support starting from kernel
+ * 2.6.30 and libmtd tries to use sysfs interface if possible, because the NAND
+ * sub-page size is available there (and not available at all in pre-sysfs
+ * kernels).
+ *
+ * Very old kernels did not have "/sys/class/mtd" directory. Not very old
+ * kernels (e.g., 2.6.29) did have "/sys/class/mtd/mtdX" directories, by there
+ * were no files there, e.g., the "name" file was not present. So all we can do
+ * is to check for a "/sys/class/mtd/mtdX/name" file. But this is not a
+ * reliable check, because if this is a new system with no MTD devices - we'll
+ * treat it as a pre-sysfs system.
+ */
+static int sysfs_is_supported(struct libmtd *lib)
+{
+	int fd, num = -1;
+	DIR *sysfs_mtd;
+	char file[strlen(lib->mtd_name) + 10];
+
+	sysfs_mtd = opendir(lib->sysfs_mtd);
+	if (!sysfs_mtd) {
+		if (errno == ENOENT) {
+			errno = 0;
+			return 0;
+		}
+		return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
+	}
+
+	/*
+	 * First of all find an "mtdX" directory. This is needed because there
+	 * may be, for example, mtd1 but no mtd0.
+	 */
+	while (1) {
+		int ret, mtd_num;
+		char tmp_buf[256];
+		struct dirent *dirent;
+
+		dirent = readdir(sysfs_mtd);
+		if (!dirent)
+			break;
+
+		if (strlen(dirent->d_name) >= 255) {
+			errmsg("invalid entry in %s: \"%s\"",
+			       lib->sysfs_mtd, dirent->d_name);
+			errno = EINVAL;
+			closedir(sysfs_mtd);
+			return -1;
+		}
+
+		ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
+			     &mtd_num, tmp_buf);
+		if (ret == 1) {
+			num = mtd_num;
+			break;
+		}
+	}
+
+	if (closedir(sysfs_mtd))
+		return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
+
+	if (num == -1)
+		/* No mtd device, treat this as pre-sysfs system */
+		return 0;
+
+	sprintf(file, lib->mtd_name, num);
+	fd = open(file, O_RDONLY | O_CLOEXEC);
+	if (fd == -1)
+		return 0;
+
+	if (close(fd)) {
+		sys_errmsg("close failed on \"%s\"", file);
+		return -1;
+	}
+
+	return 1;
+}
+
+libmtd_t libmtd_open(void)
+{
+	struct libmtd *lib;
+
+	lib = xzalloc(sizeof(*lib));
+
+	lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN;
+
+	lib->sysfs_mtd = mkpath(SYSFS_ROOT, SYSFS_MTD);
+	if (!lib->sysfs_mtd)
+		goto out_error;
+
+	lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT);
+	if (!lib->mtd)
+		goto out_error;
+
+	lib->mtd_name = mkpath(lib->mtd, MTD_NAME);
+	if (!lib->mtd_name)
+		goto out_error;
+
+	if (!sysfs_is_supported(lib)) {
+		free(lib->mtd);
+		free(lib->sysfs_mtd);
+		free(lib->mtd_name);
+		lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;
+
+		if (!legacy_procfs_is_supported()) {
+			free(lib);
+			lib = NULL;
+		}
+		return lib;
+	}
+
+	lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);
+	if (!lib->mtd_dev)
+		goto out_error;
+
+	lib->mtd_type = mkpath(lib->mtd, MTD_TYPE);
+	if (!lib->mtd_type)
+		goto out_error;
+
+	lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE);
+	if (!lib->mtd_eb_size)
+		goto out_error;
+
+	lib->mtd_size = mkpath(lib->mtd, MTD_SIZE);
+	if (!lib->mtd_size)
+		goto out_error;
+
+	lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE);
+	if (!lib->mtd_min_io_size)
+		goto out_error;
+
+	lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE);
+	if (!lib->mtd_subpage_size)
+		goto out_error;
+
+	lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE);
+	if (!lib->mtd_oob_size)
+		goto out_error;
+
+	lib->mtd_oobavail = mkpath(lib->mtd, MTD_OOBAVAIL);
+	if (!lib->mtd_oobavail)
+		goto out_error;
+
+	lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT);
+	if (!lib->mtd_region_cnt)
+		goto out_error;
+
+	lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS);
+	if (!lib->mtd_flags)
+		goto out_error;
+
+	lib->sysfs_supported = 1;
+	return lib;
+
+out_error:
+	libmtd_close((libmtd_t)lib);
+	return NULL;
+}
+
+void libmtd_close(libmtd_t desc)
+{
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	free(lib->mtd_flags);
+	free(lib->mtd_region_cnt);
+	free(lib->mtd_oob_size);
+	free(lib->mtd_oobavail);
+	free(lib->mtd_subpage_size);
+	free(lib->mtd_min_io_size);
+	free(lib->mtd_size);
+	free(lib->mtd_eb_size);
+	free(lib->mtd_type);
+	free(lib->mtd_dev);
+	free(lib->mtd_name);
+	free(lib->mtd);
+	free(lib->sysfs_mtd);
+	free(lib);
+}
+
+int mtd_dev_present(libmtd_t desc, int mtd_num) {
+	struct stat st;
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	if (!lib->sysfs_supported) {
+		return legacy_dev_present(mtd_num) == 1;
+	} else {
+		char file[strlen(lib->mtd) + 10];
+
+		sprintf(file, lib->mtd, mtd_num);
+		return !stat(file, &st);
+	}
+}
+
+int mtd_get_info(libmtd_t desc, struct mtd_info *info)
+{
+	DIR *sysfs_mtd;
+	struct dirent *dirent;
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	memset(info, 0, sizeof(struct mtd_info));
+
+	if (!lib->sysfs_supported)
+		return legacy_mtd_get_info(info);
+
+	info->sysfs_supported = 1;
+
+	/*
+	 * We have to scan the MTD sysfs directory to identify how many MTD
+	 * devices are present.
+	 */
+	sysfs_mtd = opendir(lib->sysfs_mtd);
+	if (!sysfs_mtd)
+		return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
+
+	info->lowest_mtd_num = INT_MAX;
+	while (1) {
+		int mtd_num, ret;
+		char tmp_buf[256];
+
+		errno = 0;
+		dirent = readdir(sysfs_mtd);
+		if (!dirent)
+			break;
+
+		if (strlen(dirent->d_name) >= 255) {
+			errmsg("invalid entry in %s: \"%s\"",
+			       lib->sysfs_mtd, dirent->d_name);
+			errno = EINVAL;
+			goto out_close;
+		}
+
+		ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
+			     &mtd_num, tmp_buf);
+		if (ret == 1) {
+			info->mtd_dev_cnt += 1;
+			if (mtd_num > info->highest_mtd_num)
+				info->highest_mtd_num = mtd_num;
+			if (mtd_num < info->lowest_mtd_num)
+				info->lowest_mtd_num = mtd_num;
+		}
+	}
+
+	if (!dirent && errno) {
+		sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd);
+		goto out_close;
+	}
+
+	if (closedir(sysfs_mtd))
+		return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
+
+	if (info->lowest_mtd_num == INT_MAX)
+		info->lowest_mtd_num = 0;
+
+	return 0;
+
+out_close:
+	closedir(sysfs_mtd);
+	return -1;
+}
+
+int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd)
+{
+	int ret;
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	memset(mtd, 0, sizeof(struct mtd_dev_info));
+	mtd->mtd_num = mtd_num;
+
+	if (!mtd_dev_present(desc, mtd_num)) {
+		errno = ENODEV;
+		return -1;
+	} else if (!lib->sysfs_supported)
+		return legacy_get_dev_info1(mtd_num, mtd);
+
+	if (dev_get_major(lib, mtd_num, &mtd->major, &mtd->minor))
+		return -1;
+
+	ret = dev_read_data(lib->mtd_name, mtd_num, (char *)&mtd->name,
+			    MTD_NAME_MAX + 1);
+	if (ret < 0)
+		return -1;
+	((char *)mtd->name)[ret - 1] = '\0';
+
+	ret = dev_read_data(lib->mtd_type, mtd_num, (char *)&mtd->type_str,
+			    MTD_TYPE_MAX + 1);
+	if (ret < 0)
+		return -1;
+	((char *)mtd->type_str)[ret - 1] = '\0';
+
+	if (dev_read_pos_int(lib->mtd_eb_size, mtd_num, &mtd->eb_size))
+		return -1;
+	if (dev_read_pos_ll(lib->mtd_size, mtd_num, &mtd->size))
+		return -1;
+	if (dev_read_pos_int(lib->mtd_min_io_size, mtd_num, &mtd->min_io_size))
+		return -1;
+	if (dev_read_pos_int(lib->mtd_subpage_size, mtd_num, &mtd->subpage_size))
+		return -1;
+	if (dev_read_pos_int(lib->mtd_oob_size, mtd_num, &mtd->oob_size))
+		return -1;
+	if (dev_read_pos_int(lib->mtd_oobavail, mtd_num, &mtd->oobavail)) {
+		/*
+		 * Fail to access oobavail sysfs file,
+		 * try ioctl ECCGETLAYOUT. */
+		mtd->oobavail = legacy_get_mtd_oobavail1(mtd_num);
+		/* Set 0 as default if can not get valid ecc layout */
+		if (mtd->oobavail < 0)
+			mtd->oobavail = 0;
+	}
+	if (dev_read_pos_int(lib->mtd_region_cnt, mtd_num, &mtd->region_cnt))
+		return -1;
+	if (dev_read_hex_int(lib->mtd_flags, mtd_num, &ret))
+		return -1;
+	mtd->writable = !!(ret & MTD_WRITEABLE);
+
+	mtd->eb_cnt = mtd->size / mtd->eb_size;
+	mtd->type = type_str2int(mtd->type_str);
+	mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH ||
+				mtd->type == MTD_MLCNANDFLASH);
+
+	return 0;
+}
+
+int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)
+{
+	int mtd_num;
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	if (!lib->sysfs_supported)
+		return legacy_get_dev_info(node, mtd);
+
+	if (dev_node2num(lib, node, &mtd_num))
+		return -1;
+
+	return mtd_get_dev_info1(desc, mtd_num, mtd);
+}
+
+static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
+				  const char *sreq)
+{
+	return sys_errmsg("%s ioctl failed for eraseblock %d (mtd%d)",
+			  sreq, eb, mtd->mtd_num);
+}
+
+static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
+{
+	if (eb < 0 || eb >= mtd->eb_cnt) {
+		errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+		       eb, mtd->mtd_num, mtd->eb_cnt);
+		errno = EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
+static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
+		     const char *sreq)
+{
+	int ret;
+	struct erase_info_user ei;
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	ei.start = eb * mtd->eb_size;
+	ei.length = mtd->eb_size;
+
+	ret = ioctl(fd, req, &ei);
+	if (ret < 0)
+		return mtd_ioctl_error(mtd, eb, sreq);
+
+	return 0;
+}
+#define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req)
+
+int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	return mtd_xlock(mtd, fd, eb, MEMLOCK);
+}
+
+int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	return mtd_xlock(mtd, fd, eb, MEMUNLOCK);
+}
+
+int mtd_erase_multi(libmtd_t desc, const struct mtd_dev_info *mtd,
+			int fd, int eb, int blocks)
+{
+	int ret;
+	struct libmtd *lib = (struct libmtd *)desc;
+	struct erase_info_user64 ei64;
+	struct erase_info_user ei;
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	ret = mtd_valid_erase_block(mtd, eb + blocks - 1);
+	if (ret)
+		return ret;
+
+	ei64.start = (__u64)eb * mtd->eb_size;
+	ei64.length = (__u64)mtd->eb_size * blocks;
+
+	if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
+	    lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
+		ret = ioctl(fd, MEMERASE64, &ei64);
+		if (ret == 0)
+			return ret;
+
+		if (errno != ENOTTY ||
+		    lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN)
+			return mtd_ioctl_error(mtd, eb, "MEMERASE64");
+
+		/*
+		 * MEMERASE64 support was added in kernel version 2.6.31, so
+		 * probably we are working with older kernel and this ioctl is
+		 * not supported.
+		 */
+		lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
+	}
+
+	if (ei64.start + ei64.length > 0xFFFFFFFF) {
+		errmsg("this system can address only %u eraseblocks",
+		       0xFFFFFFFFU / mtd->eb_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	ei.start = ei64.start;
+	ei.length = ei64.length;
+	ret = ioctl(fd, MEMERASE, &ei);
+	if (ret < 0)
+		return mtd_ioctl_error(mtd, eb, "MEMERASE");
+	return 0;
+}
+
+int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	return mtd_erase_multi(desc, mtd, fd, eb, 1);
+}
+
+int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo)
+{
+	int ret;
+
+	if (regidx < 0) {
+		errno = ENODEV;
+		return -1;
+	}
+
+	reginfo->regionindex = regidx;
+
+	ret = ioctl(fd, MEMGETREGIONINFO, reginfo);
+	if (ret < 0)
+		return sys_errmsg("%s ioctl failed for erase region %d",
+			"MEMGETREGIONINFO", regidx);
+
+	return 0;
+}
+
+int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	int ret;
+	erase_info_t ei;
+
+	ei.start = eb * mtd->eb_size;
+	ei.length = mtd->eb_size;
+
+	ret = ioctl(fd, MEMISLOCKED, &ei);
+	if (ret < 0) {
+		if (errno != ENOTTY && errno != EOPNOTSUPP)
+			return mtd_ioctl_error(mtd, eb, "MEMISLOCKED");
+		else
+			errno = EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %0 if there are only @patt bytes in @buf, and %-1 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		if (((const uint8_t *)buf)[i] != patt)
+			return -1;
+	return 0;
+}
+
+int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	int err, i, patt_count;
+	void *buf;
+
+	normsg("run torture test for PEB %d", eb);
+	patt_count = ARRAY_SIZE(patterns);
+
+	buf = xmalloc(mtd->eb_size);
+
+	for (i = 0; i < patt_count; i++) {
+		err = mtd_erase(desc, mtd, fd, eb);
+		if (err)
+			goto out;
+
+		/* Make sure the PEB contains only 0xFF bytes */
+		err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+		if (err)
+			goto out;
+
+		err = check_pattern(buf, 0xFF, mtd->eb_size);
+		if (err) {
+			errmsg("erased PEB %d, but a non-0xFF byte found", eb);
+			errno = EIO;
+			goto out;
+		}
+
+		/* Write a pattern and check it */
+		memset(buf, patterns[i], mtd->eb_size);
+		err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL,
+				0, 0);
+		if (err)
+			goto out;
+
+		memset(buf, ~patterns[i], mtd->eb_size);
+		err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
+		if (err)
+			goto out;
+
+		err = check_pattern(buf, patterns[i], mtd->eb_size);
+		if (err) {
+			errmsg("pattern %x checking failed for PEB %d",
+				patterns[i], eb);
+			errno = EIO;
+			goto out;
+		}
+	}
+
+	err = 0;
+	normsg("PEB %d passed torture test, do not mark it a bad", eb);
+
+out:
+	free(buf);
+	return err;
+}
+
+int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	int ret;
+	loff_t seek;
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	if (!mtd->bb_allowed)
+		return 0;
+
+	seek = (loff_t)eb * mtd->eb_size;
+	ret = ioctl(fd, MEMGETBADBLOCK, &seek);
+	if (ret == -1)
+		return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
+	return ret;
+}
+
+int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
+{
+	int ret;
+	loff_t seek;
+
+	if (!mtd->bb_allowed) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	seek = (loff_t)eb * mtd->eb_size;
+	ret = ioctl(fd, MEMSETBADBLOCK, &seek);
+	if (ret == -1)
+		return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
+	return 0;
+}
+
+int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+	     void *buf, int len)
+{
+	int ret, rd = 0;
+	off_t seek;
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	if (offs < 0 || offs + len > mtd->eb_size) {
+		errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+		       offs, len, mtd->mtd_num, mtd->eb_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Seek to the beginning of the eraseblock */
+	seek = (off_t)eb * mtd->eb_size + offs;
+	if (lseek(fd, seek, SEEK_SET) != seek)
+		return sys_errmsg("cannot seek mtd%d to offset %lld",
+				  mtd->mtd_num, (long long)seek);
+
+	while (rd < len) {
+		ret = read(fd, buf + rd, len - rd);
+		if (ret < 0)
+			return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
+					  len - rd, mtd->mtd_num, eb, offs + rd);
+		rd += ret;
+	}
+
+	return 0;
+}
+
+static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd,
+				  int ooblen, void *oob) {
+	struct nand_oobinfo old_oobinfo;
+	int start, len;
+	uint8_t *tmp_buf;
+
+	/* Read the current oob info */
+	if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo))
+		return sys_errmsg("MEMGETOOBSEL failed");
+
+	tmp_buf = malloc(ooblen);
+	memcpy(tmp_buf, oob, ooblen);
+
+	/*
+	 * We use autoplacement and have the oobinfo with the autoplacement
+	 * information from the kernel available
+	 */
+	if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+		int i, tags_pos = 0;
+		for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
+			/* Set the reserved bytes to 0xff */
+			start = old_oobinfo.oobfree[i][0];
+			len = old_oobinfo.oobfree[i][1];
+			memcpy(oob + start, tmp_buf + tags_pos, len);
+			tags_pos += len;
+		}
+	} else {
+		/* Set at least the ecc byte positions to 0xff */
+		start = old_oobinfo.eccbytes;
+		len = mtd->oob_size - start;
+		memcpy(oob + start, tmp_buf + start, len);
+	}
+
+	free(tmp_buf);
+	return 0;
+}
+
+int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
+	      int offs, void *data, int len, void *oob, int ooblen,
+	      uint8_t mode)
+{
+	int ret;
+	off_t seek;
+	struct mtd_write_req ops;
+	memset(&ops, 0, sizeof(ops));
+
+	ret = mtd_valid_erase_block(mtd, eb);
+	if (ret)
+		return ret;
+
+	if (offs < 0 || offs + len > mtd->eb_size) {
+		errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+		       offs, len, mtd->mtd_num, mtd->eb_size);
+		errno = EINVAL;
+		return -1;
+	}
+	if (offs % mtd->subpage_size) {
+		errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+		       offs, mtd->mtd_num, mtd->subpage_size);
+		errno = EINVAL;
+		return -1;
+	}
+	if (len % mtd->subpage_size) {
+		errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
+		       len, mtd->mtd_num, mtd->subpage_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Calculate seek address */
+	seek = (off_t)eb * mtd->eb_size + offs;
+
+	if (oob) {
+		ops.start = seek;
+		ops.len = len;
+		ops.ooblen = ooblen;
+		ops.usr_data = (uint64_t)(unsigned long)data;
+		ops.usr_oob = (uint64_t)(unsigned long)oob;
+		ops.mode = mode;
+
+		ret = ioctl(fd, MEMWRITE, &ops);
+		if (ret == 0)
+			return 0;
+		else if (errno != ENOTTY && errno != EOPNOTSUPP)
+			return mtd_ioctl_error(mtd, eb, "MEMWRITE");
+
+		/* Fall back to old OOB ioctl() if necessary */
+		if (mode == MTD_OPS_AUTO_OOB)
+			if (legacy_auto_oob_layout(mtd, fd, ooblen, oob))
+				return -1;
+		if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0)
+			return sys_errmsg("cannot write to OOB");
+	}
+	if (data) {
+		/* Seek to the beginning of the eraseblock */
+		if (lseek(fd, seek, SEEK_SET) != seek)
+			return sys_errmsg("cannot seek mtd%d to offset %lld",
+					mtd->mtd_num, (long long)seek);
+		ret = write(fd, data, len);
+		if (ret != len)
+			return sys_errmsg("cannot write %d bytes to mtd%d "
+					  "(eraseblock %d, offset %d)",
+					  len, mtd->mtd_num, eb, offs);
+	}
+
+	return 0;
+}
+
+static int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+		     uint64_t start, uint64_t length, void *data,
+		     unsigned int cmd64, unsigned int cmd)
+{
+	int ret, oob_offs;
+	struct mtd_oob_buf64 oob64;
+	struct mtd_oob_buf oob;
+	unsigned long long max_offs;
+	const char *cmd64_str, *cmd_str;
+	struct libmtd *lib = (struct libmtd *)desc;
+	memset(&oob64, 0, sizeof(oob64));
+	memset(&oob, 0, sizeof(oob));
+
+	if (cmd64 ==  MEMREADOOB64) {
+		cmd64_str = "MEMREADOOB64";
+		cmd_str   = "MEMREADOOB";
+	} else {
+		cmd64_str = "MEMWRITEOOB64";
+		cmd_str   = "MEMWRITEOOB";
+	}
+
+	max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size;
+	if (start >= max_offs) {
+		errmsg("bad page address %" PRIu64 ", mtd%d has %d eraseblocks (%llu bytes)",
+		       start, mtd->mtd_num, mtd->eb_cnt, max_offs);
+		errno = EINVAL;
+		return -1;
+	}
+
+	oob_offs = start & (mtd->min_io_size - 1);
+	if (oob_offs + length > mtd->oob_size || length == 0) {
+		errmsg("Cannot write %" PRIu64 " OOB bytes to address %" PRIu64 " (OOB offset %u) - mtd%d OOB size is only %d bytes",
+		       length, start, oob_offs, mtd->mtd_num,  mtd->oob_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	oob64.start = start;
+	oob64.length = length;
+	oob64.usr_ptr = (uint64_t)(unsigned long)data;
+
+	if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
+	    lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
+		ret = ioctl(fd, cmd64, &oob64);
+		if (ret == 0)
+			return ret;
+
+		if (errno != ENOTTY ||
+		    lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) {
+			sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
+				   cmd64_str, mtd->mtd_num, start, start / mtd->eb_size);
+		}
+
+		/*
+		 * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel
+		 * version 2.6.31, so probably we are working with older kernel
+		 * and these ioctls are not supported.
+		 */
+		lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
+	}
+
+	if (oob64.start > 0xFFFFFFFFULL) {
+		errmsg("this system can address only up to address %lu",
+		       0xFFFFFFFFUL);
+		errno = EINVAL;
+		return -1;
+	}
+
+	oob.start = oob64.start;
+	oob.length = oob64.length;
+	oob.ptr = data;
+
+	ret = ioctl(fd, cmd, &oob);
+	if (ret < 0)
+		sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
+			   cmd_str, mtd->mtd_num, start, start / mtd->eb_size);
+	return ret;
+}
+
+int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+		 uint64_t start, uint64_t length, void *data)
+{
+	return do_oob_op(desc, mtd, fd, start, length, data,
+			 MEMREADOOB64, MEMREADOOB);
+}
+
+int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
+		  uint64_t start, uint64_t length, void *data)
+{
+	return do_oob_op(desc, mtd, fd, start, length, data,
+			 MEMWRITEOOB64, MEMWRITEOOB);
+}
+
+int mtd_probe_node(libmtd_t desc, const char *node)
+{
+	struct stat st;
+	struct mtd_info info;
+	int i, mjr, mnr;
+	struct libmtd *lib = (struct libmtd *)desc;
+
+	if (stat(node, &st))
+		return sys_errmsg("cannot get information about \"%s\"", node);
+
+	if (!S_ISCHR(st.st_mode)) {
+		errmsg("\"%s\" is not a character device", node);
+		errno = EINVAL;
+		return -1;
+	}
+
+	mjr = major(st.st_rdev);
+	mnr = minor(st.st_rdev);
+
+	if (mtd_get_info((libmtd_t *)lib, &info))
+		return -1;
+
+	if (!lib->sysfs_supported)
+		return 0;
+
+	for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
+		int mjr1, mnr1, ret;
+
+		ret = dev_get_major(lib, i, &mjr1, &mnr1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			if (!errno)
+				break;
+			return -1;
+		}
+
+		if (mjr1 == mjr && mnr1 == mnr)
+			return 1;
+	}
+
+	errno = 0;
+	return -1;
+}

+ 116 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libmtd_int.h

@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#ifndef __LIBMTD_INT_H__
+#define __LIBMTD_INT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROGRAM_NAME "libmtd"
+
+#ifndef SYSFS_ROOT
+#define SYSFS_ROOT "/sys"
+#endif
+
+#define SYSFS_MTD        "class/mtd"
+#define MTD_NAME_PATT    "mtd%d"
+#define MTD_DEV          "dev"
+#define MTD_NAME         "name"
+#define MTD_TYPE         "type"
+#define MTD_EB_SIZE      "erasesize"
+#define MTD_SIZE         "size"
+#define MTD_MIN_IO_SIZE  "writesize"
+#define MTD_SUBPAGE_SIZE "subpagesize"
+#define MTD_OOB_SIZE     "oobsize"
+#define MTD_OOBAVAIL     "oobavail"
+#define MTD_REGION_CNT   "numeraseregions"
+#define MTD_FLAGS        "flags"
+
+#define OFFS64_IOCTLS_UNKNOWN       0
+#define OFFS64_IOCTLS_NOT_SUPPORTED 1
+#define OFFS64_IOCTLS_SUPPORTED     2
+
+/**
+ * libmtd - MTD library description data structure.
+ * @sysfs_mtd: MTD directory in sysfs
+ * @mtd: MTD device sysfs directory pattern
+ * @mtd_dev: MTD device major/minor numbers file pattern
+ * @mtd_name: MTD device name file pattern
+ * @mtd_type: MTD device type file pattern
+ * @mtd_eb_size: MTD device eraseblock size file pattern
+ * @mtd_size: MTD device size file pattern
+ * @mtd_min_io_size: minimum I/O unit size file pattern
+ * @mtd_subpage_size: sub-page size file pattern
+ * @mtd_oob_size: MTD device OOB size file pattern
+ * @mtd_oobavail: MTD device free OOB size file pattern
+ * @mtd_region_cnt: count of additional erase regions file pattern
+ * @mtd_flags: MTD device flags file pattern
+ * @sysfs_supported: non-zero if sysfs is supported by MTD
+ * @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64,
+ *                 %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are
+ *                 supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and
+ *                 %OFFS64_IOCTLS_UNKNOWN if it is not known yet;
+ *
+ *  Note, we cannot find out whether 64-bit ioctls are supported by MTD when we
+ *  are initializing the library, because this requires an MTD device node.
+ *  Indeed, we have to actually call the ioctl and check for %ENOTTY to find
+ *  out whether it is supported or not.
+ *
+ *  Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and
+ *  initialize it later, when corresponding libmtd function is used, and when
+ *  we actually have a device node and can invoke an ioctl command on it.
+ */
+struct libmtd
+{
+	char *sysfs_mtd;
+	char *mtd;
+	char *mtd_dev;
+	char *mtd_name;
+	char *mtd_type;
+	char *mtd_eb_size;
+	char *mtd_size;
+	char *mtd_min_io_size;
+	char *mtd_subpage_size;
+	char *mtd_oob_size;
+	char *mtd_oobavail;
+	char *mtd_region_cnt;
+	char *mtd_flags;
+	unsigned int sysfs_supported:1;
+	unsigned int offs64_ioctls:2;
+};
+
+int legacy_procfs_is_supported(void);
+int legacy_dev_present(int mtd_num);
+int legacy_mtd_get_info(struct mtd_info *info);
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
+int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
+int legacy_get_mtd_oobavail(const char *node);
+int legacy_get_mtd_oobavail1(int mtd_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBMTD_INT_H__ */

+ 430 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libmtd_legacy.c

@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * This file  is part of the MTD library. Implements pre-2.6.30 kernels support,
+ * where MTD did not have sysfs interface. The main limitation of the old
+ * kernels was that the sub-page size was not exported to user-space, so it was
+ * not possible to get sub-page size.
+ */
+
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include <libmtd.h>
+#include "libmtd_int.h"
+#include "common.h"
+
+#define MTD_PROC_FILE "/proc/mtd"
+#define MTD_DEV_PATT  "/dev/mtd%d"
+#define MTD_DEV_MAJOR 90
+
+#define PROC_MTD_FIRST     "dev:    size   erasesize  name\n"
+#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
+#define PROC_MTD_MAX_LEN   4096
+#define PROC_MTD_PATT      "mtd%d: %llx %x"
+
+/**
+ * struct proc_parse_info - /proc/mtd parsing information.
+ * @mtd_num: MTD device number
+ * @size: device size
+ * @eb_size: eraseblock size
+ * @name: device name
+ * @buf: contents of /proc/mtd
+ * @data_size: how much data was read into @buf
+ * @next: next string in @buf to parse
+ */
+struct proc_parse_info
+{
+	int mtd_num;
+	long long size;
+	char name[MTD_NAME_MAX + 1];
+	int eb_size;
+	char *buf;
+	int data_size;
+	char *next;
+};
+
+static int proc_parse_start(struct proc_parse_info *pi)
+{
+	int fd, ret;
+
+	fd = open(MTD_PROC_FILE, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	pi->buf = xmalloc(PROC_MTD_MAX_LEN);
+
+	ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
+	if (ret == -1) {
+		sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
+		goto out_free;
+	}
+
+	if (ret < PROC_MTD_FIRST_LEN ||
+	    memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
+		errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
+		       PROC_MTD_FIRST);
+		goto out_free;
+	}
+
+	pi->data_size = ret;
+	pi->next = pi->buf + PROC_MTD_FIRST_LEN;
+
+	close(fd);
+	return 0;
+
+out_free:
+	free(pi->buf);
+	close(fd);
+	return -1;
+}
+
+static int proc_parse_next(struct proc_parse_info *pi)
+{
+	int ret, len, pos = pi->next - pi->buf;
+	char *p, *p1;
+
+	if (pos >= pi->data_size) {
+		free(pi->buf);
+		return 0;
+	}
+
+	ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
+		     &pi->eb_size);
+	if (ret != 3)
+		return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
+
+	p = memchr(pi->next, '\"', pi->data_size - pos);
+	if (!p)
+		return errmsg("opening \" not found");
+	p += 1;
+	pos = p - pi->buf;
+	if (pos >= pi->data_size)
+		return errmsg("opening \" not found");
+
+	p1 = memchr(p, '\"', pi->data_size - pos);
+	if (!p1)
+		return errmsg("closing \" not found");
+	pos = p1 - pi->buf;
+	if (pos >= pi->data_size)
+		return errmsg("closing \" not found");
+
+	len = p1 - p;
+	if (len > MTD_NAME_MAX)
+		return errmsg("too long mtd%d device name", pi->mtd_num);
+
+	memcpy(pi->name, p, len);
+	pi->name[len] = '\0';
+
+	if (p1[1] != '\n')
+		return errmsg("opening \"\n\" not found");
+	pi->next = p1 + 2;
+	return 1;
+}
+
+/**
+ * legacy_procfs_is_supported - legacy version of 'sysfs_is_supported()'.
+ *
+ * Check if we can access the procfs files for the MTD subsystem.
+ */
+int legacy_procfs_is_supported(void)
+{
+	if (access(MTD_PROC_FILE, R_OK) != 0) {
+		if (errno == ENOENT) {
+			errno = 0;
+		} else {
+			sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
+		}
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * legacy_dev_present - legacy version of 'mtd_dev_present()'.
+ * @mtd_num: MTD device number
+ *
+ * When the kernel does not provide sysfs files for the MTD subsystem,
+ * fall-back to parsing the /proc/mtd file to determine whether an mtd device
+ * number @mtd_num is present.
+ */
+int legacy_dev_present(int mtd_num)
+{
+	int ret;
+	struct proc_parse_info pi;
+
+	ret = proc_parse_start(&pi);
+	if (ret)
+		return -1;
+
+	while (proc_parse_next(&pi)) {
+		if (pi.mtd_num == mtd_num)
+			return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
+ * @info: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_info()' and has the same conventions.
+ */
+int legacy_mtd_get_info(struct mtd_info *info)
+{
+	int ret;
+	struct proc_parse_info pi;
+
+	ret = proc_parse_start(&pi);
+	if (ret)
+		return -1;
+
+	info->lowest_mtd_num = INT_MAX;
+	while (proc_parse_next(&pi)) {
+		info->mtd_dev_cnt += 1;
+		if (pi.mtd_num > info->highest_mtd_num)
+			info->highest_mtd_num = pi.mtd_num;
+		if (pi.mtd_num < info->lowest_mtd_num)
+			info->lowest_mtd_num = pi.mtd_num;
+	}
+
+	return 0;
+}
+
+int legacy_get_mtd_oobavail(const char *node)
+{
+	struct stat st;
+	struct nand_ecclayout_user usrlay;
+	int fd, ret;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	if (fstat(fd, &st)) {
+		ret = sys_errmsg("cannot open \"%s\"", node);
+		goto out_close;
+	}
+
+	if (!S_ISCHR(st.st_mode)) {
+		errno = EINVAL;
+		ret = errmsg("\"%s\" is not a character device", node);
+		goto out_close;
+	}
+
+	ret = ioctl(fd, ECCGETLAYOUT, &usrlay);
+	if (ret < 0) {
+		if (errno == EOPNOTSUPP)
+			goto out_close;
+		sys_errmsg("ECCGETLAYOUT ioctl request failed");
+		goto out_close;
+	}
+
+	ret = usrlay.oobavail;
+
+out_close:
+	close(fd);
+
+	return ret;
+}
+
+int legacy_get_mtd_oobavail1(int mtd_num)
+{
+	char node[sizeof(MTD_DEV_PATT) + 20];
+
+	sprintf(node, MTD_DEV_PATT, mtd_num);
+	return legacy_get_mtd_oobavail(node);
+}
+
+/**
+ * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
+{
+	struct stat st;
+	struct mtd_info_user ui;
+	int fd, ret;
+	loff_t offs = 0;
+	struct proc_parse_info pi;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1) {
+		sys_errmsg("cannot open \"%s\"", node);
+		if (errno == ENOENT)
+			normsg("MTD subsystem is old and does not support "
+			       "sysfs, so MTD character device nodes have "
+			       "to exist");
+		return -1;
+	}
+
+	if (fstat(fd, &st)) {
+		sys_errmsg("cannot stat \"%s\"", node);
+		close(fd);
+		return -1;
+	}
+
+	if (!S_ISCHR(st.st_mode)) {
+		close(fd);
+		errno = EINVAL;
+		return errmsg("\"%s\" is not a character device", node);
+	}
+
+	memset(mtd, '\0', sizeof(struct mtd_dev_info));
+	mtd->major = major(st.st_rdev);
+	mtd->minor = minor(st.st_rdev);
+
+	if (mtd->major != MTD_DEV_MAJOR) {
+		close(fd);
+		errno = EINVAL;
+		return errmsg("\"%s\" has major number %d, MTD devices have "
+			      "major %d", node, mtd->major, MTD_DEV_MAJOR);
+	}
+
+	mtd->mtd_num = mtd->minor / 2;
+
+	if (ioctl(fd, MEMGETINFO, &ui)) {
+		sys_errmsg("MEMGETINFO ioctl request failed");
+		goto out_close;
+	}
+
+	ret = ioctl(fd, MEMGETBADBLOCK, &offs);
+	if (ret == -1) {
+		if (errno != EOPNOTSUPP) {
+			sys_errmsg("MEMGETBADBLOCK ioctl failed");
+			goto out_close;
+		}
+		errno = 0;
+		mtd->bb_allowed = 0;
+	} else
+		mtd->bb_allowed = 1;
+
+	mtd->type = ui.type;
+	mtd->size = ui.size;
+	mtd->eb_size = ui.erasesize;
+	mtd->min_io_size = ui.writesize;
+	mtd->oob_size = ui.oobsize;
+
+	if (mtd->min_io_size <= 0) {
+		errmsg("mtd%d (%s) has insane min. I/O unit size %d",
+		       mtd->mtd_num, node, mtd->min_io_size);
+		goto out_close;
+	}
+	if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+		errmsg("mtd%d (%s) has insane eraseblock size %d",
+		       mtd->mtd_num, node, mtd->eb_size);
+		goto out_close;
+	}
+	if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+		errmsg("mtd%d (%s) has insane size %lld",
+		       mtd->mtd_num, node, mtd->size);
+		goto out_close;
+	}
+	mtd->eb_cnt = mtd->size / mtd->eb_size;
+
+	switch(mtd->type) {
+	case MTD_ABSENT:
+		errmsg("mtd%d (%s) is removable and is not present",
+		       mtd->mtd_num, node);
+		goto out_close;
+	case MTD_RAM:
+		strcpy((char *)mtd->type_str, "ram");
+		break;
+	case MTD_ROM:
+		strcpy((char *)mtd->type_str, "rom");
+		break;
+	case MTD_NORFLASH:
+		strcpy((char *)mtd->type_str, "nor");
+		break;
+	case MTD_NANDFLASH:
+		strcpy((char *)mtd->type_str, "nand");
+		break;
+	case MTD_MLCNANDFLASH:
+		strcpy((char *)mtd->type_str, "mlc-nand");
+		break;
+	case MTD_DATAFLASH:
+		strcpy((char *)mtd->type_str, "dataflash");
+		break;
+	case MTD_UBIVOLUME:
+		strcpy((char *)mtd->type_str, "ubi");
+		break;
+	default:
+		goto out_close;
+	}
+
+	if (ui.flags & MTD_WRITEABLE)
+		mtd->writable = 1;
+	mtd->subpage_size = mtd->min_io_size;
+
+	close(fd);
+
+	ret = legacy_get_mtd_oobavail(node);
+	mtd->oobavail = ret > 0 ? ret : 0;
+
+	/*
+	 * Unfortunately, the device name is not available via ioctl, and
+	 * we have to parse /proc/mtd to get it.
+	 */
+	ret = proc_parse_start(&pi);
+	if (ret)
+		return -1;
+
+	while (proc_parse_next(&pi)) {
+		if (pi.mtd_num == mtd->mtd_num) {
+			strcpy((char *)mtd->name, pi.name);
+			return 0;
+		}
+	}
+
+	errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
+	errno = ENOENT;
+	return -1;
+
+out_close:
+	close(fd);
+	return -1;
+}
+
+/**
+ * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
+ * @mtd_num: MTD device number
+ * @mtd: the MTD device information is returned here
+ *
+ * This function is similar to 'mtd_get_dev_info1()' and has the same
+ * conventions.
+ */
+int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
+{
+	char node[sizeof(MTD_DEV_PATT) + 20];
+
+	sprintf(node, MTD_DEV_PATT, mtd_num);
+	return legacy_get_dev_info(node, mtd);
+}

+ 225 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libscan.c

@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#define PROGRAM_NAME "libscan"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <mtd_swab.h>
+#include <mtd/ubi-media.h>
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include <crc32.h>
+#include "common.h"
+
+static int all_ff(const void *buf, int len)
+{
+	int i;
+	const uint8_t *p = buf;
+
+	for (i = 0; i < len; i++)
+		if (p[i] != 0xFF)
+			return 0;
+	return 1;
+}
+
+int ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+	     int verbose)
+{
+	int eb, v = (verbose == 2), pr = (verbose == 1);
+	struct ubi_scan_info *si;
+	unsigned long long sum = 0;
+
+	si = calloc(1, sizeof(struct ubi_scan_info));
+	if (!si)
+		return sys_errmsg("cannot allocate %zd bytes of memory",
+				  sizeof(struct ubi_scan_info));
+
+	si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t));
+	if (!si->ec) {
+		sys_errmsg("cannot allocate %zd bytes of memory",
+			   sizeof(struct ubi_scan_info));
+		goto out_si;
+	}
+
+	si->vid_hdr_offs = si->data_offs = -1;
+
+	verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt);
+	for (eb = 0; eb < mtd->eb_cnt; eb++) {
+		int ret;
+		uint32_t crc;
+		struct ubi_ec_hdr ech;
+		unsigned long long ec;
+
+		if (v) {
+			normsg_cont("scanning eraseblock %d", eb);
+			fflush(stdout);
+		}
+		if (pr) {
+			printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2lld %% complete  ",
+			       eb, (long long)(eb + 1) * 100 / mtd->eb_cnt);
+			fflush(stdout);
+		}
+
+		ret = mtd_is_bad(mtd, fd, eb);
+		if (ret == -1)
+			goto out_ec;
+		if (ret) {
+			si->bad_cnt += 1;
+			si->ec[eb] = EB_BAD;
+			if (v)
+				printf(": bad\n");
+			continue;
+		}
+
+		ret = mtd_read(mtd, fd, eb, 0, &ech, sizeof(struct ubi_ec_hdr));
+		if (ret < 0)
+			goto out_ec;
+
+		if (be32_to_cpu(ech.magic) != UBI_EC_HDR_MAGIC) {
+			if (all_ff(&ech, sizeof(struct ubi_ec_hdr))) {
+				si->empty_cnt += 1;
+				si->ec[eb] = EB_EMPTY;
+				if (v)
+					printf(": empty\n");
+			} else {
+				si->alien_cnt += 1;
+				si->ec[eb] = EB_ALIEN;
+				if (v)
+					printf(": alien\n");
+			}
+			continue;
+		}
+
+		crc = mtd_crc32(UBI_CRC32_INIT, &ech, UBI_EC_HDR_SIZE_CRC);
+		if (be32_to_cpu(ech.hdr_crc) != crc) {
+			si->corrupted_cnt += 1;
+			si->ec[eb] = EB_CORRUPTED;
+			if (v)
+				printf(": bad CRC %#08x, should be %#08x\n",
+				       crc, be32_to_cpu(ech.hdr_crc));
+			continue;
+		}
+
+		ec = be64_to_cpu(ech.ec);
+		if (ec > EC_MAX) {
+			if (pr)
+				printf("\n");
+			errmsg("erase counter in EB %d is %llu, while this "
+			       "program expects them to be less than %u",
+			       eb, ec, EC_MAX);
+			goto out_ec;
+		}
+
+		if (si->vid_hdr_offs == -1) {
+			si->vid_hdr_offs = be32_to_cpu(ech.vid_hdr_offset);
+			si->data_offs = be32_to_cpu(ech.data_offset);
+			if (si->data_offs % mtd->min_io_size) {
+				if (pr)
+					printf("\n");
+				if (v)
+					printf(": corrupted because of the below\n");
+				warnmsg("bad data offset %d at eraseblock %d (n"
+					"of multiple of min. I/O unit size %d)",
+					si->data_offs, eb, mtd->min_io_size);
+				warnmsg("treat eraseblock %d as corrupted", eb);
+				si->corrupted_cnt += 1;
+				si->ec[eb] = EB_CORRUPTED;
+				continue;
+
+			}
+		} else {
+			if ((int)be32_to_cpu(ech.vid_hdr_offset) != si->vid_hdr_offs) {
+				if (pr)
+					printf("\n");
+				if (v)
+					printf(": corrupted because of the below\n");
+				warnmsg("inconsistent VID header offset: was "
+					"%d, but is %d in eraseblock %d",
+					si->vid_hdr_offs,
+					be32_to_cpu(ech.vid_hdr_offset), eb);
+				warnmsg("treat eraseblock %d as corrupted", eb);
+				si->corrupted_cnt += 1;
+				si->ec[eb] = EB_CORRUPTED;
+				continue;
+			}
+			if ((int)be32_to_cpu(ech.data_offset) != si->data_offs) {
+				if (pr)
+					printf("\n");
+				if (v)
+					printf(": corrupted because of the below\n");
+				warnmsg("inconsistent data offset: was %d, but"
+					" is %d in eraseblock %d",
+					si->data_offs,
+					be32_to_cpu(ech.data_offset), eb);
+				warnmsg("treat eraseblock %d as corrupted", eb);
+				si->corrupted_cnt += 1;
+				si->ec[eb] = EB_CORRUPTED;
+				continue;
+			}
+		}
+
+		si->ok_cnt += 1;
+		si->ec[eb] = ec;
+		if (v)
+			printf(": OK, erase counter %u\n", si->ec[eb]);
+	}
+
+	if (si->ok_cnt != 0) {
+		/* Calculate mean erase counter */
+		for (eb = 0; eb < mtd->eb_cnt; eb++) {
+			if (si->ec[eb] > EC_MAX)
+				continue;
+			sum += si->ec[eb];
+		}
+		si->mean_ec = sum / si->ok_cnt;
+	}
+
+	si->good_cnt = mtd->eb_cnt - si->bad_cnt;
+	verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d "
+		"alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt,
+		si->empty_cnt, si->alien_cnt, si->bad_cnt);
+
+	*info = si;
+	if (pr)
+		printf("\n");
+	return 0;
+
+out_ec:
+	free(si->ec);
+out_si:
+	free(si);
+	*info = NULL;
+	return -1;
+}
+
+void ubi_scan_free(struct ubi_scan_info *si)
+{
+	free(si->ec);
+	free(si);
+}

+ 1364 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libubi.c

@@ -0,0 +1,1364 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#define PROGRAM_NAME "libubi"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <libubi.h>
+#include "libubi_int.h"
+#include "common.h"
+
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+	char *n;
+	int len1 = strlen(path);
+	int len2 = strlen(name);
+
+	n = malloc(len1 + len2 + 2);
+	if (!n) {
+		sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+		return NULL;
+	}
+
+	memcpy(n, path, len1);
+	if (n[len1 - 1] != '/')
+		n[len1++] = '/';
+
+	memcpy(n + len1, name, len2 + 1);
+	return n;
+}
+
+/**
+ * read_positive_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_positive_ll(const char *file, long long *value)
+{
+	int fd, rd;
+	char buf[50];
+
+	fd = open(file, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	rd = read(fd, buf, sizeof(buf));
+	if (rd == -1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+	if (rd == sizeof(buf)) {
+		errmsg("contents of \"%s\" is too long", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+	buf[rd] = '\0';
+
+	*value = 0;
+	if (sscanf(buf, "%lld\n", value) != 1) {
+		errmsg("cannot read integer from \"%s\"\n", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (*value < 0) {
+		errmsg("negative value %lld in \"%s\"", *value, file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (close(fd))
+		return sys_errmsg("close failed on \"%s\"", file);
+
+	return 0;
+
+out_error:
+	close(fd);
+	return -1;
+}
+
+/**
+ * read_positive_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_positive_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_positive_int(const char *file, int *value)
+{
+	long long res;
+
+	if (read_positive_ll(file, &res))
+		return -1;
+
+	/* Make sure the value is not too big */
+	if (res > INT_MAX) {
+		errmsg("value %lld read from file \"%s\" is out of range",
+		       res, file);
+		errno = EINVAL;
+		return -1;
+	}
+
+	*value = res;
+	return 0;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+	int fd, rd, tmp1;
+	char tmp;
+
+	fd = open(file, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	rd = read(fd, buf, buf_len);
+	if (rd == -1) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+
+	if (rd == buf_len) {
+		errmsg("contents of \"%s\" is too long", file);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	((char *)buf)[rd] = '\0';
+
+	/* Make sure all data is read */
+	tmp1 = read(fd, &tmp, 1);
+	if (tmp1 < 0) {
+		sys_errmsg("cannot read \"%s\"", file);
+		goto out_error;
+	}
+	if (tmp1 > 0) {
+		errmsg("file \"%s\" contains too much data (> %d bytes)",
+		       file, buf_len);
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	if (close(fd))
+		return sys_errmsg("close failed on \"%s\"", file);
+
+	return rd;
+
+out_error:
+	close(fd);
+	return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of succes, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+	int ret;
+	char buf[50];
+
+	ret = read_data(file, buf, 50);
+	if (ret < 0)
+		return ret;
+
+	ret = sscanf(buf, "%d:%d\n", major, minor);
+	if (ret != 2) {
+		errno = EINVAL;
+		return errmsg("\"%s\" does not have major:minor format", file);
+	}
+
+	if (*major < 0 || *minor < 0) {
+		errno = EINVAL;
+		return errmsg("bad major:minor %d:%d in \"%s\"",
+			      *major, *minor, file);
+	}
+
+	return 0;
+}
+
+/**
+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+	char file[strlen(patt) + 50];
+
+	sprintf(file, patt, dev_num);
+	return read_positive_int(file, value);
+}
+
+/**
+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+	char file[strlen(patt) + 100];
+
+	sprintf(file, patt, dev_num, vol_id);
+	return read_positive_int(file, value);
+}
+
+/**
+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+	char file[strlen(patt) + 50];
+
+	sprintf(file, patt, dev_num);
+	return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+		       long long *value)
+{
+	char file[strlen(patt) + 100];
+
+	sprintf(file, patt, dev_num, vol_id);
+	return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+			 int buf_len)
+{
+	char file[strlen(patt) + 100];
+
+	sprintf(file, patt, dev_num, vol_id);
+	return read_data(file, buf, buf_len);
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an UBI device.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor)
+{
+	char file[strlen(lib->dev_dev) + 50];
+
+	sprintf(file, lib->dev_dev, dev_num);
+	return read_major(file, major, minor);
+}
+
+/**
+ * vol_get_major - get major and minor numbers of an UBI volume.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id,
+			 int *major, int *minor)
+{
+	char file[strlen(lib->vol_dev) + 100];
+
+	sprintf(file, lib->vol_dev, dev_num, vol_id);
+	return read_major(file, major, minor);
+}
+
+/**
+ * vol_node2nums - find UBI device number and volume ID by volume device node
+ *                 file.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
+ * @vol_id: volume ID is returned hers
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
+			 int *vol_id)
+{
+	struct stat st;
+	struct ubi_info info;
+	int i, fd, major, minor;
+	char file[strlen(lib->ubi_vol) + 100];
+
+	if (stat(node, &st))
+		return sys_errmsg("cannot get information about \"%s\"",
+				  node);
+
+	if (!S_ISCHR(st.st_mode)) {
+		errno = EINVAL;
+		return errmsg("\"%s\" is not a character device", node);
+	}
+
+	major = major(st.st_rdev);
+	minor = minor(st.st_rdev);
+
+	if (minor == 0) {
+		errno = EINVAL;
+		return errmsg("\"%s\" is not a volume character device", node);
+	}
+
+	if (ubi_get_info((libubi_t *)lib, &info))
+		return -1;
+
+	for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+		int major1, minor1, ret;
+
+		ret = dev_get_major(lib, i, &major1, &minor1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			return -1;
+		}
+
+		if (major1 == major)
+			break;
+	}
+
+	if (i > info.highest_dev_num) {
+		errno = ENODEV;
+		return -1;
+	}
+
+	/* Make sure this UBI volume exists */
+	sprintf(file, lib->ubi_vol, i, minor - 1);
+	fd = open(file, O_RDONLY);
+	if (fd == -1) {
+		errno = ENODEV;
+		return -1;
+	}
+
+	if (close(fd))
+		return sys_errmsg("close failed on \"%s\"", file);
+
+	*dev_num = i;
+	*vol_id = minor - 1;
+	errno = 0;
+	return 0;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
+{
+	struct stat st;
+	struct ubi_info info;
+	int i, major, minor;
+
+	if (stat(node, &st))
+		return sys_errmsg("cannot get information about \"%s\"", node);
+
+	if (!S_ISCHR(st.st_mode)) {
+		errno = EINVAL;
+		return errmsg("\"%s\" is not a character device", node);
+	}
+
+	major = major(st.st_rdev);
+	minor = minor(st.st_rdev);
+
+	if (minor != 0) {
+		errno = EINVAL;
+		return errmsg("\"%s\" is not an UBI character device", node);
+	}
+
+	if (ubi_get_info((libubi_t *)lib, &info))
+		return -1;
+
+	for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+		int major1, minor1, ret;
+
+		ret = dev_get_major(lib, i, &major1, &minor1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			return -1;
+		}
+
+		if (major1 == major) {
+			if (minor1 != 0) {
+				errmsg("UBI character device minor number is "
+				       "%d, but must be 0", minor1);
+				errno = EINVAL;
+				return -1;
+			}
+			errno = 0;
+			*dev_num = i;
+			return 0;
+		}
+	}
+
+	errno = ENODEV;
+	return -1;
+}
+
+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num)
+{
+	struct ubi_info info;
+	int i, ret, mtd_num1;
+	struct libubi *lib = desc;
+
+	if (ubi_get_info(desc, &info))
+		return -1;
+
+	for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+		ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			return -1;
+		}
+
+		if (mtd_num1 == mtd_num) {
+			errno = 0;
+			*dev_num = i;
+			return 0;
+		}
+	}
+
+	errno = 0;
+	return -1;
+}
+
+libubi_t libubi_open(void)
+{
+	int fd, version;
+	struct libubi *lib;
+
+	lib = calloc(1, sizeof(struct libubi));
+	if (!lib)
+		return NULL;
+
+	lib->sysfs_ctrl = mkpath(SYSFS_ROOT, SYSFS_CTRL);
+	if (!lib->sysfs_ctrl)
+		goto out_error;
+
+	lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
+	if (!lib->ctrl_dev)
+		goto out_error;
+
+	lib->sysfs_ubi = mkpath(SYSFS_ROOT, SYSFS_UBI);
+	if (!lib->sysfs_ubi)
+		goto out_error;
+
+	/* Make sure UBI is present */
+	fd = open(lib->sysfs_ubi, O_RDONLY);
+	if (fd == -1) {
+		errno = 0;
+		goto out_error;
+	}
+
+	if (close(fd)) {
+		sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi);
+		goto out_error;
+	}
+
+	lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
+	if (!lib->ubi_dev)
+		goto out_error;
+
+	lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
+	if (!lib->ubi_version)
+		goto out_error;
+
+	lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
+	if (!lib->dev_dev)
+		goto out_error;
+
+	lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
+	if (!lib->dev_avail_ebs)
+		goto out_error;
+
+	lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
+	if (!lib->dev_total_ebs)
+		goto out_error;
+
+	lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
+	if (!lib->dev_bad_count)
+		goto out_error;
+
+	lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
+	if (!lib->dev_eb_size)
+		goto out_error;
+
+	lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
+	if (!lib->dev_max_ec)
+		goto out_error;
+
+	lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
+	if (!lib->dev_bad_rsvd)
+		goto out_error;
+
+	lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
+	if (!lib->dev_max_vols)
+		goto out_error;
+
+	lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
+	if (!lib->dev_min_io_size)
+		goto out_error;
+
+	lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM);
+	if (!lib->dev_mtd_num)
+		goto out_error;
+
+	lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
+	if (!lib->ubi_vol)
+		goto out_error;
+
+	lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
+	if (!lib->vol_type)
+		goto out_error;
+
+	lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
+	if (!lib->vol_dev)
+		goto out_error;
+
+	lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
+	if (!lib->vol_alignment)
+		goto out_error;
+
+	lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
+	if (!lib->vol_data_bytes)
+		goto out_error;
+
+	lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
+	if (!lib->vol_rsvd_ebs)
+		goto out_error;
+
+	lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
+	if (!lib->vol_eb_size)
+		goto out_error;
+
+	lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
+	if (!lib->vol_corrupted)
+		goto out_error;
+
+	lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
+	if (!lib->vol_name)
+		goto out_error;
+
+	if (read_positive_int(lib->ubi_version, &version))
+		goto out_error;
+	if (version != LIBUBI_UBI_VERSION) {
+		errmsg("this library was made for UBI version %d, but UBI "
+		       "version %d is detected\n", LIBUBI_UBI_VERSION, version);
+		goto out_error;
+	}
+
+	return lib;
+
+out_error:
+	libubi_close((libubi_t)lib);
+	return NULL;
+}
+
+void libubi_close(libubi_t desc)
+{
+	struct libubi *lib = (struct libubi *)desc;
+
+	free(lib->vol_name);
+	free(lib->vol_corrupted);
+	free(lib->vol_eb_size);
+	free(lib->vol_rsvd_ebs);
+	free(lib->vol_data_bytes);
+	free(lib->vol_alignment);
+	free(lib->vol_dev);
+	free(lib->vol_type);
+	free(lib->ubi_vol);
+	free(lib->dev_mtd_num);
+	free(lib->dev_min_io_size);
+	free(lib->dev_max_vols);
+	free(lib->dev_bad_rsvd);
+	free(lib->dev_max_ec);
+	free(lib->dev_eb_size);
+	free(lib->dev_bad_count);
+	free(lib->dev_total_ebs);
+	free(lib->dev_avail_ebs);
+	free(lib->dev_dev);
+	free(lib->ubi_version);
+	free(lib->ubi_dev);
+	free(lib->sysfs_ubi);
+	free(lib->ctrl_dev);
+	free(lib->sysfs_ctrl);
+	free(lib);
+}
+
+/**
+ * do_attach - perform the actual attach operation.
+ * @node: name of the UBI control character device node
+ * @r: attach request
+ *
+ * This function performs the actual UBI attach operation. Returns %0 in case of
+ * success and %-1 in case of failure. @r->ubi_num contains newly created UBI
+ * device number.
+ */
+static int do_attach(const char *node, struct ubi_attach_req *r)
+{
+	int fd, ret;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	ret = ioctl(fd, UBI_IOCATT, r);
+	close(fd);
+	if (ret == -1)
+		return -1;
+
+	return ret;
+}
+
+#ifndef MTD_CHAR_MAJOR
+/*
+ * This is taken from kernel <linux/mtd/mtd.h> and is unlikely to change anytime
+ * soon.
+ */
+#define MTD_CHAR_MAJOR 90
+#endif
+
+/**
+ * mtd_node_to_num - converts device node to MTD number.
+ * @mtd_dev_node: path to device node to convert
+ *
+ * This function converts given @mtd_dev_node to MTD device number.
+ * @mtd_dev_node should contain path to the MTD device node. Returns MTD device
+ * number in case of success and %-1 in case of failure (errno is set).
+ */
+static int mtd_node_to_num(const char *mtd_dev_node)
+{
+	int major, minor;
+	struct stat sb;
+
+	if (stat(mtd_dev_node, &sb) < 0)
+		return sys_errmsg("cannot stat \"%s\"", mtd_dev_node);
+
+	if (!S_ISCHR(sb.st_mode)) {
+		errno = EINVAL;
+		return sys_errmsg("\"%s\" is not a character device",
+				  mtd_dev_node);
+	}
+
+	major = major(sb.st_rdev);
+	minor = minor(sb.st_rdev);
+
+	if (major != MTD_CHAR_MAJOR) {
+		errno = EINVAL;
+		return sys_errmsg("\"%s\" is not an MTD device", mtd_dev_node);
+	}
+
+	return minor / 2;
+}
+
+int ubi_attach(libubi_t desc, const char *node, struct ubi_attach_request *req)
+{
+	struct ubi_attach_req r;
+	int ret;
+
+	(void)desc;
+
+	if (req->mtd_dev_node) {
+		/*
+		 * User has passed path to device node. Lets find out MTD
+		 * device number of the device and update req->mtd_num with it
+		 */
+		req->mtd_num = mtd_node_to_num(req->mtd_dev_node);
+		if (req->mtd_num == -1)
+			return -1;
+	}
+
+	memset(&r, 0, sizeof(struct ubi_attach_req));
+	r.ubi_num = req->dev_num;
+	r.mtd_num = req->mtd_num;
+	r.vid_hdr_offset = req->vid_hdr_offset;
+
+	if (req->max_beb_per1024) {
+		/*
+		 * We first have to check if the running kernel supports the
+		 * 'max_beb_per1024' parameter. To do this, we invoke the
+		 * "attach" ioctl 2 times: first with incorrect value %-1 of
+		 * 'max_beb_per1024'.
+		 *
+		 * If the ioctl succeeds, it means that the kernel doesn't
+		 * support the feature and just ignored our 'max_beb_per1024'
+		 * value.
+		 *
+		 * If the ioctl returns -EINVAL, we assume this is because
+		 * 'max_beb_per1024' was set to -1, and we invoke the ioctl for
+		 * the second time with the 'max_beb_per1024' value.
+		 */
+		r.max_beb_per1024 = -1;
+		ret = do_attach(node, &r);
+		if (ret == 0) {
+			req->dev_num = r.ubi_num;
+			/*
+			 * The call succeeded. It means that the kernel ignored
+			 * 'max_beb_per1024' parameter.
+			 */
+			return 1;
+		} else if (errno != EINVAL)
+			return ret;
+	}
+
+	r.max_beb_per1024 = req->max_beb_per1024;
+
+	ret = do_attach(node, &r);
+	if (ret == 0)
+		req->dev_num = r.ubi_num;
+
+	return ret;
+}
+
+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num)
+{
+	int ret, ubi_dev;
+
+	ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev);
+	if (ret == -1) {
+		errno = ENODEV;
+		return ret;
+	}
+
+	return ubi_remove_dev(desc, node, ubi_dev);
+}
+
+int ubi_detach(libubi_t desc, const char *node, const char *mtd_dev_node)
+{
+	int mtd_num;
+
+	if (!mtd_dev_node) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	mtd_num = mtd_node_to_num(mtd_dev_node);
+	if (mtd_num == -1)
+		return -1;
+
+	return ubi_detach_mtd(desc, node, mtd_num);
+}
+
+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev)
+{
+	int fd, ret;
+	(void)desc;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+	ret = ioctl(fd, UBI_IOCDET, &ubi_dev);
+	if (ret == -1)
+		goto out_close;
+
+out_close:
+	close(fd);
+	return ret;
+}
+
+int ubi_probe_node(libubi_t desc, const char *node)
+{
+	struct stat st;
+	struct ubi_info info;
+	int i, fd, major, minor;
+	struct libubi *lib = (struct libubi *)desc;
+	char file[strlen(lib->ubi_vol) + 100];
+
+	if (stat(node, &st))
+		return sys_errmsg("cannot get information about \"%s\"", node);
+
+	if (!S_ISCHR(st.st_mode)) {
+		errmsg("\"%s\" is not a character device", node);
+		errno = EINVAL;
+		return -1;
+	}
+
+	major = major(st.st_rdev);
+	minor = minor(st.st_rdev);
+
+	if (ubi_get_info((libubi_t *)lib, &info))
+		return -1;
+
+	for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+		int major1, minor1, ret;
+
+		ret = dev_get_major(lib, i, &major1, &minor1);
+		if (ret) {
+			if (errno == ENOENT)
+				continue;
+			if (!errno)
+				goto out_not_ubi;
+			return -1;
+		}
+
+		if (major1 == major)
+			break;
+	}
+
+	if (i > info.highest_dev_num)
+		goto out_not_ubi;
+
+	if (minor == 0)
+		return 1;
+
+	/* This is supposdely an UBI volume device node */
+	sprintf(file, lib->ubi_vol, i, minor - 1);
+	fd = open(file, O_RDONLY);
+	if (fd == -1)
+		goto out_not_ubi;
+
+        if (close(fd))
+		sys_errmsg("close failed on \"%s\"", file);
+
+	return 2;
+
+out_not_ubi:
+	errmsg("\"%s\" has major:minor %d:%d, but this does not correspond to "
+	       "any existing UBI device or volume", node, major, minor);
+	errno = ENODEV;
+	return -1;
+}
+
+int ubi_get_info(libubi_t desc, struct ubi_info *info)
+{
+	DIR *sysfs_ubi;
+	struct dirent *dirent;
+	struct libubi *lib = (struct libubi *)desc;
+
+	memset(info, 0, sizeof(struct ubi_info));
+
+	if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) {
+		/*
+		 * Older UBI versions did not have control device, so we do not
+		 * panic here for compatibility reasons. May be few years later
+		 * we could return -1 here, but for now just set major:minor to
+		 * -1.
+		 */
+		info->ctrl_major = info->ctrl_minor = -1;
+	}
+
+	/*
+	 * We have to scan the UBI sysfs directory to identify how many UBI
+	 * devices are present.
+	 */
+	sysfs_ubi = opendir(lib->sysfs_ubi);
+	if (!sysfs_ubi)
+		return -1;
+
+	info->lowest_dev_num = INT_MAX;
+	while (1) {
+		int dev_num, ret;
+		char tmp_buf[256];
+
+		errno = 0;
+		dirent = readdir(sysfs_ubi);
+		if (!dirent)
+			break;
+
+		if (strlen(dirent->d_name) >= 255) {
+			errmsg("invalid entry in %s: \"%s\"",
+			       lib->sysfs_ubi, dirent->d_name);
+			errno = EINVAL;
+			goto out_close;
+		}
+
+		ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s",
+			     &dev_num, tmp_buf);
+		if (ret == 1) {
+			info->dev_count += 1;
+			if (dev_num > info->highest_dev_num)
+				info->highest_dev_num = dev_num;
+			if (dev_num < info->lowest_dev_num)
+				info->lowest_dev_num = dev_num;
+		}
+	}
+
+	if (!dirent && errno) {
+		sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+		goto out_close;
+	}
+
+	if (closedir(sysfs_ubi))
+		return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+
+	if (info->lowest_dev_num == INT_MAX)
+		info->lowest_dev_num = 0;
+
+	if (read_positive_int(lib->ubi_version, &info->version))
+		return -1;
+
+	return 0;
+
+out_close:
+	closedir(sysfs_ubi);
+	return -1;
+}
+
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+{
+	int fd, ret;
+	struct ubi_mkvol_req r;
+	size_t n;
+	(void)desc;
+
+	memset(&r, 0, sizeof(struct ubi_mkvol_req));
+
+	r.vol_id = req->vol_id;
+	r.alignment = req->alignment;
+	r.bytes = req->bytes;
+	r.vol_type = req->vol_type;
+	r.flags = req->flags;
+
+	n = strlen(req->name);
+	if (n > UBI_MAX_VOLUME_NAME)
+		return -1;
+
+	strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME);
+	r.name[UBI_MAX_VOLUME_NAME] = '\0';
+	r.name_len = n;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	ret = ioctl(fd, UBI_IOCMKVOL, &r);
+	if (ret == -1) {
+		close(fd);
+		return ret;
+	}
+
+	close(fd);
+	req->vol_id = r.vol_id;
+
+	return 0;
+}
+
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+{
+	int fd, ret;
+	(void)desc;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+	if (ret == -1) {
+		close(fd);
+		return ret;
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+int ubi_rnvols(libubi_t desc, const char *node, struct ubi_rnvol_req *rnvol)
+{
+	int fd, ret;
+	(void)desc;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	ret = ioctl(fd, UBI_IOCRNVOL, rnvol);
+	if (ret == -1) {
+		close(fd);
+		return ret;
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+{
+	int fd, ret;
+	struct ubi_rsvol_req req;
+	(void)desc;
+
+	fd = open(node, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("cannot open \"%s\"", node);
+
+	req.bytes = bytes;
+	req.vol_id = vol_id;
+
+	ret = ioctl(fd, UBI_IOCRSVOL, &req);
+	close(fd);
+	return ret;
+}
+
+int ubi_vol_block_create(int fd)
+{
+	return ioctl(fd, UBI_IOCVOLCRBLK, NULL);
+}
+
+int ubi_vol_block_remove(int fd)
+{
+	return ioctl(fd, UBI_IOCVOLRMBLK, NULL);
+}
+
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
+{
+	(void)desc;
+	if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+		return -1;
+	return 0;
+}
+
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes)
+{
+	struct ubi_leb_change_req req;
+	(void)desc;
+
+	memset(&req, 0, sizeof(struct ubi_leb_change_req));
+	req.lnum = lnum;
+	req.bytes = bytes;
+	req.dtype = 3;
+
+	if (ioctl(fd, UBI_IOCEBCH, &req))
+		return -1;
+	return 0;
+}
+
+int ubi_dev_present(libubi_t desc, int dev_num)
+{
+	struct stat st;
+	struct libubi *lib = (struct libubi *)desc;
+	char file[strlen(lib->ubi_dev) + 50];
+
+	sprintf(file, lib->ubi_dev, dev_num);
+	return !stat(file, &st);
+}
+
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
+{
+	DIR *sysfs_ubi;
+	struct dirent *dirent;
+	struct libubi *lib = (struct libubi *)desc;
+
+	memset(info, 0, sizeof(struct ubi_dev_info));
+	info->dev_num = dev_num;
+
+	if (!ubi_dev_present(desc, dev_num))
+		return -1;
+
+	sysfs_ubi = opendir(lib->sysfs_ubi);
+	if (!sysfs_ubi)
+		return -1;
+
+	info->lowest_vol_id = INT_MAX;
+
+	while (1) {
+		int vol_id, ret, devno;
+		char tmp_buf[256];
+
+		errno = 0;
+		dirent = readdir(sysfs_ubi);
+		if (!dirent)
+			break;
+
+		if (strlen(dirent->d_name) >= 255) {
+			errmsg("invalid entry in %s: \"%s\"",
+			       lib->sysfs_ubi, dirent->d_name);
+			goto out_close;
+		}
+
+		ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf);
+		if (ret == 2 && devno == dev_num) {
+			info->vol_count += 1;
+			if (vol_id > info->highest_vol_id)
+				info->highest_vol_id = vol_id;
+			if (vol_id < info->lowest_vol_id)
+				info->lowest_vol_id = vol_id;
+		}
+	}
+
+	if (!dirent && errno) {
+		sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+		goto out_close;
+	}
+
+	if (closedir(sysfs_ubi))
+		return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+
+	if (info->lowest_vol_id == INT_MAX)
+		info->lowest_vol_id = 0;
+
+	if (dev_get_major(lib, dev_num, &info->major, &info->minor))
+		return -1;
+
+	if (dev_read_int(lib->dev_mtd_num, dev_num, &info->mtd_num))
+		return -1;
+	if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs))
+		return -1;
+	if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs))
+		return -1;
+	if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+		return -1;
+	if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size))
+		return -1;
+	if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+		return -1;
+	if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+		return -1;
+	if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+		return -1;
+	if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
+		return -1;
+
+	info->avail_bytes = (long long)info->avail_lebs * info->leb_size;
+	info->total_bytes = (long long)info->total_lebs * info->leb_size;
+
+	return 0;
+
+out_close:
+	closedir(sysfs_ubi);
+	return -1;
+}
+
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
+{
+	int err, dev_num;
+	struct libubi *lib = (struct libubi *)desc;
+
+	err = ubi_probe_node(desc, node);
+	if (err != 1) {
+		if (err == 2)
+			errno = ENODEV;
+		return -1;
+	}
+
+	if (dev_node2num(lib, node, &dev_num))
+		return -1;
+
+	return ubi_get_dev_info1(desc, dev_num, info);
+}
+
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+		      struct ubi_vol_info *info)
+{
+	int ret;
+	struct libubi *lib = (struct libubi *)desc;
+	char buf[50];
+
+	memset(info, 0, sizeof(struct ubi_vol_info));
+	info->dev_num = dev_num;
+	info->vol_id = vol_id;
+
+	if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
+		return -1;
+
+	ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
+	if (ret < 0)
+		return -1;
+
+	if (strncmp(buf, "static\n", ret) == 0)
+		info->type = UBI_STATIC_VOLUME;
+	else if (strncmp(buf, "dynamic\n", ret) == 0)
+		info->type = UBI_DYNAMIC_VOLUME;
+	else {
+		errmsg("bad value at \"%s\"", buf);
+		errno = EINVAL;
+		return -1;
+	}
+
+	ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+			   &info->alignment);
+	if (ret)
+		return -1;
+	ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+			  &info->data_bytes);
+	if (ret)
+		return -1;
+	ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs);
+	if (ret)
+		return -1;
+	ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size);
+	if (ret)
+		return -1;
+	ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+			   &info->corrupted);
+	if (ret)
+		return -1;
+	info->rsvd_bytes = (long long)info->leb_size * info->rsvd_lebs;
+
+	ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+			    UBI_VOL_NAME_MAX + 2);
+	if (ret < 0)
+		return -1;
+
+	info->name[ret - 1] = '\0';
+	return 0;
+}
+
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+{
+	int err, vol_id, dev_num;
+	struct libubi *lib = (struct libubi *)desc;
+
+	err = ubi_probe_node(desc, node);
+	if (err != 2) {
+		if (err == 1)
+			errno = ENODEV;
+		return -1;
+	}
+
+	if (vol_node2nums(lib, node, &dev_num, &vol_id))
+		return -1;
+
+	return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+}
+
+int ubi_get_vol_info1_nm(libubi_t desc, int dev_num, const char *name,
+			 struct ubi_vol_info *info)
+{
+	int i, err;
+	unsigned int nlen = strlen(name);
+	struct ubi_dev_info dev_info;
+
+	if (nlen == 0) {
+		errmsg("bad \"name\" input parameter");
+		errno = EINVAL;
+		return -1;
+	}
+
+	err = ubi_get_dev_info1(desc, dev_num, &dev_info);
+	if (err)
+		return err;
+
+	for (i = dev_info.lowest_vol_id;
+	     i <= dev_info.highest_vol_id; i++) {
+		err = ubi_get_vol_info1(desc, dev_num, i, info);
+		if (err == -1) {
+			if (errno == ENOENT)
+				continue;
+			return -1;
+		}
+
+		if (nlen == strlen(info->name) && !strcmp(name, info->name))
+			return 0;
+	}
+
+	errno = ENOENT;
+	return -1;
+}
+
+int ubi_set_property(int fd, uint8_t property, uint64_t value)
+{
+	struct ubi_set_vol_prop_req r;
+
+	memset(&r, 0, sizeof(struct ubi_set_vol_prop_req));
+	r.property = property;
+	r.value = value;
+
+	return ioctl(fd, UBI_IOCSETVOLPROP, &r);
+}
+
+int ubi_leb_unmap(int fd, int lnum)
+{
+	return ioctl(fd, UBI_IOCEBUNMAP, &lnum);
+}
+
+int ubi_is_mapped(int fd, int lnum)
+{
+	return ioctl(fd, UBI_IOCEBISMAP, &lnum);
+}

+ 134 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libubi_int.h

@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_INT_H__
+#define __LIBUBI_INT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The below are pre-define UBI file and directory names.
+ *
+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'.
+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is
+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y'
+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout.
+ */
+
+#ifndef SYSFS_ROOT
+#define SYSFS_ROOT	  "/sys"
+#endif
+#define SYSFS_UBI         "class/ubi"
+#define SYSFS_CTRL        "class/misc/ubi_ctrl/"
+
+#define CTRL_DEV          "dev"
+
+#define UBI_VER           "version"
+#define UBI_DEV_NAME_PATT "ubi%d"
+
+#define DEV_DEV           "dev"
+#define DEV_AVAIL_EBS     "avail_eraseblocks"
+#define DEV_TOTAL_EBS     "total_eraseblocks"
+#define DEV_BAD_COUNT     "bad_peb_count"
+#define DEV_EB_SIZE       "eraseblock_size"
+#define DEV_MAX_EC        "max_ec"
+#define DEV_MAX_RSVD      "reserved_for_bad"
+#define DEV_MAX_VOLS      "max_vol_count"
+#define DEV_MIN_IO_SIZE   "min_io_size"
+#define DEV_MTD_NUM       "mtd_num"
+
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
+#define VOL_TYPE          "type"
+#define VOL_DEV           "dev"
+#define VOL_ALIGNMENT     "alignment"
+#define VOL_DATA_BYTES    "data_bytes"
+#define VOL_RSVD_EBS      "reserved_ebs"
+#define VOL_EB_SIZE       "usable_eb_size"
+#define VOL_CORRUPTED     "corrupted"
+#define VOL_NAME          "name"
+
+/**
+ * libubi - UBI library description data structure.
+ * @sysfs: sysfs file system path
+ * @sysfs_ctrl: UBI control device directory in sysfs
+ * @ctrl_dev: UBI control device major/minor numbers sysfs file
+ * @sysfs_ubi: UBI directory in sysfs
+ * @ubi_dev: UBI device sysfs directory pattern
+ * @ubi_version: UBI version file sysfs path
+ * @dev_dev: UBI device major/minor numbers file pattern
+ * @dev_avail_ebs: count of available eraseblocks sysfs path pattern
+ * @dev_total_ebs: total eraseblocks count sysfs path pattern
+ * @dev_bad_count: count of bad eraseblocks sysfs path pattern
+ * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern
+ * @dev_max_ec: maximum erase counter sysfs path pattern
+ * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks
+ *                handling
+ * @dev_max_vols: maximum volumes number count sysfs path pattern
+ * @dev_min_io_size: minimum I/O unit size sysfs path pattern
+ * @dev_mtd_num: MTD device number
+ * @ubi_vol: UBI volume sysfs directory pattern
+ * @vol_type: volume type sysfs path pattern
+ * @vol_dev: volume major/minor numbers file pattern
+ * @vol_alignment: volume alignment sysfs path pattern
+ * @vol_data_bytes: volume data size sysfs path pattern
+ * @vol_rsvd_ebs: volume reserved size sysfs path pattern
+ * @vol_eb_size: volume eraseblock size sysfs path pattern
+ * @vol_corrupted: volume corruption flag sysfs path pattern
+ * @vol_name: volume name sysfs path pattern
+ */
+struct libubi
+{
+	char *sysfs;
+	char *sysfs_ctrl;
+	char *ctrl_dev;
+	char *sysfs_ubi;
+	char *ubi_dev;
+	char *ubi_version;
+	char *dev_dev;
+	char *dev_avail_ebs;
+	char *dev_total_ebs;
+	char *dev_bad_count;
+	char *dev_eb_size;
+	char *dev_max_ec;
+	char *dev_bad_rsvd;
+	char *dev_max_vols;
+	char *dev_min_io_size;
+	char *dev_mtd_num;
+	char *ubi_vol;
+	char *vol_type;
+	char *vol_dev;
+	char *vol_alignment;
+	char *vol_data_bytes;
+	char *vol_rsvd_ebs;
+	char *vol_eb_size;
+	char *vol_corrupted;
+	char *vol_name;
+	char *vol_max_count;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_INT_H__ */

+ 315 - 0
EVSE/GPL/mtd-utils-2.1.2/lib/libubigen.c

@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generating UBI images.
+ *
+ * Authors: Oliver Lohmann
+ *          Artem Bityutskiy
+ */
+
+#define PROGRAM_NAME "libubigen"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mtd/ubi-media.h>
+#include <mtd_swab.h>
+#include <libubigen.h>
+#include <crc32.h>
+#include "common.h"
+
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+		      int subpage_size, int vid_hdr_offs, int ubi_ver,
+		      uint32_t image_seq)
+{
+	if (!vid_hdr_offs) {
+		vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
+		vid_hdr_offs /= subpage_size;
+		vid_hdr_offs *= subpage_size;
+	}
+
+	ui->peb_size = peb_size;
+	ui->min_io_size = min_io_size;
+	ui->vid_hdr_offs = vid_hdr_offs;
+	ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
+	ui->data_offs /= min_io_size;
+	ui->data_offs *= min_io_size;
+	ui->leb_size = peb_size - ui->data_offs;
+	ui->ubi_ver = ubi_ver;
+	ui->image_seq = image_seq;
+
+	ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE;
+	if (ui->max_volumes > UBI_MAX_VOLUMES)
+		ui->max_volumes = UBI_MAX_VOLUMES;
+	ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
+}
+
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
+{
+	struct ubi_vtbl_record *vtbl;
+	int i;
+
+	vtbl = calloc(1, ui->vtbl_size);
+	if (!vtbl) {
+		sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
+		return NULL;
+	}
+
+	for (i = 0; i < ui->max_volumes; i++) {
+		uint32_t crc = mtd_crc32(UBI_CRC32_INIT, &vtbl[i],
+				     UBI_VTBL_RECORD_SIZE_CRC);
+		vtbl[i].crc = cpu_to_be32(crc);
+	}
+
+	return vtbl;
+}
+
+int ubigen_add_volume(const struct ubigen_info *ui,
+		      const struct ubigen_vol_info *vi,
+		      struct ubi_vtbl_record *vtbl)
+{
+	struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
+	uint32_t tmp;
+
+	if (vi->id >= ui->max_volumes) {
+		errmsg("too high volume id %d, max. volumes is %d",
+		       vi->id, ui->max_volumes);
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (vi->alignment >= ui->leb_size) {
+		errmsg("too large alignment %d, max is %d (LEB size)",
+		       vi->alignment, ui->leb_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	memset(vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
+	tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
+	vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
+	vtbl_rec->alignment = cpu_to_be32(vi->alignment);
+	vtbl_rec->vol_type = vi->type;
+	tmp = ui->leb_size % vi->alignment;
+	vtbl_rec->data_pad = cpu_to_be32(tmp);
+	vtbl_rec->flags = vi->flags;
+
+	memcpy(vtbl_rec->name, vi->name, vi->name_len);
+	vtbl_rec->name[vi->name_len] = '\0';
+	vtbl_rec->name_len = cpu_to_be16(vi->name_len);
+
+	tmp = mtd_crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+	vtbl_rec->crc =	 cpu_to_be32(tmp);
+	return 0;
+}
+
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+		        struct ubi_ec_hdr *hdr, long long ec)
+{
+	uint32_t crc;
+
+	memset(hdr, 0, sizeof(struct ubi_ec_hdr));
+
+	hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+	hdr->version = ui->ubi_ver;
+	hdr->ec = cpu_to_be64(ec);
+	hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+	hdr->data_offset = cpu_to_be32(ui->data_offs);
+	hdr->image_seq = cpu_to_be32(ui->image_seq);
+
+	crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+	hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+void ubigen_init_vid_hdr(const struct ubigen_info *ui,
+			 const struct ubigen_vol_info *vi,
+			 struct ubi_vid_hdr *hdr, int lnum,
+			 const void *data, int data_size)
+{
+	uint32_t crc;
+
+	memset(hdr, 0, sizeof(struct ubi_vid_hdr));
+
+	hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+	hdr->version = ui->ubi_ver;
+	hdr->vol_type = vi->type;
+	hdr->vol_id = cpu_to_be32(vi->id);
+	hdr->lnum = cpu_to_be32(lnum);
+	hdr->data_pad = cpu_to_be32(vi->data_pad);
+	hdr->compat = vi->compat;
+
+	if (vi->type == UBI_VID_STATIC) {
+		hdr->data_size = cpu_to_be32(data_size);
+		hdr->used_ebs = cpu_to_be32(vi->used_ebs);
+		crc = mtd_crc32(UBI_CRC32_INIT, data, data_size);
+		hdr->data_crc = cpu_to_be32(crc);
+	}
+
+	crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
+	hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+int ubigen_write_volume(const struct ubigen_info *ui,
+			const struct ubigen_vol_info *vi, long long ec,
+			long long bytes, int in, int out)
+{
+	int len = vi->usable_leb_size, rd, lnum = 0;
+	char *inbuf, *outbuf;
+
+	if (vi->id >= ui->max_volumes) {
+		errmsg("too high volume id %d, max. volumes is %d",
+		       vi->id, ui->max_volumes);
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (vi->alignment >= ui->leb_size) {
+		errmsg("too large alignment %d, max is %d (LEB size)",
+		       vi->alignment, ui->leb_size);
+		errno = EINVAL;
+		return -1;
+	}
+
+	inbuf = malloc(ui->leb_size);
+	if (!inbuf)
+		return sys_errmsg("cannot allocate %d bytes of memory",
+				  ui->leb_size);
+	outbuf = malloc(ui->peb_size);
+	if (!outbuf) {
+		sys_errmsg("cannot allocate %d bytes of memory", ui->peb_size);
+		goto out_free;
+	}
+
+	memset(outbuf, 0xFF, ui->data_offs);
+	ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec);
+
+	while (bytes) {
+		int l;
+		struct ubi_vid_hdr *vid_hdr;
+
+		if (bytes < len)
+			len = bytes;
+		bytes -= len;
+
+		l = len;
+		do {
+			rd = read(in, inbuf + len - l, l);
+			if (rd != l) {
+				sys_errmsg("cannot read %d bytes from the input file", l);
+				goto out_free1;
+			}
+
+			l -= rd;
+		} while (l);
+
+		vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+		ubigen_init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
+
+		memcpy(outbuf + ui->data_offs, inbuf, len);
+		memset(outbuf + ui->data_offs + len, 0xFF,
+		       ui->peb_size - ui->data_offs - len);
+
+		if (write(out, outbuf, ui->peb_size) != ui->peb_size) {
+			sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
+			goto out_free1;
+		}
+
+		lnum += 1;
+	}
+
+	free(outbuf);
+	free(inbuf);
+	return 0;
+
+out_free1:
+	free(outbuf);
+out_free:
+	free(inbuf);
+	return -1;
+}
+
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+			    long long ec1, long long ec2,
+			    struct ubi_vtbl_record *vtbl, int fd)
+{
+	int ret;
+	struct ubigen_vol_info vi;
+	char *outbuf;
+	struct ubi_vid_hdr *vid_hdr;
+	off_t seek;
+
+	vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
+	vi.id = UBI_LAYOUT_VOLUME_ID;
+	vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
+	vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
+	vi.usable_leb_size = ui->leb_size - vi.data_pad;
+	vi.data_pad = ui->leb_size - vi.usable_leb_size;
+	vi.type = UBI_LAYOUT_VOLUME_TYPE;
+	vi.name = UBI_LAYOUT_VOLUME_NAME;
+	vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
+	vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
+
+	outbuf = malloc(ui->peb_size);
+	if (!outbuf)
+		return sys_errmsg("failed to allocate %d bytes",
+				  ui->peb_size);
+
+	memset(outbuf, 0xFF, ui->data_offs);
+	vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+	memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size);
+	memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
+	       ui->peb_size - ui->data_offs - ui->vtbl_size);
+
+	seek = (off_t) peb1 * ui->peb_size;
+	if (lseek(fd, seek, SEEK_SET) != seek) {
+		sys_errmsg("cannot seek output file");
+		goto out_free;
+	}
+
+	ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
+	ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
+	ret = write(fd, outbuf, ui->peb_size);
+	if (ret != ui->peb_size) {
+		sys_errmsg("cannot write %d bytes", ui->peb_size);
+		goto out_free;
+	}
+
+	seek = (off_t) peb2 * ui->peb_size;
+	if (lseek(fd, seek, SEEK_SET) != seek) {
+		sys_errmsg("cannot seek output file");
+		goto out_free;
+	}
+	ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
+	ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
+	ret = write(fd, outbuf, ui->peb_size);
+	if (ret != ui->peb_size) {
+		sys_errmsg("cannot write %d bytes", ui->peb_size);
+		goto out_free;
+	}
+
+	free(outbuf);
+	return 0;
+
+out_free:
+	free(outbuf);
+	return -1;
+}

+ 104 - 0
EVSE/GPL/mtd-utils-2.1.2/make_a_release.sh

@@ -0,0 +1,104 @@
+#!/bin/sh -uef
+
+# A small helper script to release mtd-utils. Takes the new version
+# as a parameter.
+
+fatal() {
+        printf "Error: %s\n" "$1" >&2
+        exit 1
+}
+
+usage() {
+        cat <<EOF
+Usage: ${0##*/} <new_ver> <outdir>
+
+<new_ver>  - mtd utils version to create in X.Y.Z[-rcX] format
+<outdir>   - the output directory where to store the tarball with the
+             gpg signature
+EOF
+        exit 0
+}
+
+[ $# -eq 0 ] && usage
+[ $# -eq 2 ] || fatal "Insufficient or too many argumetns"
+
+new_ver="$1"; shift
+outdir="$1"; shift
+
+release_name="mtd-utils-$new_ver"
+tag_name="v$new_ver"
+
+# Make sure the input is sane and the makefile contains sensible version
+VER_REGEX="\([0-9]\+.[0-9]\+.[0-9]\+\)\(-rc[0-9]\+\)\?"
+
+echo "$new_ver" | grep -q -x "$VER_REGEX" ||
+        fatal "please, provide new version in X.Y.Z[-rcX] format"
+
+grep -q -x "m4_define(\[RELEASE\], $VER_REGEX)" configure.ac ||
+        fatal "configure.ac does not contain a valid version string"
+
+# Make sure the git index is up-to-date
+[ -z "$(git status --porcelain)" ] || fatal "Git index is not up-to-date"
+
+# Make sure the tag does not exist
+[ -z "$(git tag -l "$tag_name")" ] || fatal "Tag $tag_name already exists"
+
+# Change the version in the configure.ac
+sed -i -e "s/^m4_define(\[RELEASE\], $VER_REGEX)/m4_define([RELEASE], $new_ver)/" configure.ac
+
+# And commit the change
+git commit -s -m "Release $release_name" configure.ac
+
+# Create new signed tag
+echo "Signing tag $tag_name"
+git tag -m "$release_name" -s "$tag_name"
+
+# Prepare signed tarball
+./autogen.sh
+./configure --enable-test --enable-unit-tests
+make dist-bzip2
+mkdir -p "$outdir"
+mv "$release_name.tar.bz2" "$outdir"
+
+echo "Signing the tarball"
+gpg -o "$outdir/$release_name.tar.bz2.asc" --detach-sign -a "$outdir/$release_name.tar.bz2"
+
+scp_url="casper.infradead.org:/var/ftp/pub/mtd-utils"
+ftp_url="ftp://ftp.infradead.org/pub/mtd-utils"
+git_url="git://git.infradead.org/mtd-utils.git"
+
+cat <<EOF1
+Created $outdir/$release_name.tar.bz2
+Please, verify, then push the tag and upload the tarball and the signature
+You can use these commands:
+
+------------------------------------------------------------------------------
+git push origin master $tag_name
+scp $outdir/$release_name.tar.bz2 $outdir/$release_name.tar.bz2.asc $scp_url
+------------------------------------------------------------------------------
+
+Please, send an announcement, below is the command you may run in your
+run. Substitute "me" with your e-mail address if needed, although it is
+cleaner to configure 'git send-email' to interpret 'me' as an alias for
+your name/email, see 'sendemail.aliasesfile' git configuration option.
+
+------------------------------------------------------------------------------
+mtd_tmpfile=\$(mktemp)
+
+cat > \$mtd_tmpfile <<EOF
+Subject: [ANNOUNCE] $release_name is released
+
+Hi,
+
+$release_name is released.
+
+Tarball:               $ftp_url/$release_name.tar.bz2
+Tarball gpg signature: $ftp_url/$release_name.tar.bz2.asc
+Signed git tag:        $git_url $tag_name
+EOF
+
+git send-email --from me --to 'MTD Mailing List <linux-mtd@lists.infradead.org>' --cc 'Peter Korsgaard (buildroot) <jacmet@sunsite.dk>' --cc 'Josh Boyer (Fedora) <jwboyer@gmail.com>' --cc 'Riku Voipio (Debian) <riku.voipio@linaro.org>' \$mtd_tmpfile
+
+rm \$mtd_tmpfile
+------------------------------------------------------------------------------
+EOF1

+ 41 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/MAKEDEV

@@ -0,0 +1,41 @@
+#!/bin/bash
+
+function mkftl () {
+	mknod /dev/ftl$1 b 44 $2
+	for a in `seq 1 15`; do
+		mknod /dev/ftl$1$a b 44 `expr $2 + $a`
+	done
+}
+function mknftl () {
+	mknod /dev/nftl$1 b 93 $2
+	for a in `seq 1 15`; do
+		mknod /dev/nftl$1$a b 93 `expr $2 + $a`
+	done
+}
+function mkrfd () {
+	mknod /dev/rfd$1 b 256 $2
+	for a in `seq 1 15`; do
+		mknod /dev/rfd$1$a b 256 `expr $2 + $a`
+	done
+}
+function mkinftl () {
+	mknod /dev/inftl$1 b 96 $2
+	for a in `seq 1 15`; do
+		mknod /dev/inftl$1$a b 96 `expr $2 + $a`
+	done
+}
+
+M=0
+for C in a b c d e f g h i j k l m n o p; do
+    mkftl $C $M
+    mknftl $C $M
+    mkrfd $C $M
+    mkinftl $C $M
+    let M=M+16
+done
+
+for a in `seq 0 16` ; do
+	mknod /dev/mtd$a c 90 `expr $a + $a`
+	mknod /dev/mtdr$a c 90 `expr $a + $a + 1`
+	mknod /dev/mtdblock$a b 31 $a
+done

+ 67 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/Makemodule.am

@@ -0,0 +1,67 @@
+ftl_format_SOURCES = misc-utils/ftl_format.c
+
+doc_loadbios_SOURCES = misc-utils/doc_loadbios.c
+
+ftl_check_SOURCES = misc-utils/ftl_check.c
+
+mtd_debug_SOURCES = misc-utils/mtd_debug.c
+
+mtdpart_SOURCES = misc-utils/mtdpart.c
+
+docfdisk_SOURCES = misc-utils/docfdisk.c
+
+serve_image_SOURCES = misc-utils/serve_image.c
+serve_image_LDADD = libmtd.a
+
+recv_image_SOURCES = misc-utils/recv_image.c
+recv_image_LDADD = libmtd.a
+
+flash_lock_SOURCES = misc-utils/flash_lock.c
+
+flash_unlock_SOURCES = misc-utils/flash_unlock.c
+
+flash_otp_info_SOURCES = misc-utils/flash_otp_info.c
+
+flash_otp_dump_SOURCES = misc-utils/flash_otp_dump.c
+
+flash_otp_lock_SOURCES = misc-utils/flash_otp_lock.c
+
+flash_otp_write_SOURCES = misc-utils/flash_otp_write.c
+
+flashcp_SOURCES = misc-utils/flashcp.c
+
+flash_erase_SOURCES = misc-utils/flash_erase.c
+flash_erase_LDADD = libmtd.a
+
+MISC_BINS = \
+	ftl_format doc_loadbios ftl_check mtd_debug docfdisk \
+	serve_image recv_image flash_erase flash_lock \
+	flash_unlock flash_otp_info flash_otp_dump flash_otp_lock \
+	flash_otp_write flashcp mtdpart
+
+MISC_SH = \
+	misc-utils/flash_eraseall
+
+MISC_EXTRA = \
+	misc-utils/MAKEDEV
+
+MISC_HEADER = \
+	misc-utils/mcast_image.h \
+	misc-utils/lsmtd.h
+
+MISC_MAN =
+
+if BUILD_LSMTD
+lsmtd_SOURCES = misc-utils/lsmtd.c misc-utils/lsmtd_scan.c
+lsmtd_LDADD = libmtd.a libubi.a
+lsmtd_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/misc-utils
+
+MISC_BINS += lsmtd
+MISC_MAN += misc-utils/lsmtd.8
+endif
+
+EXTRA_DIST += $(MISC_HEADER) $(MISC_EXTRA) $(MISC_SH)
+
+dist_man8_MANS += $(MISC_MAN)
+sbin_PROGRAMS += $(MISC_BINS)
+sbin_SCRIPTS += $(MISC_SH)

+ 150 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/doc_loadbios.c

@@ -0,0 +1,150 @@
+#define PROGRAM_NAME "doc_loadbios"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <mtd/mtd-user.h>
+
+unsigned char databuf[512];
+
+int main(int argc,char **argv)
+{
+	mtd_info_t meminfo;
+	int ifd,ofd;
+	struct stat statbuf;
+	erase_info_t erase;
+	unsigned long retlen, ofs, iplsize, ipltailsize;
+	unsigned char *iplbuf;
+	iplbuf = NULL;
+
+	if (argc < 3) {
+		fprintf(stderr,"You must specify a device,"
+				" the source firmware file and the offset\n");
+		return 1;
+	}
+
+	// Open and size the device
+	if ((ofd = open(argv[1],O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if ((ifd = open(argv[2], O_RDONLY)) < 0) {
+		perror("Open firmware file\n");
+		close(ofd);
+		return 1;
+	}
+
+	if (fstat(ifd, &statbuf) != 0) {
+		perror("Stat firmware file");
+		goto error;
+	}
+
+#if 0
+	if (statbuf.st_size > 65536) {
+		printf("Firmware too large (%ld bytes)\n",statbuf.st_size);
+		goto error;
+	}
+#endif
+
+	if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		goto error;
+	}
+
+	iplsize = (ipltailsize = 0);
+	if (argc >= 4) {
+		/* DoC Millennium has IPL in the first 1K of flash memory */
+		/* You may want to specify the offset 1024 to store
+		   the firmware next to IPL. */
+		iplsize = strtoul(argv[3], NULL, 0);
+		ipltailsize = iplsize % meminfo.erasesize;
+	}
+
+	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+		perror("lseek");
+		goto error;
+	}
+
+	if (ipltailsize) {
+		iplbuf = malloc(ipltailsize);
+		if (iplbuf == NULL) {
+			fprintf(stderr, "Not enough memory for IPL tail buffer of"
+					" %lu bytes\n", (unsigned long) ipltailsize);
+			goto error;
+		}
+		printf("Reading IPL%s area of length %lu at offset %lu\n",
+				(iplsize - ipltailsize) ? " tail" : "",
+				(long unsigned) ipltailsize,
+				(long unsigned) (iplsize - ipltailsize));
+		if (read(ofd, iplbuf, ipltailsize) != ipltailsize) {
+			perror("read");
+			goto error;
+		}
+	}
+
+	erase.length = meminfo.erasesize;
+
+	for (ofs = iplsize - ipltailsize ;
+			ofs < iplsize + statbuf.st_size ;
+			ofs += meminfo.erasesize) {
+		erase.start = ofs;
+		printf("Performing Flash Erase of length %lu at offset %lu\n",
+				(long unsigned) erase.length, (long unsigned) erase.start);
+
+		if (ioctl(ofd,MEMERASE,&erase) != 0) {
+			perror("ioctl(MEMERASE)");
+			goto error;
+		}
+	}
+
+	if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+		perror("lseek");
+		goto error;
+	}
+
+	if (ipltailsize) {
+		printf("Writing IPL%s area of length %lu at offset %lu\n",
+				(iplsize - ipltailsize) ? " tail" : "",
+				(long unsigned) ipltailsize,
+				(long unsigned) (iplsize - ipltailsize));
+		if (write(ofd, iplbuf, ipltailsize) != ipltailsize) {
+			perror("write");
+			goto error;
+		}
+	}
+
+	printf("Writing the firmware of length %lu at %lu... ",
+			(unsigned long) statbuf.st_size,
+			(unsigned long) iplsize);
+	do {
+		retlen = read(ifd, databuf, 512);
+		if (retlen < 512)
+			memset(databuf+retlen, 0xff, 512-retlen);
+		if (write(ofd, databuf, 512) != 512) {
+			perror("write");
+			goto error;
+		}
+	} while (retlen == 512);
+	printf("Done.\n");
+
+	if (iplbuf != NULL)
+		free(iplbuf);
+	close(ifd);
+	close(ofd);
+	return 0;
+
+error:
+	if (iplbuf != NULL)
+		free(iplbuf);
+	close(ifd);
+	close(ofd);
+	return 1;
+}

+ 322 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/docfdisk.c

@@ -0,0 +1,322 @@
+/*
+ * docfdisk.c: Modify INFTL partition tables
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define PROGRAM_NAME "docfdisk"
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+unsigned char *buf;
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct INFTLMediaHeader *mh;
+
+#define MAXSCAN 10
+
+static void show_header(int mhoffs) {
+	int i, unitsize, numunits, bmbits, numpart;
+	int start, end, num, nextunit;
+	unsigned int flags;
+	struct INFTLPartition *ip;
+
+	bmbits = le32_to_cpu(mh->BlockMultiplierBits);
+	printf("  bootRecordID          = %s\n"
+			"  NoOfBootImageBlocks   = %d\n"
+			"  NoOfBinaryPartitions  = %d\n"
+			"  NoOfBDTLPartitions    = %d\n"
+			"  BlockMultiplierBits   = %d\n"
+			"  FormatFlags           = %d\n"
+			"  OsakVersion           = %d.%d.%d.%d\n"
+			"  PercentUsed           = %d\n",
+			mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
+			le32_to_cpu(mh->NoOfBinaryPartitions),
+			le32_to_cpu(mh->NoOfBDTLPartitions),
+			bmbits,
+			le32_to_cpu(mh->FormatFlags),
+			((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+			((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+			le32_to_cpu(mh->PercentUsed));
+
+	numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
+		le32_to_cpu(mh->NoOfBDTLPartitions);
+	unitsize = meminfo.erasesize >> bmbits;
+	numunits = meminfo.size / unitsize;
+	nextunit = mhoffs / unitsize;
+	nextunit++;
+	printf("Unitsize is %d bytes.  Device has %d units.\n",
+			unitsize, numunits);
+	if (numunits > 32768) {
+		printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
+	}
+	if (bmbits && (numunits <= 16384)) {
+		printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
+	}
+	for (i = 0; i < 4; i++) {
+		ip = &(mh->Partitions[i]);
+		flags = le32_to_cpu(ip->flags);
+		start = le32_to_cpu(ip->firstUnit);
+		end = le32_to_cpu(ip->lastUnit);
+		num = le32_to_cpu(ip->virtualUnits);
+		if (start < nextunit) {
+			printf("ERROR: Overlapping or misordered partitions!\n");
+		}
+		if (start > nextunit) {
+			printf("  Unpartitioned space: %d bytes\n"
+					"    virtualUnits  = %d\n"
+					"    firstUnit     = %d\n"
+					"    lastUnit      = %d\n",
+					(start - nextunit) * unitsize, start - nextunit,
+					nextunit, start - 1);
+		}
+		if (flags & INFTL_BINARY)
+			printf("  Partition %d   (BDK):", i+1);
+		else
+			printf("  Partition %d  (BDTL):", i+1);
+		printf(" %d bytes\n"
+				"    virtualUnits  = %d\n"
+				"    firstUnit     = %d\n"
+				"    lastUnit      = %d\n"
+				"    flags         = 0x%x\n"
+				"    spareUnits    = %d\n",
+				num * unitsize, num, start, end,
+				le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
+		if (num > (1 + end - start)) {
+			printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
+		}
+		end++;
+		if (end > nextunit)
+			nextunit = end;
+		if (flags & INFTL_LAST)
+			break;
+	}
+	if (i >= 4) {
+		printf("Odd.  Last partition was not marked with INFTL_LAST.\n");
+		i--;
+	}
+	if ((i+1) != numpart) {
+		printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
+	}
+	if (nextunit > numunits) {
+		printf("ERROR: Partitions appear to extend beyond end of device!\n");
+	}
+	if (nextunit < numunits) {
+		printf("  Unpartitioned space: %d bytes\n"
+				"    virtualUnits  = %d\n"
+				"    firstUnit     = %d\n"
+				"    lastUnit      = %d\n",
+				(numunits - nextunit) * unitsize, numunits - nextunit,
+				nextunit, numunits - 1);
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	int ret, i, mhblock, unitsize, block;
+	unsigned int nblocks[4], npart;
+	unsigned int totblocks;
+	struct INFTLPartition *ip = NULL;
+	unsigned char *oobbuf;
+	struct mtd_oob_buf oob;
+	char line[20];
+	int mhoffs;
+	struct INFTLMediaHeader *mh2;
+
+	if (argc < 2) {
+		printf(
+				"Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
+				"  Sizes are in device units (run with no sizes to show unitsize and current\n"
+				"  partitions).  Last size = 0 means go to end of device.\n",
+				PROGRAM_NAME);
+		return 1;
+	}
+
+	npart = argc - 2;
+	if (npart > 4) {
+		printf("Max 4 partitions allowed.\n");
+		return 1;
+	}
+
+	for (i = 0; i < npart; i++) {
+		nblocks[i] = strtoul(argv[2+i], NULL, 0);
+		if (i && !nblocks[i-1]) {
+			printf("No sizes allowed after 0\n");
+			return 1;
+		}
+	}
+
+	// Open and size the device
+	if ((fd = open(argv[1], O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		return 1;
+	}
+
+	printf("Device size is %d bytes.  Erasesize is %d bytes.\n",
+			meminfo.size, meminfo.erasesize);
+
+	buf = malloc(meminfo.erasesize);
+	oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
+	if (!buf || !oobbuf) {
+		printf("Can't malloc block buffer\n");
+		return 1;
+	}
+	oob.length = meminfo.oobsize;
+
+	mh = (struct INFTLMediaHeader *) buf;
+
+	for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
+		if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
+			if (errno == EBADMSG) {
+				printf("ECC error at eraseblock %d\n", mhblock);
+				continue;
+			}
+			perror("Read eraseblock");
+			return 1;
+		}
+		if (ret != meminfo.erasesize) {
+			printf("Short read!\n");
+			return 1;
+		}
+		if (!strcmp("BNAND", mh->bootRecordID)) break;
+	}
+	if (mhblock >= MAXSCAN) {
+		printf("Unable to find INFTL Media Header\n");
+		return 1;
+	}
+	printf("Found INFTL Media Header at block %d:\n", mhblock);
+	mhoffs = mhblock * meminfo.erasesize;
+
+	oob.ptr = oobbuf;
+	oob.start = mhoffs;
+	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+		if (ioctl(fd, MEMREADOOB, &oob)) {
+			perror("ioctl(MEMREADOOB)");
+			return 1;
+		}
+		oob.start += meminfo.writesize;
+		oob.ptr += meminfo.oobsize;
+	}
+
+	show_header(mhoffs);
+
+	if (!npart)
+		return 0;
+
+	printf("\n-------------------------------------------------------------------------\n");
+
+	unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
+	totblocks = meminfo.size / unitsize;
+	block = mhoffs / unitsize;
+	block++;
+
+	mh->NoOfBDTLPartitions = 0;
+	mh->NoOfBinaryPartitions = npart;
+
+	for (i = 0; i < npart; i++) {
+		ip = &(mh->Partitions[i]);
+		ip->firstUnit = cpu_to_le32(block);
+		if (!nblocks[i])
+			nblocks[i] = totblocks - block;
+		ip->virtualUnits = cpu_to_le32(nblocks[i]);
+		block += nblocks[i];
+		ip->lastUnit = cpu_to_le32(block-1);
+		ip->spareUnits = 0;
+		ip->flags = cpu_to_le32(INFTL_BINARY);
+	}
+	if (block > totblocks) {
+		printf("Requested partitions extend beyond end of device.\n");
+		return 1;
+	}
+	ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
+
+	/* update the spare as well */
+	mh2 = (struct INFTLMediaHeader *) (buf + 4096);
+	memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
+
+	printf("\nProposed new Media Header:\n");
+	show_header(mhoffs);
+
+	printf("\nReady to update device.  Type 'yes' to proceed, anything else to abort: ");
+	if (!fgets(line, sizeof(line), stdin)) {
+		printf("Failed to retrieve input chars!\n");
+		return 1;
+	}
+
+	if (strcmp("yes\n", line))
+		return 0;
+	printf("Updating MediaHeader...\n");
+
+	erase.start = mhoffs;
+	erase.length = meminfo.erasesize;
+	if (ioctl(fd, MEMERASE, &erase)) {
+		perror("ioctl(MEMERASE)");
+		printf("Your MediaHeader may be hosed.  UHOH!\n");
+		return 1;
+	}
+
+	oob.ptr = oobbuf;
+	oob.start = mhoffs;
+	for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+		memset(oob.ptr, 0xff, 6); // clear ECC.
+		if (ioctl(fd, MEMWRITEOOB, &oob)) {
+			perror("ioctl(MEMWRITEOOB)");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+		if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
+			perror("Write page");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+		if (ret != meminfo.writesize) {
+			printf("Short write!\n");
+			printf("Your MediaHeader may be hosed.  UHOH!\n");
+			return 1;
+		}
+
+		oob.start += meminfo.writesize;
+		oob.ptr += meminfo.oobsize;
+		buf += meminfo.writesize;
+	}
+
+	printf("Success.  REBOOT or unload the diskonchip module to update partitions!\n");
+	return 0;
+}

+ 92 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/fectest.c

@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "mcast_image.h"
+#include "libfec.h"
+#include <crc32.h>
+
+#define ERASE_SIZE 131072
+#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE)
+#define DROPS 8
+
+int main(void)
+{
+	int i, j;
+	unsigned char buf[NR_PKTS * PKT_SIZE];
+	unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE];
+	struct fec_parms *fec;
+	unsigned char *srcs[NR_PKTS];
+	unsigned char *pkt[NR_PKTS + DROPS];
+	int pktnr[NR_PKTS + DROPS];
+	struct timeval then, now;
+
+	srand(3453);
+	for (i=0; i < sizeof(buf); i++)
+		if (i < ERASE_SIZE)
+			buf[i] = rand();
+		else
+			buf[i] = 0;
+
+	for (i=0; i < NR_PKTS + DROPS; i++)
+		srcs[i] = buf + (i * PKT_SIZE);
+
+	for (i=0; i < NR_PKTS + DROPS; i++) {
+		pkt[i] = malloc(PKT_SIZE);
+		pktnr[i] = -1;
+	}
+	fec = fec_new(NR_PKTS, NR_PKTS + DROPS);
+	if (!fec) {
+		printf("fec_init() failed\n");
+		exit(1);
+	}
+	j = 0;
+	for (i=0; i < NR_PKTS + DROPS; i++) {
+#if 1
+		if (i == 27  || i == 40  || i == 44 || i == 45 || i == 56 )
+			continue;
+#endif
+		if (i == 69 || i == 93 || i == 103)
+			continue;
+		fec_encode(fec, srcs, pkt[j], i, PKT_SIZE);
+		pktnr[j] = i;
+		j++;
+	}
+	gettimeofday(&then, NULL);
+	if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) {
+		printf("Decode failed\n");
+		exit(1);
+	}
+
+	for (i=0; i < NR_PKTS; i++)
+		memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE);
+	gettimeofday(&now, NULL);
+	now.tv_sec -= then.tv_sec;
+	now.tv_usec -= then.tv_usec;
+	if (now.tv_usec < 0) {
+		now.tv_usec += 1000000;
+		now.tv_sec--;
+	}
+
+	if (memcmp(pktbuf, buf, ERASE_SIZE)) {
+		int fd;
+		printf("Compare failed\n");
+		fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+		if (fd >= 0)
+			write(fd, buf, ERASE_SIZE);
+		close(fd);
+		fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+		if (fd >= 0)
+			write(fd, pktbuf, ERASE_SIZE);
+
+		exit(1);
+	}
+
+	printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec);
+	return 0;
+}

+ 263 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_erase.c

@@ -0,0 +1,263 @@
+/* flash_erase.c -- erase MTD devices
+
+   Copyright (C) 2000 Arcom Control System Ltd
+   Copyright (C) 2010 Mike Frysinger <vapier@gentoo.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#define PROGRAM_NAME "flash_erase"
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <common.h>
+#include <crc32.h>
+#include <libmtd.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/jffs2-user.h>
+
+static const char *mtd_device;
+
+static int quiet;		/* true -- don't output progress */
+static int jffs2;		/* format for jffs2 usage */
+static int noskipbad;		/* do not skip bad blocks */
+static int unlock;		/* unlock sectors before erasing */
+
+static struct jffs2_unknown_node cleanmarker;
+int target_endian = __BYTE_ORDER;
+
+static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb,
+			  int eb_start, int eb_cnt)
+{
+	bareverbose(!quiet, "\rErasing %d Kibyte @ %llx -- %2i %% complete ",
+		mtd->eb_size / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt);
+	fflush(stdout);
+}
+
+static void display_help (void)
+{
+	printf("Usage: %s [options] MTD_DEVICE <start offset> <block count>\n"
+			"Erase blocks of the specified MTD device.\n"
+			"Specify a count of 0 to erase to end of device.\n"
+			"\n"
+			"  -j, --jffs2       format the device for jffs2\n"
+			"  -N, --noskipbad   don't skip bad blocks\n"
+			"  -u, --unlock      unlock sectors before erasing\n"
+			"  -q, --quiet       do not display progress messages\n"
+			"      --silent      same as --quiet\n"
+			"      --help        display this help and exit\n"
+			"      --version     output version information and exit\n",
+			PROGRAM_NAME);
+}
+
+static void display_version (void)
+{
+	common_print_version();
+	printf("Copyright (C) 2000 Arcom Control Systems Ltd\n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+}
+
+int main(int argc, char *argv[])
+{
+	libmtd_t mtd_desc;
+	struct mtd_dev_info mtd;
+	int fd, cmlen = 8;
+	unsigned long long start;
+	unsigned int eb, eb_start, eb_cnt;
+	bool isNAND;
+	int error = 0;
+	off_t offset = 0;
+
+	/*
+	 * Process user arguments
+	 */
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "jNquVh";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 'h'},
+			{"version", no_argument, 0, 'V'},
+			{"jffs2", no_argument, 0, 'j'},
+			{"noskipbad", no_argument, 0, 'N'},
+			{"quiet", no_argument, 0, 'q'},
+			{"silent", no_argument, 0, 'q'},
+			{"unlock", no_argument, 0, 'u'},
+
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'h':
+			display_help();
+			return EXIT_SUCCESS;
+		case 'V':
+			display_version();
+			return EXIT_SUCCESS;
+		case 'j':
+			jffs2 = 1;
+			break;
+		case 'N':
+			noskipbad = 1;
+			break;
+		case 'q':
+			quiet = 1;
+			break;
+		case 'u':
+			unlock = 1;
+			break;
+		case '?':
+			error = 1;
+			break;
+		}
+	}
+	switch (argc - optind) {
+	case 3:
+		mtd_device = argv[optind];
+		start = simple_strtoull(argv[optind + 1], &error);
+		eb_cnt = simple_strtoul(argv[optind + 2], &error);
+		break;
+	default:
+	case 0:
+		errmsg("no MTD device specified");
+		/* fall-through */
+	case 1:
+		errmsg("no start erase block specified");
+		/* fall-through */
+	case 2:
+		errmsg("no erase block count specified");
+		error = 1;
+		break;
+	}
+	if (error)
+		return errmsg("Try `--help' for more information");
+
+	/*
+	 * Locate MTD and prepare for erasure
+	 */
+	mtd_desc = libmtd_open();
+	if (mtd_desc == NULL)
+		return errmsg("can't initialize libmtd");
+
+	if ((fd = open(mtd_device, O_RDWR)) < 0)
+		return sys_errmsg("%s", mtd_device);
+
+	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
+		return errmsg("mtd_get_dev_info failed");
+
+	if (jffs2 && mtd.type == MTD_MLCNANDFLASH)
+		return errmsg("JFFS2 cannot support MLC NAND.");
+
+	eb_start = start / mtd.eb_size;
+
+	isNAND = mtd.type == MTD_NANDFLASH || mtd.type == MTD_MLCNANDFLASH;
+
+	if (jffs2) {
+		cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
+		cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
+		if (!isNAND) {
+			cleanmarker.totlen = cpu_to_je32(sizeof(cleanmarker));
+		} else {
+			cleanmarker.totlen = cpu_to_je32(8);
+			cmlen = min(mtd.oobavail, 8);
+		}
+		cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(cleanmarker) - 4));
+	}
+
+	/*
+	 * Now do the actual erasing of the MTD device
+	 */
+	if (eb_cnt == 0)
+		eb_cnt = (mtd.size / mtd.eb_size) - eb_start;
+
+	for (eb = eb_start; eb < eb_start + eb_cnt; eb++) {
+		offset = (off_t)eb * mtd.eb_size;
+
+		if (!noskipbad) {
+			int ret = mtd_is_bad(&mtd, fd, eb);
+			if (ret > 0) {
+				verbose(!quiet, "Skipping bad block at %08llx", (unsigned long long)offset);
+				continue;
+			} else if (ret < 0) {
+				if (errno == EOPNOTSUPP) {
+					noskipbad = 1;
+					if (isNAND)
+						return errmsg("%s: Bad block check not available", mtd_device);
+				} else
+					return sys_errmsg("%s: MTD get bad block failed", mtd_device);
+			}
+		}
+
+		show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+
+		if (unlock) {
+			if (mtd_unlock(&mtd, fd, eb) != 0) {
+				sys_errmsg("%s: MTD unlock failure", mtd_device);
+				continue;
+			}
+		}
+
+		if (mtd_erase(mtd_desc, &mtd, fd, eb) != 0) {
+			sys_errmsg("%s: MTD Erase failure", mtd_device);
+			continue;
+		}
+
+		/* format for JFFS2 ? */
+		if (!jffs2)
+			continue;
+
+		/* write cleanmarker */
+		if (isNAND) {
+			if (mtd_write(mtd_desc, &mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen,
+					MTD_OPS_AUTO_OOB) != 0) {
+				sys_errmsg("%s: MTD writeoob failure", mtd_device);
+				continue;
+			}
+		} else {
+			if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
+				sys_errmsg("%s: MTD write failure", mtd_device);
+				continue;
+			}
+		}
+		verbose(!quiet, " Cleanmarker Updated.");
+	}
+	show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+	bareverbose(!quiet, "\n");
+
+	return 0;
+}

+ 4 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_eraseall

@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "${0##*/} has been replaced by \`flash_erase <mtddev> 0 0\`; please use it" 1>&2
+[ $# -ne 0 ] && set -- "$@" 0 0
+exec flash_erase "$@"

+ 8 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_lock.c

@@ -0,0 +1,8 @@
+/*
+ * flash_{lock,unlock}
+ *
+ * utilities for locking/unlocking sectors of flash devices
+ */
+
+#define PROGRAM_NAME "flash_lock"
+#include "flash_unlock.c"

+ 71 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_dump.c

@@ -0,0 +1,71 @@
+/*
+ * flash_otp_dump.c -- display One-Time-Programm data
+ */
+
+#define PROGRAM_NAME "flash_otp_dump"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+	int fd, val, i, ret;
+	int offset = 0;
+	unsigned char buf[16];
+
+	if (argc <= 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+		fprintf(stderr,"Usage: %s [ -f | -u ] <device> [<offset>]\n", PROGRAM_NAME);
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	if (argc >= 4) {
+		char *p;
+		offset = (off_t)strtoull(argv[3], &p, 0);
+		if (argv[3][0] == 0 || *p != 0) {
+			fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
+			return ERANGE;
+		}
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		perror("lseek()");
+		return errno;
+	}
+
+	printf("OTP %s data for %s\n",
+			argv[1][1] == 'f' ? "factory" : "user", argv[2]);
+	while ((ret = read(fd, buf, sizeof(buf)))) {
+		if (ret < 0) {
+			perror("read()");
+			return errno;
+		}
+		printf("0x%04x:", offset);
+		for (i = 0; i < ret; i++)
+			printf(" %02x", buf[i]);
+		printf("\n");
+		offset += ret;
+	}
+
+	close(fd);
+	return 0;
+}

+ 65 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_info.c

@@ -0,0 +1,65 @@
+/*
+ * flash_otp_info.c -- print info about One-Time-Programm data
+ */
+
+#define PROGRAM_NAME "flash_otp_info"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+	int fd, val, i, ret;
+
+	if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+		fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", PROGRAM_NAME);
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	ret = ioctl(fd, OTPGETREGIONCOUNT, &val);
+	if (ret < 0) {
+		perror("OTPGETREGIONCOUNT");
+		return errno;
+	}
+
+	printf("Number of OTP %s blocks on %s: %d\n",
+			argv[1][1] == 'f' ? "factory" : "user", argv[2], val);
+
+	if (val > 0) {
+		struct otp_info info[val];
+
+		ret = ioctl(fd, OTPGETREGIONINFO, &info);
+		if (ret	< 0) {
+			perror("OTPGETREGIONCOUNT");
+			return errno;
+		}
+
+		for (i = 0; i < val; i++)
+			printf("block %2d:  offset = 0x%04x  "
+					"size = %2d bytes  %s\n",
+					i, info[i].start, info[i].length,
+					info[i].locked ? "[locked]" : "[unlocked]");
+	}
+
+	close(fd);
+	return 0;
+}

+ 72 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_lock.c

@@ -0,0 +1,72 @@
+/*
+ * flash_otp_lock.c -- lock area of One-Time-Program data
+ */
+
+#define PROGRAM_NAME "flash_otp_lock"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+#include "common.h"
+
+int main(int argc,char *argv[])
+{
+	int fd, val, ret, offset, size;
+	char *p;
+
+	if (argc != 5 || strcmp(argv[1], "-u")) {
+		fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", PROGRAM_NAME);
+		fprintf(stderr, "offset and size must match on OTP region boundaries\n");
+		fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n");
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_WRONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	offset = strtoul(argv[3], &p, 0);
+	if (argv[3][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	size = strtoul(argv[4], &p, 0);
+	if (argv[4][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad size value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	printf("About to lock OTP user data on %s from 0x%x to 0x%x\n",
+			argv[2], offset, offset + size);
+	if (prompt("Are you sure?", false)) {
+		struct otp_info info;
+		info.start = offset;
+		info.length = size;
+		ret = ioctl(fd, OTPLOCK, &info);
+		if (ret	< 0) {
+			perror("OTPLOCK");
+			return errno;
+		}
+		printf("Done.\n");
+	} else {
+		printf("Aborted\n");
+	}
+
+	return 0;
+}

+ 122 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_otp_write.c

@@ -0,0 +1,122 @@
+/*
+ * flash_otp_write.c -- write One-Time-Program data
+ */
+
+#define PROGRAM_NAME "flash_otp_write"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <common.h>
+#include <mtd/mtd-user.h>
+
+static ssize_t xread(int fd, void *buf, size_t count)
+{
+	ssize_t ret, done = 0;
+
+retry:
+	ret = read(fd, buf + done, count - done);
+	if (ret < 0)
+		return ret;
+
+	done += ret;
+
+	if (ret == 0 /* EOF */ || done == count)
+		return done;
+	else
+		goto retry;
+}
+
+int main(int argc,char *argv[])
+{
+	int fd, val, ret, size, wrote, len;
+	mtd_info_t mtdInfo;
+	off_t offset;
+	char *p, buf[2048];
+
+	if (argc != 4 || strcmp(argv[1], "-u")) {
+		fprintf(stderr, "Usage: %s -u <device> <offset>\n", PROGRAM_NAME);
+		fprintf(stderr, "the raw data to write should be provided on stdin\n");
+		fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n");
+		return EINVAL;
+	}
+
+	fd = open(argv[2], O_WRONLY);
+	if (fd < 0) {
+		perror(argv[2]);
+		return errno;
+	}
+
+	val = MTD_OTP_USER;
+	ret = ioctl(fd, OTPSELECT, &val);
+	if (ret < 0) {
+		perror("OTPSELECT");
+		return errno;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
+		perror("MEMGETINFO");
+		return errno;
+	}
+
+	offset = (off_t)strtoull(argv[3], &p, 0);
+	if (argv[3][0] == 0 || *p != 0) {
+		fprintf(stderr, "%s: bad offset value\n", PROGRAM_NAME);
+		return ERANGE;
+	}
+
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		perror("lseek()");
+		return errno;
+	}
+
+	printf("Writing OTP user data on %s at offset 0x%llx\n", argv[2], (unsigned long long)offset);
+
+	if (mtd_type_is_nand_user(&mtdInfo))
+		len = mtdInfo.writesize;
+	else
+		len = 256;
+
+	if (len > sizeof(buf)) {
+		printf("huh, writesize (%d) bigger than buffer (%zu)\n",
+				len, sizeof(buf));
+		return ENOMEM;
+	}
+
+	wrote = 0;
+	while ((size = xread(0, buf, len))) {
+		if (size < 0) {
+			perror("read()");
+			return errno;
+		}
+		p = buf;
+		while (size > 0) {
+			if (mtd_type_is_nand_user(&mtdInfo)) {
+				/* Fill remain buffers with 0xff */
+				memset(buf + size, 0xff, mtdInfo.writesize - size);
+				size = mtdInfo.writesize;
+			}
+			ret = write(fd, p, size);
+			if (ret < 0) {
+				perror("write()");
+				return errno;
+			}
+			if (ret == 0) {
+				printf("write() returned 0 after writing %d bytes\n", wrote);
+				return 0;
+			}
+			p += ret;
+			wrote += ret;
+			size -= ret;
+		}
+	}
+
+	printf("Wrote %d bytes of OTP user data\n", wrote);
+	return 0;
+}

+ 218 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flash_unlock.c

@@ -0,0 +1,218 @@
+/*
+ * flash_{lock,unlock}
+ *
+ * utilities for locking/unlocking sectors of flash devices
+ */
+
+enum flash_lock_request {
+	REQUEST_LOCK,
+	REQUEST_UNLOCK,
+	REQUEST_ISLOCKED,
+};
+
+#ifndef PROGRAM_NAME
+#define PROGRAM_NAME		"flash_unlock"
+#define DEFAULT_REQUEST		REQUEST_UNLOCK
+#else
+#define DEFAULT_REQUEST		REQUEST_LOCK
+#endif
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include "common.h"
+#include <mtd/mtd-user.h>
+
+static const char *flash_msg[] = {
+	[ REQUEST_LOCK ]	= "lock",
+	[ REQUEST_UNLOCK ]	= "unlock",
+	[ REQUEST_ISLOCKED ]	= "check lock status",
+};
+
+static NORETURN void usage(int status)
+{
+	fprintf(status ? stderr : stdout,
+		"Utility to lock, unlock, or check the lock status of the flash.\n"
+		"Default action: %s\n"
+		"\n"
+		"Usage: %s [options] [--] <mtd device> [offset [block count]]\n"
+		"\n"
+		"Options:\n"
+		" -h         --help              Display this help and exit\n"
+		" -V         --version           Display version information and exit\n"
+		" -i         --islocked          Check if flash region is locked\n"
+		" -l         --lock              Lock a region of flash\n"
+		" -u         --unlock            Unlock a region of flash\n"
+		"\n"
+		"If offset is not specified, it defaults to 0.\n"
+		"If block count is not specified, it defaults to all blocks.\n"
+		"A block count of -1 means all blocks.\n",
+		flash_msg[DEFAULT_REQUEST],
+		PROGRAM_NAME);
+	exit(status);
+}
+
+static const char short_opts[] = "hiluV";
+static const struct option long_opts[] = {
+	{ "help",	no_argument,	0, 'h' },
+	{ "islocked",	no_argument,	0, 'i' },
+	{ "lock",	no_argument,	0, 'l' },
+	{ "unlock",	no_argument,	0, 'u' },
+	{ "version",	no_argument,	0, 'V' },
+	{ NULL,		0,		0, 0 },
+};
+
+/* Program arguments */
+static const char *dev, *offs_s, *count_s;
+static enum flash_lock_request req = DEFAULT_REQUEST;
+
+static void process_args(int argc, char *argv[])
+{
+	int arg_idx;
+	int req_set = 0;
+
+	for (;;) {
+		int c;
+
+		c = getopt_long(argc, argv, short_opts, long_opts, NULL);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'h':
+			usage(EXIT_SUCCESS);
+		case 'i':
+			req = REQUEST_ISLOCKED;
+			req_set++;
+			break;
+		case 'l':
+			req = REQUEST_LOCK;
+			req_set++;
+			break;
+		case 'u':
+			req = REQUEST_UNLOCK;
+			req_set++;
+			break;
+		case 'V':
+			common_print_version();
+			exit(0);
+		default:
+			usage(EXIT_FAILURE);
+		}
+	}
+
+	if (req_set > 1) {
+		errmsg("cannot specify more than one lock/unlock/islocked option");
+		usage(EXIT_FAILURE);
+	}
+
+	arg_idx = optind;
+
+	/* Sanity checks */
+	if (argc - arg_idx < 1) {
+		errmsg("too few arguments");
+		usage(EXIT_FAILURE);
+	} else if (argc - arg_idx > 3) {
+		errmsg("too many arguments");
+		usage(EXIT_FAILURE);
+	}
+
+	/* First non-option argument */
+	dev = argv[arg_idx++];
+
+	/* Second non-option argument */
+	if (arg_idx < argc)
+		offs_s = argv[arg_idx++];
+	else
+		offs_s = NULL;
+
+	/* Third non-option argument */
+	if (arg_idx < argc)
+		count_s = argv[arg_idx++];
+	else
+		count_s = NULL;
+
+}
+
+int main(int argc, char *argv[])
+{
+	int fd, request;
+	struct mtd_info_user mtdInfo;
+	struct erase_info_user mtdLockInfo;
+	long count;
+	int ret = 0;
+
+	process_args(argc, argv);
+
+	/* Get the device info to compare to command line sizes */
+	fd = open(dev, O_RDWR);
+	if (fd < 0)
+		sys_errmsg_die("could not open: %s", dev);
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo))
+		sys_errmsg_die("could not get mtd info: %s", dev);
+
+	/* Make sure user options are valid */
+	if (offs_s) {
+		mtdLockInfo.start = simple_strtol(offs_s, &ret);
+		if (ret)
+			errmsg_die("bad offset");
+	} else {
+		mtdLockInfo.start = 0;
+	}
+	if (mtdLockInfo.start >= mtdInfo.size)
+		errmsg_die("%#x is beyond device size %#x",
+			mtdLockInfo.start, mtdInfo.size);
+
+	if (count_s) {
+		count = simple_strtol(count_s, &ret);
+		if (ret)
+			errmsg_die("bad count");
+		if (count == -1)
+			mtdLockInfo.length = mtdInfo.size;
+		else
+			mtdLockInfo.length = mtdInfo.erasesize * count;
+	} else {
+		mtdLockInfo.length = mtdInfo.size;
+	}
+	if (mtdLockInfo.start + mtdLockInfo.length > mtdInfo.size)
+		errmsg_die("range is more than device supports: %#x + %#x > %#x",
+			mtdLockInfo.start, mtdLockInfo.length, mtdInfo.size);
+
+	/* Finally do the operation */
+	switch (req) {
+	case REQUEST_LOCK:
+		request = MEMLOCK;
+		break;
+	case REQUEST_UNLOCK:
+		request = MEMUNLOCK;
+		break;
+	case REQUEST_ISLOCKED:
+		request = MEMISLOCKED;
+		break;
+	default:
+		errmsg_die("unknown request type: %d", req);
+		break;
+	}
+	ret = ioctl(fd, request, &mtdLockInfo);
+	if (ret < 0)
+		sys_errmsg_die("could not %s device: %s\n",
+				flash_msg[req], dev);
+
+	if (req == REQUEST_ISLOCKED) {
+		printf("Device: %s\n", dev);
+		printf("Start: %#0x\n", mtdLockInfo.start);
+		printf("Len: %#0x\n", mtdLockInfo.length);
+		printf("Lock status: %s\n", ret ? "locked" : "unlocked");
+		printf("Return code: %d\n", ret);
+	}
+
+	return 0;
+}

+ 406 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/flashcp.c

@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham@2d3d.co.za>
+ * All rights reserved.
+ *
+ * Renamed to flashcp.c to avoid conflicts with fcp from fsh package
+ *
+ * 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 author nor the names of other contributors
+ *	  may be used to endorse or promote products derived from this software
+ *	  without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+#define PROGRAM_NAME "flashcp"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mtd/mtd-user.h>
+#include <getopt.h>
+
+#include "common.h"
+
+/* for debugging purposes only */
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
+#else
+#undef DEBUG
+#define DEBUG(fmt,args...)
+#endif
+
+#define KB(x) ((x) / 1024)
+#define PERCENTAGE(x,total) (((x) * 100) / (total))
+
+/* size of read/write buffer */
+#define BUFSIZE (10 * 1024)
+
+/* cmd-line flags */
+#define FLAG_NONE		0x00
+#define FLAG_VERBOSE	0x01
+#define FLAG_HELP		0x02
+#define FLAG_FILENAME	0x04
+#define FLAG_DEVICE		0x08
+#define FLAG_ERASE_ALL	0x10
+
+/* error levels */
+#define LOG_NORMAL	1
+#define LOG_ERROR	2
+
+static void log_printf (int level,const char *fmt, ...)
+{
+	FILE *fp = level == LOG_NORMAL ? stdout : stderr;
+	va_list ap;
+	va_start (ap,fmt);
+	vfprintf (fp,fmt,ap);
+	va_end (ap);
+	fflush (fp);
+}
+
+static NORETURN void showusage(bool error)
+{
+	int level = error ? LOG_ERROR : LOG_NORMAL;
+
+	log_printf (level,
+			"\n"
+			"Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n"
+			"\n"
+			"usage: %1$s [ -v | --verbose | -A | --erase-all ] <filename> <device>\n"
+			"       %1$s -h | --help\n"
+			"       %1$s -V | --version\n"
+			"\n"
+			"   -h | --help      Show this help message\n"
+			"   -v | --verbose   Show progress reports\n"
+			"   -A | --erase-all Erases the whole device regardless of the image size\n"
+			"   -V | --version   Show version information and exit\n"
+			"   <filename>       File which you want to copy to flash\n"
+			"   <device>         Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
+			"\n",
+			PROGRAM_NAME);
+
+	exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int safe_open (const char *pathname,int flags)
+{
+	int fd;
+
+	fd = open (pathname,flags);
+	if (fd < 0)
+	{
+		log_printf (LOG_ERROR,"While trying to open %s",pathname);
+		if (flags & O_RDWR)
+			log_printf (LOG_ERROR," for read/write access");
+		else if (flags & O_RDONLY)
+			log_printf (LOG_ERROR," for read access");
+		else if (flags & O_WRONLY)
+			log_printf (LOG_ERROR," for write access");
+		log_printf (LOG_ERROR,": %m\n");
+		exit (EXIT_FAILURE);
+	}
+
+	return (fd);
+}
+
+static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
+{
+	ssize_t result;
+
+	result = read (fd,buf,count);
+	if (count != result)
+	{
+		if (verbose) log_printf (LOG_NORMAL,"\n");
+		if (result < 0)
+		{
+			log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
+			exit (EXIT_FAILURE);
+		}
+		log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
+		exit (EXIT_FAILURE);
+	}
+}
+
+static void safe_rewind (int fd,const char *filename)
+{
+	if (lseek (fd,0L,SEEK_SET) < 0)
+	{
+		log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
+		exit (EXIT_FAILURE);
+	}
+}
+
+/******************************************************************************/
+
+static int dev_fd = -1,fil_fd = -1;
+
+static void cleanup (void)
+{
+	if (dev_fd > 0) close (dev_fd);
+	if (fil_fd > 0) close (fil_fd);
+}
+
+int main (int argc,char *argv[])
+{
+	const char *filename = NULL,*device = NULL;
+	int i,flags = FLAG_NONE;
+	ssize_t result;
+	size_t size,written;
+	struct mtd_info_user mtd;
+	struct erase_info_user erase;
+	struct stat filestat;
+	unsigned char src[BUFSIZE],dest[BUFSIZE];
+
+	/*********************
+	 * parse cmd-line
+	 *****************/
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hvAV";
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 'h'},
+			{"verbose", no_argument, 0, 'v'},
+			{"erase-all", no_argument, 0, 'A'},
+			{"version", no_argument, 0, 'V'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 'h':
+				flags |= FLAG_HELP;
+				DEBUG("Got FLAG_HELP\n");
+				break;
+			case 'v':
+				flags |= FLAG_VERBOSE;
+				DEBUG("Got FLAG_VERBOSE\n");
+				break;
+			case 'A':
+				flags |= FLAG_ERASE_ALL;
+				DEBUG("Got FLAG_ERASE_ALL\n");
+				break;
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+				break;
+			default:
+				DEBUG("Unknown parameter: %s\n",argv[option_index]);
+				showusage(true);
+		}
+	}
+	if (optind+2 == argc) {
+		flags |= FLAG_FILENAME;
+		filename = argv[optind];
+		DEBUG("Got filename: %s\n",filename);
+
+		flags |= FLAG_DEVICE;
+		device = argv[optind+1];
+		DEBUG("Got device: %s\n",device);
+	}
+
+	if (flags & FLAG_HELP || device == NULL)
+		showusage(flags != FLAG_HELP);
+
+	atexit (cleanup);
+
+	/* get some info about the flash device */
+	dev_fd = safe_open (device,O_SYNC | O_RDWR);
+	if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
+	{
+		DEBUG("ioctl(): %m\n");
+		log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
+		exit (EXIT_FAILURE);
+	}
+
+	/* get some info about the file we want to copy */
+	fil_fd = safe_open (filename,O_RDONLY);
+	if (fstat (fil_fd,&filestat) < 0)
+	{
+		log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
+		exit (EXIT_FAILURE);
+	}
+
+	/* does it fit into the device/partition? */
+	if (filestat.st_size > mtd.size)
+	{
+		log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
+		exit (EXIT_FAILURE);
+	}
+
+	/*****************************************************
+	 * erase enough blocks so that we can write the file *
+	 *****************************************************/
+
+#warning "Check for smaller erase regions"
+
+	erase.start = 0;
+
+	if (flags & FLAG_ERASE_ALL)
+	{
+		erase.length = mtd.size;
+	}
+	else
+	{
+		erase.length = (filestat.st_size + mtd.erasesize - 1) / mtd.erasesize;
+		erase.length *= mtd.erasesize;
+	}
+
+	if (flags & FLAG_VERBOSE)
+	{
+		/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
+		int blocks = erase.length / mtd.erasesize;
+		erase.length = mtd.erasesize;
+		log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
+		for (i = 1; i <= blocks; i++)
+		{
+			log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
+			if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+			{
+				log_printf (LOG_NORMAL,"\n");
+				log_printf (LOG_ERROR,
+						"While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
+						(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+				exit (EXIT_FAILURE);
+			}
+			erase.start += mtd.erasesize;
+		}
+		log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
+	}
+	else
+	{
+		/* if not, erase the whole chunk in one shot */
+		if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+		{
+			log_printf (LOG_ERROR,
+					"While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
+					(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+			exit (EXIT_FAILURE);
+		}
+	}
+	DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
+
+	/**********************************
+	 * write the entire file to flash *
+	 **********************************/
+
+	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size));
+	size = filestat.st_size;
+	i = BUFSIZE;
+	written = 0;
+	while (size)
+	{
+		if (size < BUFSIZE) i = size;
+		if (flags & FLAG_VERBOSE)
+			log_printf (LOG_NORMAL,"\rWriting data: %dk/%lluk (%llu%%)",
+					KB (written + i),
+					KB ((unsigned long long)filestat.st_size),
+					PERCENTAGE (written + i,(unsigned long long)filestat.st_size));
+
+		/* read from filename */
+		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+		/* write to device */
+		result = write (dev_fd,src,i);
+		if (i != result)
+		{
+			if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
+			if (result < 0)
+			{
+				log_printf (LOG_ERROR,
+						"While writing data to 0x%.8lx-0x%.8lx on %s: %m\n",
+						written,written + i,device);
+				exit (EXIT_FAILURE);
+			}
+			log_printf (LOG_ERROR,
+					"Short write count returned while writing to x%.8zx-0x%.8zx on %s: %zu/%llu bytes written to flash\n",
+					written,written + i,device,written + result,(unsigned long long)filestat.st_size);
+			exit (EXIT_FAILURE);
+		}
+
+		written += i;
+		size -= i;
+	}
+	if (flags & FLAG_VERBOSE)
+		log_printf (LOG_NORMAL,
+				"\rWriting data: %lluk/%lluk (100%%)\n",
+				KB ((unsigned long long)filestat.st_size),
+				KB ((unsigned long long)filestat.st_size));
+	DEBUG("Wrote %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size);
+
+	/**********************************
+	 * verify that flash == file data *
+	 **********************************/
+
+	safe_rewind (fil_fd,filename);
+	safe_rewind (dev_fd,device);
+	size = filestat.st_size;
+	i = BUFSIZE;
+	written = 0;
+	if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%lluk (0%%)",KB ((unsigned long long)filestat.st_size));
+	while (size)
+	{
+		if (size < BUFSIZE) i = size;
+		if (flags & FLAG_VERBOSE)
+			log_printf (LOG_NORMAL,
+					"\rVerifying data: %luk/%lluk (%llu%%)",
+					KB (written + i),
+					KB ((unsigned long long)filestat.st_size),
+					PERCENTAGE (written + i,(unsigned long long)filestat.st_size));
+
+		/* read from filename */
+		safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+		/* read from device */
+		safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
+
+		/* compare buffers */
+		if (memcmp (src,dest,i))
+		{
+			log_printf (LOG_ERROR,
+					"File does not seem to match flash data. First mismatch at 0x%.8zx-0x%.8zx\n",
+					written,written + i);
+			exit (EXIT_FAILURE);
+		}
+
+		written += i;
+		size -= i;
+	}
+	if (flags & FLAG_VERBOSE)
+		log_printf (LOG_NORMAL,
+				"\rVerifying data: %lluk/%lluk (100%%)\n",
+				KB ((unsigned long long)filestat.st_size),
+				KB ((unsigned long long)filestat.st_size));
+	DEBUG("Verified %d / %lluk bytes\n",written,(unsigned long long)filestat.st_size);
+
+	exit (EXIT_SUCCESS);
+}

+ 231 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/ftl_check.c

@@ -0,0 +1,231 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+  Utility to create an FTL partition in a memory region
+
+  ftl_check.c 1.10 1999/10/25 20:01:35
+
+  The contents of this file are subject to the Mozilla Public
+  License Version 1.1 (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.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS
+  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  implied. See the License for the specific language governing
+  rights and limitations under the License.
+
+  The initial developer of the original code is David A. Hinds
+  <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+  Alternatively, the contents of this file may be used under the
+  terms of the GNU Public License version 2 (the "GPL"), in which
+  case the provisions of the GPL are applicable instead of the
+  above.  If you wish to allow the use of your version of this file
+  only under the terms of the GPL and not to allow others to use
+  your version of this file under the MPL, indicate your decision
+  by deleting the provisions above and replace them with the notice
+  and other provisions required by the GPL.  If you do not delete
+  the provisions above, a recipient may use your version of this
+  file under either the MPL or the GPL.
+
+  ======================================================================*/
+
+#define PROGRAM_NAME "ftl_check"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+#include <mtd_swab.h>
+
+#include "common.h"
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+	if ((s > 0x100000) && ((s % 0x100000) == 0))
+		printf("%d mb", s / 0x100000);
+	else if ((s > 0x400) && ((s % 0x400) == 0))
+		printf("%d kb", s / 0x400);
+	else
+		printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static void check_partition(int fd)
+{
+	mtd_info_t mtd;
+	erase_unit_header_t hdr, hdr2;
+	off_t i;
+	u_int j, nbam, *bam;
+	int control, data, blk_free, deleted;
+
+	/* Get partition size, block size */
+	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+		perror("get info failed");
+		return;
+	}
+
+	printf("Memory region info:\n");
+	printf("  Region size = ");
+	print_size(mtd.size);
+	printf("  Erase block size = ");
+	print_size(mtd.erasesize);
+	printf("\n\n");
+
+	for (i = 0; i < mtd.size/mtd.erasesize; i++) {
+		if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		read_nocheck(fd, &hdr, sizeof(hdr));
+		if ((le32_to_cpu(hdr.FormattedSize) > 0) &&
+				(le32_to_cpu(hdr.FormattedSize) <= mtd.size) &&
+				(le16_to_cpu(hdr.NumEraseUnits) > 0) &&
+				(le16_to_cpu(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize))
+			break;
+	}
+	if (i == mtd.size/mtd.erasesize) {
+		fprintf(stderr, "No valid erase unit headers!\n");
+		return;
+	}
+
+	printf("Partition header:\n");
+	printf("  Formatted size = ");
+	print_size(le32_to_cpu(hdr.FormattedSize));
+	printf(", erase units = %d, transfer units = %d\n",
+			le16_to_cpu(hdr.NumEraseUnits), hdr.NumTransferUnits);
+	printf("  Erase unit size = ");
+	print_size(1 << hdr.EraseUnitSize);
+	printf(", virtual block size = ");
+	print_size(1 << hdr.BlockSize);
+	printf("\n");
+
+	/* Create basic block allocation table for control blocks */
+	nbam = (mtd.erasesize >> hdr.BlockSize);
+	bam = malloc(nbam * sizeof(u_int));
+
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		if (read(fd, &hdr2, sizeof(hdr2)) == -1) {
+			perror("read failed");
+			break;
+		}
+		printf("\nErase unit %lld:\n", (long long)i);
+		if ((hdr2.FormattedSize != hdr.FormattedSize) ||
+				(hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
+				(hdr2.SerialNumber != hdr.SerialNumber))
+			printf("  Erase unit header is corrupt.\n");
+		else if (le16_to_cpu(hdr2.LogicalEUN) == 0xffff)
+			printf("  Transfer unit, erase count = %d\n", le32_to_cpu(hdr2.EraseCount));
+		else {
+			printf("  Logical unit %d, erase count = %d\n",
+					le16_to_cpu(hdr2.LogicalEUN), le32_to_cpu(hdr2.EraseCount));
+			if (lseek(fd, (i << hdr.EraseUnitSize)+le32_to_cpu(hdr.BAMOffset),
+						SEEK_SET) == -1) {
+				perror("seek failed");
+				break;
+			}
+			if (read(fd, bam, nbam * sizeof(u_int)) == -1) {
+				perror("read failed");
+				break;
+			}
+			blk_free = deleted = control = data = 0;
+			for (j = 0; j < nbam; j++) {
+				if (BLOCK_FREE(le32_to_cpu(bam[j])))
+					blk_free++;
+				else if (BLOCK_DELETED(le32_to_cpu(bam[j])))
+					deleted++;
+				else switch (BLOCK_TYPE(le32_to_cpu(bam[j]))) {
+					case BLOCK_CONTROL: control++; break;
+					case BLOCK_DATA: data++; break;
+					default: break;
+				}
+			}
+			printf("  Block allocation: %d control, %d data, %d free,"
+					" %d deleted\n", control, data, blk_free, deleted);
+		}
+	}
+
+	free(bam);
+} /* format_partition */
+
+/* Show usage information */
+static void showusage(void)
+{
+	fprintf(stderr, "usage: %s device\n", PROGRAM_NAME);
+}
+
+/*====================================================================*/
+
+static const struct option long_opts[] = {
+	{"help", no_argument, 0, 'h'},
+	{"version", no_argument, 0, 'V'},
+	{0, 0, 0, 0},
+};
+
+int main(int argc, char *argv[])
+{
+	int c, optch, errflg, fd;
+	struct stat buf;
+
+	errflg = 0;
+	while ((optch = getopt_long(argc, argv, "hV", long_opts, &c)) != -1) {
+		switch (optch) {
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+			case 'h':
+				errflg = 1; break;
+			default:
+				errflg = -1; break;
+		}
+	}
+	if (errflg || (optind != argc-1)) {
+		showusage();
+		exit(errflg > 0 ? 0 : EXIT_FAILURE);
+	}
+
+	fd = open(argv[optind], O_RDONLY);
+	if (fd == -1) {
+		perror("open failed");
+		exit(EXIT_FAILURE);
+	}
+	if (fstat(fd, &buf) != 0) {
+		perror("status check failed");
+		close(fd);
+		exit(EXIT_FAILURE);
+	}
+	if (!(buf.st_mode & S_IFCHR)) {
+		fprintf(stderr, "%s is not a character special device\n",
+				argv[optind]);
+		close(fd);
+		exit(EXIT_FAILURE);
+	}
+
+	check_partition(fd);
+	close(fd);
+
+	exit(EXIT_SUCCESS);
+	return 0;
+}

+ 343 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/ftl_format.c

@@ -0,0 +1,343 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+  Utility to create an FTL partition in a memory region
+
+  ftl_format.c 1.13 1999/10/25 20:01:35
+
+  The contents of this file are subject to the Mozilla Public
+  License Version 1.1 (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.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS
+  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  implied. See the License for the specific language governing
+  rights and limitations under the License.
+
+  The initial developer of the original code is David A. Hinds
+  <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+  Alternatively, the contents of this file may be used under the
+  terms of the GNU Public License version 2 (the "GPL"), in which
+  case the provisions of the GPL are applicable instead of the
+  above.  If you wish to allow the use of your version of this file
+  only under the terms of the GPL and not to allow others to use
+  your version of this file under the MPL, indicate your decision
+  by deleting the provisions above and replace them with the notice
+  and other provisions required by the GPL.  If you do not delete
+  the provisions above, a recipient may use your version of this
+  file under either the MPL or the GPL.
+
+  ======================================================================*/
+
+#define PROGRAM_NAME "ftl_format"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+#include <mtd_swab.h>
+#include "common.h"
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+	if ((s > 0x100000) && ((s % 0x100000) == 0))
+		printf("%d mb", s / 0x100000);
+	else if ((s > 0x400) && ((s % 0x400) == 0))
+		printf("%d kb", s / 0x400);
+	else
+		printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static const char LinkTarget[] = {
+	0x13, 0x03, 'C', 'I', 'S'
+};
+static const char DataOrg[] = {
+	0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00
+};
+
+static void build_header(erase_unit_header_t *hdr, u_int RegionSize,
+		u_int BlockSize, u_int Spare, int Reserve,
+		u_int BootSize)
+{
+	u_int i, BootUnits, nbam, __FormattedSize;
+
+	/* Default everything to the erased state */
+	memset(hdr, 0xff, sizeof(*hdr));
+	memcpy(hdr->LinkTargetTuple, LinkTarget, 5);
+	memcpy(hdr->DataOrgTuple, DataOrg, 10);
+	hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff;
+	BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1);
+	BootUnits = BootSize / BlockSize;
+
+	/* We only support 512-byte blocks */
+	hdr->BlockSize = 9;
+	hdr->EraseUnitSize = 0;
+	for (i = BlockSize; i > 1; i >>= 1)
+		hdr->EraseUnitSize++;
+	hdr->EraseCount = cpu_to_le32(0);
+	hdr->FirstPhysicalEUN = cpu_to_le16(BootUnits);
+	hdr->NumEraseUnits = cpu_to_le16((RegionSize - BootSize) >> hdr->EraseUnitSize);
+	hdr->NumTransferUnits = Spare;
+	__FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize);
+	/* Leave a little bit of space between the CIS and BAM */
+	hdr->BAMOffset = cpu_to_le32(0x80);
+	/* Adjust size to account for BAM space */
+	nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
+			+ le32_to_cpu(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
+
+	__FormattedSize -=
+		(le16_to_cpu(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize);
+	__FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff);
+
+	hdr->FormattedSize = cpu_to_le32(__FormattedSize);
+
+	/* hdr->FirstVMAddress defaults to erased state */
+	hdr->NumVMPages = cpu_to_le16(0);
+	hdr->Flags = 0;
+	/* hdr->Code defaults to erased state */
+	hdr->SerialNumber = cpu_to_le32(time(NULL));
+	/* hdr->AltEUHOffset defaults to erased state */
+
+} /* build_header */
+
+/*====================================================================*/
+
+static int format_partition(int fd, int quiet, int interrogate,
+		u_int spare, int reserve, u_int bootsize)
+{
+	mtd_info_t mtd;
+	erase_info_t erase;
+	erase_unit_header_t hdr;
+	u_int step, lun, i, nbam, *bam;
+
+	/* Get partition size, block size */
+	if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+		perror("get info failed");
+		return -1;
+	}
+
+#if 0
+	/* Intel Series 100 Flash: skip first block */
+	if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) &&
+			(bootsize == 0)) {
+		if (!quiet)
+			printf("Skipping first block to protect CIS info...\n");
+		bootsize = 1;
+	}
+#endif
+
+	/* Create header */
+	build_header(&hdr, mtd.size, mtd.erasesize,
+			spare, reserve, bootsize);
+
+	if (!quiet) {
+		printf("Partition size = ");
+		print_size(mtd.size);
+		printf(", erase unit size = ");
+		print_size(mtd.erasesize);
+		printf(", %d transfer units\n", spare);
+		if (bootsize != 0) {
+			print_size(le16_to_cpu(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize);
+			printf(" allocated for boot image\n");
+		}
+		printf("Reserved %d%%, formatted size = ", reserve);
+		print_size(le32_to_cpu(hdr.FormattedSize));
+		printf("\n");
+		fflush(stdout);
+	}
+
+	if (interrogate)
+		if (!prompt("This will destroy all data on the target device. Confirm?", false))
+			return -1;
+
+	/* Create basic block allocation table for control blocks */
+	nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int)
+			+ le32_to_cpu(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
+	bam = malloc(nbam * sizeof(u_int));
+	for (i = 0; i < nbam; i++)
+		bam[i] = cpu_to_le32(BLOCK_CONTROL);
+
+	/* Erase partition */
+	if (!quiet) {
+		printf("Erasing all blocks...\n");
+		fflush(stdout);
+	}
+	erase.length = mtd.erasesize;
+	erase.start = mtd.erasesize * le16_to_cpu(hdr.FirstPhysicalEUN);
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		if (ioctl(fd, MEMERASE, &erase) < 0) {
+			if (!quiet) {
+				putchar('\n');
+				fflush(stdout);
+			}
+			perror("block erase failed");
+			free(bam);
+			return -1;
+		}
+		erase.start += erase.length;
+		if (!quiet) {
+			if (mtd.size <= 0x800000) {
+				if (erase.start % 0x100000) {
+					if (!(erase.start % 0x20000)) putchar('-');
+				}
+				else putchar('+');
+			}
+			else {
+				if (erase.start % 0x800000) {
+					if (!(erase.start % 0x100000)) putchar('+');
+				}
+				else putchar('*');
+			}
+			fflush(stdout);
+		}
+	}
+	if (!quiet) putchar('\n');
+
+	/* Prepare erase units */
+	if (!quiet) {
+		printf("Writing erase unit headers...\n");
+		fflush(stdout);
+	}
+	lun = 0;
+	/* Distribute transfer units over the entire region */
+	step = spare ? (le16_to_cpu(hdr.NumEraseUnits) / spare) : (le16_to_cpu(hdr.NumEraseUnits) + 1);
+	for (i = 0; i < le16_to_cpu(hdr.NumEraseUnits); i++) {
+		off_t ofs = (off_t) (i + le16_to_cpu(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize;
+		if (lseek(fd, ofs, SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		/* Is this a transfer unit? */
+		if (((i+1) % step) == 0)
+			hdr.LogicalEUN = cpu_to_le16(0xffff);
+		else {
+			hdr.LogicalEUN = cpu_to_le16(lun);
+			lun++;
+		}
+		if (write(fd, &hdr, sizeof(hdr)) == -1) {
+			perror("write failed");
+			break;
+		}
+		if (lseek(fd, ofs + le32_to_cpu(hdr.BAMOffset), SEEK_SET) == -1) {
+			perror("seek failed");
+			break;
+		}
+		if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
+			perror("write failed");
+			break;
+		}
+	}
+
+	free(bam);
+
+	if (i < le16_to_cpu(hdr.NumEraseUnits))
+		return -1;
+	else
+		return 0;
+} /* format_partition */
+
+/*====================================================================*/
+
+static const struct option long_opts[] = {
+	{"help", no_argument, 0, 'h'},
+	{"version", no_argument, 0, 'V'},
+	{0, 0, 0, 0},
+};
+
+static const char *short_opts = "qir:s:b:Vh";
+
+int main(int argc, char *argv[])
+{
+	int quiet, interrogate, reserve, c;
+	int optch, errflg, fd, ret;
+	u_int spare, bootsize;
+	char *s;
+	extern char *optarg;
+	struct stat buf;
+
+	quiet = 0;
+	interrogate = 0;
+	spare = 1;
+	reserve = 5;
+	errflg = 0;
+	bootsize = 0;
+
+	while ((optch = getopt_long(argc, argv, short_opts, long_opts, &c)) != -1) {
+		switch (optch) {
+			case 'q':
+				quiet = 1; break;
+			case 'i':
+				interrogate = 1; break;
+			case 's':
+				spare = strtoul(optarg, NULL, 0); break;
+			case 'r':
+				reserve = strtoul(optarg, NULL, 0); break;
+			case 'b':
+				bootsize = strtoul(optarg, &s, 0);
+				if ((*s == 'k') || (*s == 'K'))
+					bootsize *= 1024;
+				break;
+			case 'V':
+				common_print_version();
+				exit(EXIT_SUCCESS);
+			case 'h':
+				errflg = 1; break;
+			default:
+				errflg = -1; break;
+		}
+	}
+	if (errflg || (optind != argc-1)) {
+		fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]"
+				" [-r reserve-percent] [-b bootsize] device\n", PROGRAM_NAME);
+		exit(errflg > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+	}
+
+	fd = open(argv[optind], O_RDWR);
+	if (fd == -1) {
+		perror("open failed");
+		exit(EXIT_FAILURE);
+	}
+	if (fstat(fd, &buf) != 0) {
+		perror("status check failed");
+		close(fd);
+		exit(EXIT_FAILURE);
+	}
+	if (!(buf.st_mode & S_IFCHR)) {
+		fprintf(stderr, "%s is not a character special device\n",
+				argv[optind]);
+		close(fd);
+		exit(EXIT_FAILURE);
+	}
+
+	ret = format_partition(fd, quiet, interrogate, spare, reserve,
+			bootsize);
+	if (!quiet) {
+		if (ret)
+			printf("format failed.\n");
+		else
+			printf("format successful.\n");
+	}
+	close(fd);
+
+	return ret ? EXIT_FAILURE : EXIT_SUCCESS;
+}

+ 112 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.8

@@ -0,0 +1,112 @@
+.TH LSMTD 8 "April 2017" "mtd-utils"
+.SH NAME
+lsmtd \- list memory technology devices
+.SH SYNOPSIS
+.B lsmtd
+[options]
+.RI [ device ...]
+.SH DESCRIPTION
+.B lsmtd
+lists information about all available or the specified MTD and UBI devices.
+The
+.B lsmtd
+command reads the
+.B sysfs
+filesystem to gather information. Alternatively, the
+.B procfs
+filesystem and ioctl interfaces are used, should the sysfs filesytem not
+be available.
+.PP
+The command prints all MTD and UBI devices in a pretty-printed list format by
+default.
+.PP
+The default output is subject to change. So whenever possible, you should
+avoid using default outputs in your scripts. Always explicitly define expected
+columns by using
+.B \-\-output
+.I columns-list
+in environments where a stable output is required.
+.PP
+Use
+.B "lsmtd --help"
+to get a list of all available columns.
+.SH OPTIONS
+.TP
+.BR \-b , " \-\-bytes"
+Print columns with size quantities (e.g. erase block size) in bytes instead
+of a human-readable format.
+.TP
+.BR \-h , " \-\-help"
+Display a help text and exit.
+.TP
+.BR \-i , " \-\-ascii"
+Only use ascii characters for pretty printing.
+.TP
+.BR \-J , " \-\-json"
+Use JSON output format. All potentially unsafe characters in string values are
+escaped with JSON escape sequences or hex-escaped (\\u<code>).
+.TP
+.BR \-l , " \-\-list"
+Use a pretty-printed list output format (default).
+.TP
+.BR \-m , " \-\-no-ubi"
+Do not display information about UBI devices or volumes.
+.TP
+.BR \-n , " \-\-noheadings"
+Do not print column headings when using raw or list output format.
+.TP
+.BR \-o , " \-\-output " \fIlist\fP
+Specify which output columns to print.  Use
+.B \-\-help
+to get a list of all supported columns.
+
+The default list of columns may be extended if \fIlist\fP is
+specified in the format \fI+list\fP (e.g. \fBlsmtd -o +EB-SIZE\fP).
+.TP
+.BR \-O , " \-\-output\-all "
+Output all available columns.
+.TP
+.BR \-P , " \-\-pairs"
+Produce output in the form of key="value" pairs.
+All potentially unsafe characters are hex-escaped (\\x<code>).
+.TP
+.BR \-r , " \-\-raw"
+Produce output in raw format. All potentially unsafe characters are
+hex-escaped (\\x<code>).
+.TP
+.BR \-u , " \-\-si\-units"
+Display human readable sizes as powers of ten rather than powers of two.
+.TP
+.BR \-V , " \-\-version"
+Print version information and exit.
+.TP
+.BR \-x , " \-\-sort " \fIcolumn\fP
+Sort output lines by \fIcolumn\fP.
+.SH NOTES
+If the
+.B \-\-bytes
+option is not specified, the JSON output format prints sizes as string values
+even if they do not have a suffix.
+.SH AUTHORS
+.nf
+David Oberhollenzer <david.oberhollenzer@sigma-star.at>
+.fi
+.SH REPORTING BUGS
+Report mtd-utils bugs to the Linux mtd mailing list.
+.TP
+Linux mtd mailing list: <linux-mtd@lists.infradead.org>
+.TP
+Linux mtd home page: <http://www.linux-mtd.infradead.org/>
+.SH AVAILABILITY
+The lsmtd command is part of the mtd-utils package and is available from
+ftp://ftp.infradead.org/pub/mtd-utils/.
+.SH COPYRIGHT
+Copyright \(co 2017 David Oberhollenzer - sigma star gmbh
+.br
+License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.
+.br
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+.SH SEE ALSO
+.BR lsblk (8),
+.BR ls (1)

+ 794 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.c

@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2017 David Oberhollenzer - sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA.
+ *
+ * Author: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
+ */
+#include <getopt.h>
+#include <stdio.h>
+
+#include "lsmtd.h"
+
+#define FLAG_SI 0x0001
+#define FLAG_BYTES 0x0002
+#define FLAG_NO_HEADING 0x0004
+#define FLAG_RAW 0x0008
+#define FLAG_PAIRS 0x0010
+#define FLAG_LIST 0x0020
+#define FLAG_JSON 0x0040
+#define FLAG_ASCII 0x0080
+#define FLAG_NO_UBI 0x0100
+#define FLAG_DRYRUN 0x1000
+
+static int flags;
+static struct column **selected;
+static size_t num_selected;
+static size_t max_selected;
+struct column *sort_by;
+
+static const struct option long_opts[] = {
+	{ "help", no_argument, NULL, 'h' },
+	{ "version", no_argument, NULL, 'V' },
+	{ "si-units", no_argument, NULL, 'u' },
+ 	{ "bytes", no_argument, NULL, 'b' },
+	{ "noheadings", no_argument, NULL, 'n' },
+	{ "raw", no_argument, NULL, 'r' },
+	{ "output", required_argument, NULL, 'o' },
+	{ "output-all", no_argument, NULL, 'O' },
+	{ "pairs", no_argument, NULL, 'P' },
+	{ "list", no_argument, NULL, 'l' },
+	{ "json", no_argument, NULL, 'J' },
+	{ "sort", required_argument, NULL, 'x' },
+	{ "ascii", no_argument, NULL, 'i' },
+	{ "no-ubi", no_argument, NULL, 'm' },
+	{ NULL, 0, NULL, 0 },
+};
+
+static const char *short_opts = "x:o:OPJlibrumnhV";
+static const char *default_cols = "DEVICE,MAJ:MIN,NAME,TYPE,SIZE";
+
+static struct column cols[] = {
+	{ "DEVICE", "name of the device node", COL_DEVNAME, COL_DT_STRING, 0 },
+	{ "MAJ:MIN", "major:minor device number",
+		COL_DEVNUM, COL_DT_STRING, 0 },
+	{ "NAME", "device name string", COL_NAME, COL_DT_STRING, 0 },
+	{ "TYPE", "device type", COL_TYPE, COL_DT_STRING, 0 },
+	{ "SIZE", "size of the device", COL_SIZE, COL_DT_SIZE, 0 },
+	{ "EB-SIZE", "erase block size", COL_EBSIZE, COL_DT_SIZE, 0 },
+	{ "EB-COUNT", "number of erase blocks", COL_EBCOUNT, COL_DT_NUMBER, 0 },
+	{ "MIN-IO", "minimum I/O size", COL_MINIO, COL_DT_SIZE, 0 },
+	{ "SUB-SIZE", "subpage size", COL_SUBSIZE, COL_DT_SIZE, 0 },
+	{ "OOB-SIZE", "out of band data size", COL_OOBSIZE, COL_DT_SIZE, 0 },
+	{ "RO", "read-only device", COL_RO, COL_DT_BOOL, 0 },
+	{ "CORRUPTED", "wheather an UBI volume is corrupted",
+		COL_CORRUPTED, COL_DT_BOOL, 0 },
+	{ "REGIONS", "number of additional erase regions",
+		COL_REGION, COL_DT_NUMBER, 0 },
+	{ "BB", "wheather the MTD device may have bad eraseblocks",
+		COL_BB, COL_DT_BOOL, 0 },
+	{ "MAX-EC", "current highest erase counter value on UBI devices",
+		COL_MAXEC, COL_DT_NUMBER, 0 },
+	{ "FREE", "available bytes on an UBI device or volume",
+		COL_FREE, COL_DT_SIZE, 0 },
+	{ "FREE-LEB", "available LEBs on an UBI device or volume",
+		COL_FREE_LEB, COL_DT_NUMBER, 0 },
+	{ "BAD-COUNT", "number of bad physical eraseblocks",
+		COL_BAD_COUNT, COL_DT_NUMBER, 0 },
+	{ "BAD-RSVD", "number of reserved eraseblocks for bad block handling",
+		COL_BAD_RSVD, COL_DT_NUMBER, 0 },
+};
+
+static NORETURN void usage(int status)
+{
+	FILE *outstream = status == EXIT_SUCCESS ? stdout : stderr;
+	size_t i, len, max_len = 0;
+
+	fputs(
+"Usage: "PROGRAM_NAME" [options] [<device> ...]\n\n"
+"List information about memory technology devices.\n\n"
+"Options:\n"
+"  -u, --si-units       Scale sizes by factors of 1000 instead of 1024\n"
+"  -b, --bytes          Print sizes in bytes\n"
+"  -i, --ascii          Use ascii characters only\n"
+"  -l, --list           Use list output format (default)\n"
+"  -n, --noheadings     Don't print a heading\n"
+"  -r, --raw            Use raw output format\n"
+"  -P, --pairs          Use key=\"value\" output format\n"
+"  -J, --json           Use JSON output format\n"
+"  -o, --output <list>  Comma seperated list of columns to print\n"
+"  -O, --output-all     Print all columns\n"
+"  -x, --sort <column>  Sort output by <column>\n"
+"  -m, --no-ubi         Do not display information about UBI devices/volumes\n"
+"\n"
+"  -h, --help           Display this help text and exit\n"
+"  -V, --version        Output version information and exit\n"
+"\n"
+"Available columns (for --output, --sort):\n",
+	outstream);
+
+	for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
+		len = strlen(cols[i].name);
+		max_len = len > max_len ? len : max_len;
+	}
+
+	for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
+		fprintf(outstream, "  %*s  %s\n", (int)max_len, cols[i].name,
+			cols[i].desc);
+	}
+
+	fputs("\nFor more details see "PROGRAM_NAME"(8).\n", stdout);
+	exit(status);
+}
+
+static NORETURN void version(int status)
+{
+	common_print_version();
+	fputs(
+"Copyright (C) 2017 David Oberhollenzer - sigma star gmbh\n"
+"License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n\n"
+"Written by David Oberhollenzer.\n",
+		stdout);
+	exit(status);
+}
+
+static struct column *column_by_name(const char *name, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
+		if (strncmp(cols[i].name, name, len) != 0)
+			continue;
+		if (strlen(cols[i].name) == len)
+			return cols + i;
+	}
+
+	return NULL;
+}
+
+static int process_col_list(const char *list)
+{
+	struct column *col;
+	const char *end;
+	size_t len;
+
+	if (*list == '+') {
+		++list;
+	} else {
+		num_selected = 0;
+	}
+
+	while (*list) {
+		end = strchrnul(list, ',');
+		len = end - list;
+
+		col = column_by_name(list, len);
+		if (!col) {
+			fprintf(stderr, "Unknown column '%.*s'\n",
+				(int)len, list);
+			return -1;
+		}
+
+		if (num_selected == max_selected) {
+			max_selected = max_selected ? max_selected * 2 : 10;
+			selected = xrealloc(selected, max_selected *
+							sizeof(*selected));
+		}
+
+		selected[num_selected++] = col;
+		list = *end ? end + 1 : end;
+	}
+	return 0;
+}
+
+static void select_all(void)
+{
+	size_t i;
+
+	num_selected = sizeof(cols) / sizeof(cols[0]);
+
+	if (max_selected < num_selected) {
+		max_selected = num_selected;
+		selected = xrealloc(selected, max_selected * sizeof(*selected));
+	}
+
+	for (i = 0; i < num_selected; ++i)
+		selected[i] = cols + i;
+}
+
+static void process_args(int argc, char **argv)
+{
+	int i;
+
+	process_col_list(default_cols);
+
+	while (1) {
+		i = getopt_long(argc, argv, short_opts, long_opts, NULL);
+		if (i == -1)
+			break;
+
+		switch (i) {
+		case 'x':
+			sort_by = column_by_name(optarg, strlen(optarg));
+			if (!sort_by) {
+				fprintf(stderr, "Unknown column '%s'\n",
+					optarg);
+				goto fail;
+			}
+			break;
+		case 'o':
+			if (process_col_list(optarg) != 0)
+				goto fail;
+			break;
+		case 'O':
+			select_all();
+			break;
+		case 'i': flags |= FLAG_ASCII; break;
+		case 'J': flags |= FLAG_JSON; break;
+		case 'P': flags |= FLAG_PAIRS; break;
+		case 'l': flags |= FLAG_LIST; break;
+		case 'b': flags |= FLAG_BYTES; break;
+		case 'r': flags |= FLAG_RAW; break;
+		case 'u': flags |= FLAG_SI; break;
+		case 'n': flags |= FLAG_NO_HEADING; break;
+		case 'm': flags |= FLAG_NO_UBI; break;
+		case 'h': usage(EXIT_SUCCESS);
+		case 'V': version(EXIT_SUCCESS);
+		default: usage(EXIT_FAILURE);
+		}
+	}
+
+	i = flags & (FLAG_LIST|FLAG_PAIRS|FLAG_RAW|FLAG_JSON);
+
+	if (i & (i - 1)) {
+		fputs(PROGRAM_NAME": these options are mutually exclusive: "
+			"--list --pairs --raw --json\n", stderr);
+		goto fail;
+	} else if (!i) {
+		flags |= FLAG_LIST;
+	}
+
+	/*if (optind < argc)
+		list_arg = optind;*/
+	return;
+fail:
+	fputs("Try `"PROGRAM_NAME" --help` for more information\n\n", stderr);
+	exit(EXIT_FAILURE);
+}
+
+static const char *tree_prefix(bool is_last)
+{
+	if (is_last)
+		return (flags & FLAG_ASCII) ? "`-" : "└─";
+	return (flags & FLAG_ASCII) ? "|-" : "├─";
+}
+
+static size_t count_chars(const char *str)
+{
+	size_t count = 0;
+	while (*str) {
+		if (((*str) & 0xC0) != 0x80)
+			++count;
+		++str;
+	}
+	return count;
+}
+
+static void devno_to_string(char *buffer, int major, int minor)
+{
+	sprintf(buffer, flags & FLAG_LIST ? "%3d:%d" : "%d:%d", major, minor);
+}
+
+static void bool_to_string(char *buffer, int value)
+{
+	if (flags & FLAG_JSON)
+		strcpy(buffer, value ? "true" : "false");
+	else
+		strcpy(buffer, value ? "1" : "0");
+}
+
+static void size_to_string(char *buffer, long long int size)
+{
+	static const char *bcdmap = "0112334456678899";
+	static const char *suffix = "KMGTPE";
+	int scale, idx, i, remainder = 0;
+
+	if (flags & FLAG_BYTES) {
+		sprintf(buffer, "%lld", size);
+		return;
+	}
+
+	scale = flags & FLAG_SI ? 1000 : 1024;
+
+	for (idx = -1; size >= scale && (idx < 0 || suffix[idx]); ++idx) {
+		if (remainder >= (scale / 2)) {
+			remainder = 0;
+			size = (size / scale) + 1;
+		} else {
+			remainder = size % scale;
+			size /= scale;
+		}
+	}
+
+	i = sprintf(buffer, "%lld", size);
+
+	remainder = (remainder >> 6) & 0x0F;
+	if (remainder) {
+		buffer[i++] = '.';
+		buffer[i++] = bcdmap[remainder];
+	}
+	if (idx >= 0)
+		buffer[i++] = suffix[idx];
+	buffer[i] = '\0';
+}
+
+static void print_json_string(const char *value)
+{
+	static const char *jsonrepl = "nrtfb", *jsonesc = "\n\r\t\f\b";
+	const char *ptr;
+
+	fputc('"', stdout);
+	for (; *value; ++value) {
+		ptr = strchr(jsonesc, *value);
+		if (ptr) {
+			fputc('\\', stdout);
+			fputc(jsonrepl[ptr - jsonesc], stdout);
+		} else if (*value == '\\' || *value == '"') {
+			fputc('\\', stdout);
+			fputc(*value, stdout);
+		} else if (isascii(*value) &&
+			(iscntrl(*value) || !isprint(*value))) {
+			fprintf(stdout, "\\u%04X", *value);
+		} else {
+			fputc(*value, stdout);
+		}
+	}
+	fputc('"', stdout);
+}
+
+static void print_escaped(const char *value)
+{
+	while (*value) {
+		if (iscntrl(*value) || !isprint(*value) ||
+			*value == '\\' || *value == '"') {
+			fprintf(stdout, "\\x%02X", *(value++));
+		} else {
+			fputc(*(value++), stdout);
+		}
+	}
+}
+
+static void print_padded(const char *value, bool numeric, size_t width)
+{
+	size_t i;
+
+	if (numeric) {
+		fprintf(stdout, "%*s", (int)width, value);
+	} else {
+		for (i = 0; i < width && *value; ++i) {
+			fputc(*(value++), stdout);
+			while (((*value) & 0xC0) == 0x80)
+				fputc(*(value++), stdout);
+		}
+
+		for (; i < width; ++i)
+			fputc(' ', stdout);
+	}
+}
+
+static void print_column(struct column *col, const char *value,
+			bool is_first, int level)
+{
+	bool numeric = false;
+	const char *key;
+	size_t colw;
+
+	if (col->datatype == COL_DT_NUMBER || col->datatype == COL_DT_SIZE ||
+		col->datatype == COL_DT_BOOL) {
+		numeric = true;
+	}
+
+	if (flags & FLAG_JSON) {
+		if ((col->datatype == COL_DT_SIZE) && !(flags & FLAG_BYTES))
+			numeric = false;
+
+		if (!is_first)
+			fputs(",\n", stdout);
+
+		while (level--)
+			fputc('\t', stdout);
+
+		fputc('"', stdout);
+		for (key = col->name; *key; ++key)
+			fputc(isupper(*key) ? tolower(*key) : *key, stdout);
+		fputs("\": ", stdout);
+
+		if (numeric) {
+			fputs(value, stdout);
+		} else {
+			print_json_string(value);
+		}
+	} else if (flags & FLAG_DRYRUN) {
+		colw = count_chars(value);
+		col->width = colw > col->width ? colw : col->width;
+	} else if (flags & FLAG_PAIRS) {
+		if (!is_first)
+			fputc(' ', stdout);
+		fprintf(stdout, "%s=\"", col->name);
+		print_escaped(value);
+		fputs("\"", stdout);
+	} else if (flags & FLAG_RAW) {
+		if (!is_first)
+			fputc(' ', stdout);
+		print_escaped(value);
+	} else if (flags & FLAG_LIST) {
+		if (!is_first)
+			fputc(' ', stdout);
+		print_padded(value, numeric, col->width);
+	}
+}
+
+static size_t print_mtd_device(struct mtd_dev_info *info)
+{
+	size_t i, count = 0;
+	const char *value;
+	char buffer[128];
+
+	for (i = 0; i < num_selected; ++i) {
+		value = buffer;
+		switch (selected[i]->type) {
+		case COL_DEVNAME:
+			sprintf(buffer, "mtd%d", info->mtd_num);
+			break;
+		case COL_DEVNUM:
+			devno_to_string(buffer, info->major, info->minor);
+			break;
+		case COL_TYPE:
+			value = info->type_str;
+			break;
+		case COL_NAME:
+			value = info->name;
+			break;
+		case COL_SIZE:
+			size_to_string(buffer, info->size);
+			break;
+		case COL_EBSIZE:
+			size_to_string(buffer, info->eb_size);
+			break;
+		case COL_EBCOUNT:
+			sprintf(buffer, "%d", info->eb_cnt);
+			break;
+		case COL_MINIO:
+			size_to_string(buffer, info->min_io_size);
+			break;
+		case COL_SUBSIZE:
+			size_to_string(buffer, info->subpage_size);
+			break;
+		case COL_OOBSIZE:
+			size_to_string(buffer, info->oob_size);
+			break;
+		case COL_RO:
+			bool_to_string(buffer, !info->writable);
+			break;
+		case COL_BB:
+			bool_to_string(buffer, !info->bb_allowed);
+			break;
+		case COL_REGION:
+			sprintf(buffer, "%d", info->region_cnt);
+			break;
+		default:
+			if (flags & FLAG_JSON)
+				continue;
+			buffer[0] = '\0';
+			break;
+		}
+		print_column(selected[i], value, i == 0, 2);
+		++count;
+	}
+	return count;
+}
+
+static size_t print_ubi_device(struct mtd_dev_info *mtd,
+				struct ubi_dev_info *info)
+{
+	size_t i, count = 0;
+	char value[128];
+
+	for (i = 0; i < num_selected; ++i) {
+		switch (selected[i]->type) {
+		case COL_DEVNAME:
+			if (flags & FLAG_LIST) {
+				sprintf(value, "%subi%d", tree_prefix(true),
+							info->dev_num);
+			} else {
+				sprintf(value, "ubi%d", info->dev_num);
+			}
+			break;
+		case COL_DEVNUM:
+			devno_to_string(value, info->major, info->minor);
+			break;
+		case COL_SIZE:
+			size_to_string(value, info->total_bytes);
+			break;
+		case COL_EBSIZE:
+			size_to_string(value, info->leb_size);
+			break;
+		case COL_EBCOUNT:
+			sprintf(value, "%d", info->total_lebs);
+			break;
+		case COL_MINIO:
+			size_to_string(value, info->min_io_size);
+			break;
+		case COL_MAXEC:
+			sprintf(value, "%lld", info->max_ec);
+			break;
+		case COL_FREE:
+			size_to_string(value, info->avail_bytes);
+			break;
+		case COL_FREE_LEB:
+			sprintf(value, "%d", info->avail_lebs);
+			break;
+		case COL_BAD_COUNT:
+			sprintf(value, "%d", info->bad_count);
+			break;
+		case COL_BAD_RSVD:
+			sprintf(value, "%d", info->bad_rsvd);
+			break;
+		case COL_RO:
+			bool_to_string(value, !mtd->writable);
+			break;
+		default:
+			if (flags & FLAG_JSON)
+				continue;
+			value[0] = '\0';
+			break;
+		}
+		print_column(selected[i], value, i == 0, 3);
+		++count;
+	}
+	return count;
+}
+
+static size_t print_ubi_vol(struct mtd_dev_info *mtd, struct ubi_dev_info *dev,
+				struct ubi_vol_info *info, bool is_last)
+{
+	size_t i, count = 0;
+	const char *value;
+	char buffer[128];
+	int used;
+
+	for (i = 0; i < num_selected; ++i) {
+		value = buffer;
+		switch (selected[i]->type) {
+		case COL_DEVNAME:
+			if (flags & FLAG_LIST) {
+				sprintf(buffer, "  %subi%d_%d",
+						tree_prefix(is_last),
+						info->dev_num, info->vol_id);
+			} else {
+				sprintf(buffer, "ubi%d_%d", info->dev_num,
+							info->vol_id);
+			}
+			break;
+		case COL_DEVNUM:
+			devno_to_string(buffer, info->major, info->minor);
+			break;
+		case COL_TYPE:
+			if (info->type == UBI_DYNAMIC_VOLUME) {
+				value = "dynamic";
+			} else {
+				value = "static";
+			}
+			break;
+		case COL_NAME:
+			value = info->name;
+			break;
+		case COL_SIZE:
+			size_to_string(buffer, info->rsvd_bytes);
+			break;
+		case COL_EBSIZE:
+			size_to_string(buffer, info->leb_size);
+			break;
+		case COL_EBCOUNT:
+			sprintf(buffer, "%d", info->rsvd_lebs);
+			break;
+		case COL_MINIO:
+			size_to_string(buffer, dev->min_io_size);
+			break;
+		case COL_FREE:
+			size_to_string(buffer,
+					info->rsvd_bytes - info->data_bytes);
+			break;
+		case COL_FREE_LEB:
+			used = info->data_bytes / info->leb_size;
+			sprintf(buffer, "%d", info->rsvd_lebs - used);
+			break;
+		case COL_RO:
+			bool_to_string(buffer, !mtd->writable);
+			break;
+		case COL_CORRUPTED:
+			bool_to_string(buffer, info->corrupted);
+			break;
+		default:
+			if (flags & FLAG_JSON)
+				continue;
+			buffer[0] = '\0';
+			break;
+		}
+		print_column(selected[i], value, i == 0, 4);
+		++count;
+	}
+	return count;
+}
+
+static void print_list(void)
+{
+	struct ubi_node *ubi;
+	bool is_last;
+	size_t i;
+	int j;
+
+	if (!(flags & FLAG_NO_HEADING)) {
+		if (flags & (FLAG_DRYRUN | FLAG_RAW)) {
+			for (i = 0; i < num_selected; ++i)
+				selected[i]->width = strlen(selected[i]->name);
+		}
+
+		if (!(flags & FLAG_DRYRUN)) {
+			for (i = 0; i < num_selected; ++i) {
+				fprintf(stdout, "%-*s ",
+					(int)selected[i]->width,
+					selected[i]->name);
+			}
+			fputc('\n', stdout);
+		}
+	}
+
+	for (i = 0; i < num_mtd_devices; ++i) {
+		print_mtd_device(&mtd_dev[i].info);
+		if (!(flags & FLAG_DRYRUN))
+			fputc('\n', stdout);
+
+		ubi = mtd_dev[i].ubi;
+		if (!ubi)
+			continue;
+
+		print_ubi_device(&mtd_dev[i].info, &ubi->info);
+		if (!(flags & FLAG_DRYRUN))
+			fputc('\n', stdout);
+
+		for (j = 0; j < ubi->info.vol_count; ++j) {
+			is_last = (j == (ubi->info.vol_count - 1));
+			print_ubi_vol(&mtd_dev[i].info, &ubi->info,
+					ubi->vol_info + j, is_last);
+			if (!(flags & FLAG_DRYRUN))
+				fputc('\n', stdout);
+		}
+	}
+}
+
+static void print_pairs(void)
+{
+	struct ubi_node *ubi;
+	int i, j;
+
+	for (i = 0; i < num_mtd_devices; ++i) {
+		print_mtd_device(&mtd_dev[i].info);
+		fputc('\n', stdout);
+
+		ubi = mtd_dev[i].ubi;
+		if (ubi) {
+			print_ubi_device(&mtd_dev[i].info, &ubi->info);
+			fputc('\n', stdout);
+
+			for (j = 0; j < ubi->info.vol_count; ++j) {
+				print_ubi_vol(&mtd_dev[i].info, &ubi->info,
+						ubi->vol_info + j, false);
+				fputc('\n', stdout);
+			}
+		}
+	}
+}
+
+static void print_json(void)
+{
+	struct ubi_node *ubi;
+	int i, j;
+
+	fputs("{\n\t\"mtddevices\": [", stdout);
+
+	for (i = 0; i < num_mtd_devices; ++i) {
+		fputs(i ? ",{\n" : "{\n", stdout);
+		if (print_mtd_device(&mtd_dev[i].info) > 0)
+			fputs(",\n", stdout);
+
+		ubi = mtd_dev[i].ubi;
+		if (ubi) {
+			fputs("\t\t\"ubi\": {\n", stdout);
+			if (print_ubi_device(&mtd_dev[i].info, &ubi->info) > 0)
+				fputs(",\n", stdout);
+
+			fputs("\t\t\t\"volumes\": [", stdout);
+
+			for (j = 0; j < ubi->info.vol_count; ++j) {
+				fputs(j ? ",{\n" : "{\n", stdout);
+				print_ubi_vol(&mtd_dev[i].info, &ubi->info,
+						ubi->vol_info + j, false);
+				fputs("\n\t\t\t}", stdout);
+			}
+
+			fputs("]\n\t\t}\n", stdout);
+		} else if (!(flags & FLAG_NO_UBI)) {
+			fputs("\t\t\"ubi\": null\n", stdout);
+		}
+		fputs("\t}", stdout);
+	}
+
+	fputs("]\n}\n", stdout);
+}
+
+int main(int argc, char **argv)
+{
+	int ret, status = EXIT_FAILURE;
+	libmtd_t lib_mtd;
+	libubi_t lib_ubi;
+
+	process_args(argc, argv);
+
+	lib_mtd = libmtd_open();
+	if (lib_mtd) {
+		ret = scan_mtd(lib_mtd);
+		libmtd_close(lib_mtd);
+		if (ret)
+			goto out;
+	} else {
+		if (errno) {
+			perror("libmtd_open");
+			return EXIT_FAILURE;
+		}
+		return EXIT_SUCCESS;
+	}
+
+	if (!(flags & FLAG_NO_UBI)) {
+		lib_ubi = libubi_open();
+		if (lib_ubi) {
+			ret = scan_ubi(lib_ubi);
+			libubi_close(lib_ubi);
+			if (ret)
+				goto out;
+		} else if (errno) {
+			perror("libubi_open");
+			goto out;
+		}
+	}
+
+	if (flags & FLAG_JSON) {
+		print_json();
+	} else if (flags & FLAG_PAIRS) {
+		print_pairs();
+	} else {
+		flags |= FLAG_DRYRUN;
+		print_list();
+		flags &= ~FLAG_DRYRUN;
+		print_list();
+	}
+
+	status = EXIT_SUCCESS;
+out:
+	scan_free();
+	free(selected);
+	return status;
+}

+ 67 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd.h

@@ -0,0 +1,67 @@
+#ifndef LSMTD_H
+#define LSMTD_H
+
+#define PROGRAM_NAME "lsmtd"
+#include "common.h"
+#include "xalloc.h"
+
+#include <libmtd.h>
+#include <libubi.h>
+
+#define COL_DEVNAME 1
+#define COL_DEVNUM 2
+#define COL_TYPE 3
+#define COL_NAME 4
+#define COL_SIZE 5
+#define COL_EBSIZE 6
+#define COL_EBCOUNT 7
+#define COL_MINIO 8
+#define COL_SUBSIZE 9
+#define COL_OOBSIZE 10
+#define COL_MAXEC 11
+#define COL_FREE 12
+#define COL_FREE_LEB 13
+#define COL_BAD_COUNT 14
+#define COL_BAD_RSVD 15
+#define COL_RO 16
+#define COL_BB 17
+#define COL_REGION 18
+#define COL_CORRUPTED 19
+
+#define COL_DT_STRING 1
+#define COL_DT_NUMBER 2
+#define COL_DT_SIZE 3
+#define COL_DT_BOOL 4
+
+struct ubi_node {
+	struct ubi_dev_info info;
+	struct ubi_vol_info *vol_info;
+};
+
+struct mtd_node {
+	struct mtd_dev_info info;
+	struct ubi_node *ubi;
+};
+
+struct column {
+	const char *name;
+	const char *desc;
+	int type;
+	int datatype;
+	size_t width;
+};
+
+extern struct ubi_node *ubi_dev;
+extern int num_ubi_devices;
+
+extern struct mtd_node *mtd_dev;
+extern int num_mtd_devices;
+
+extern struct column *sort_by;
+
+int scan_mtd(libmtd_t lib_mtd);
+int scan_ubi(libubi_t lib_ubi);
+void scan_free(void);
+
+#endif /* LSMTD_H */
+

+ 224 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/lsmtd_scan.c

@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 David Oberhollenzer - sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA.
+ *
+ * Author: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
+ */
+#include "lsmtd.h"
+
+struct ubi_node *ubi_dev;
+int num_ubi_devices;
+
+struct mtd_node *mtd_dev;
+int num_mtd_devices;
+
+static int compare_mtd(const void *l, const void *r)
+{
+	const struct mtd_node *a = l, *b = r;
+
+	switch (sort_by->type) {
+	case COL_DEVNAME:
+		return a->info.mtd_num - b->info.mtd_num;
+	case COL_DEVNUM:
+		if (a->info.major == b->info.major)
+			return a->info.minor - b->info.minor;
+		return a->info.major - b->info.major;
+	case COL_TYPE:
+		return strcmp(a->info.type_str, b->info.type_str);
+	case COL_NAME:
+		return strcmp(a->info.name, b->info.name);
+	case COL_SIZE:
+		if (a->info.size < b->info.size)
+			return -1;
+		if (a->info.size > b->info.size)
+			return 1;
+		return 0;
+	case COL_EBSIZE:
+		return a->info.eb_size - b->info.eb_size;
+	case COL_EBCOUNT:
+		return a->info.eb_cnt - b->info.eb_cnt;
+	case COL_MINIO:
+		return a->info.min_io_size - b->info.min_io_size;
+	case COL_SUBSIZE:
+		return a->info.subpage_size - b->info.subpage_size;
+	case COL_OOBSIZE:
+		return a->info.oob_size - b->info.oob_size;
+	case COL_RO:
+		return !a->info.writable - !b->info.writable;
+	case COL_BB:
+		return a->info.bb_allowed - b->info.bb_allowed;
+	case COL_REGION:
+		return a->info.region_cnt - b->info.region_cnt;
+	}
+	return 0;
+}
+
+static int compare_ubi_vol(const void *l, const void *r)
+{
+	const struct ubi_vol_info *a = l, *b = r;
+	long long all, bll;
+
+	switch (sort_by->type) {
+	case COL_DEVNAME:
+		if (a->dev_num == b->dev_num)
+			return a->vol_id - b->vol_id;
+		return a->dev_num - b->dev_num;
+	case COL_DEVNUM:
+		if (a->major == b->major)
+			return a->minor - b->minor;
+		return a->major - b->major;
+	case COL_TYPE:
+		if (a->type == b->type)
+			return 0;
+		return a->type == UBI_DYNAMIC_VOLUME ? 1 : -1;
+	case COL_NAME:
+		return strcmp(a->name, b->name);
+	case COL_SIZE:
+		all = a->rsvd_bytes;
+		bll = b->rsvd_bytes;
+		goto out_ll;
+	case COL_EBSIZE:
+		return a->leb_size - b->leb_size;
+	case COL_EBCOUNT:
+		return a->rsvd_lebs - b->rsvd_lebs;
+	case COL_FREE:
+	case COL_FREE_LEB:
+		all = (a->rsvd_bytes - a->data_bytes);
+		bll = (b->rsvd_bytes - b->data_bytes);
+		goto out_ll;
+	case COL_CORRUPTED:
+		return a->corrupted - b->corrupted;
+	}
+	return 0;
+out_ll:
+	return (all < bll) ? -1 : ((all > bll) ? 1 : 0);
+}
+
+static int scan_ubi_device(libubi_t lib_ubi, struct ubi_node *dev)
+{
+	int lo = dev->info.lowest_vol_id, hi = dev->info.highest_vol_id;
+	int i, idx = 0, dev_num = dev->info.dev_num;
+	struct ubi_vol_info vol_info;
+
+	if (!dev->info.vol_count)
+		return 0;
+
+	dev->vol_info = xcalloc(dev->info.vol_count, sizeof(dev->vol_info[0]));
+
+	for (i = lo; i <= hi; ++i) {
+		if (ubi_get_vol_info1(lib_ubi, dev_num, i, &vol_info)) {
+			if (errno == ENOENT)
+				continue;
+			perror("ubi_get_vol_info1");
+			return -1;
+		}
+
+		dev->vol_info[idx++] = vol_info;
+	}
+
+	if (sort_by)
+		qsort(dev->vol_info, idx, sizeof(vol_info), compare_ubi_vol);
+	return 0;
+}
+
+int scan_ubi(libubi_t lib_ubi)
+{
+	struct ubi_dev_info dev_info;
+	struct ubi_info info;
+	int i, j;
+
+	if (ubi_get_info(lib_ubi, &info))
+		return -1;
+
+	if (!info.dev_count)
+		return 0;
+
+	ubi_dev = xcalloc(info.dev_count, sizeof(ubi_dev[0]));
+
+	for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) {
+		if (!ubi_dev_present(lib_ubi, i))
+			continue;
+
+		if (ubi_get_dev_info1(lib_ubi, i, &dev_info)) {
+			perror("ubi_get_dev_info1");
+			return -1;
+		}
+
+		for (j = 0; j < num_mtd_devices; ++j) {
+			if (mtd_dev[j].info.mtd_num == dev_info.mtd_num)
+				break;
+		}
+
+		if (j == num_mtd_devices) {
+			fprintf(stderr, "Cannot find mtd device %d refered to "
+				"by ubi device %d\n", dev_info.mtd_num,
+				dev_info.dev_num);
+			return -1;
+		}
+
+		ubi_dev[num_ubi_devices].info = dev_info;
+		mtd_dev[j].ubi = ubi_dev + num_ubi_devices;
+
+		if (scan_ubi_device(lib_ubi, ubi_dev + num_ubi_devices))
+			return -1;
+
+		++num_ubi_devices;
+	}
+	return 0;
+}
+
+int scan_mtd(libmtd_t lib_mtd)
+{
+	struct mtd_dev_info dev_info;
+	struct mtd_info info;
+	int i, idx = 0;
+
+	if (mtd_get_info(lib_mtd, &info))
+		return -1;
+
+	if (!info.mtd_dev_cnt)
+		return 0;
+
+	mtd_dev = xcalloc(info.mtd_dev_cnt, sizeof(mtd_dev[0]));
+
+	for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; ++i) {
+		if (!mtd_dev_present(lib_mtd, i))
+			continue;
+
+		if (mtd_get_dev_info1(lib_mtd, i, &dev_info)) {
+			perror("mtd_get_dev_info1");
+			return -1;
+		}
+
+		memcpy(&(mtd_dev[idx++].info), &dev_info, sizeof(dev_info));
+	}
+
+	num_mtd_devices = idx;
+
+	if (sort_by)
+		qsort(mtd_dev, num_mtd_devices, sizeof(*mtd_dev), compare_mtd);
+	return 0;
+}
+
+void scan_free(void)
+{
+	int i;
+
+	for (i = 0; i < num_ubi_devices; ++i)
+		free(ubi_dev[i].vol_info);
+
+	free(ubi_dev);
+	free(mtd_dev);
+}

+ 22 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/mcast_image.h

@@ -0,0 +1,22 @@
+#include <stdint.h>
+
+#define PKT_SIZE 2820
+
+struct image_pkt_hdr {
+	uint32_t resend;
+	uint32_t totcrc;
+	uint32_t nr_blocks;
+	uint32_t blocksize;
+	uint32_t block_crc;
+	uint32_t block_nr;
+	uint32_t pkt_sequence;
+	uint16_t pkt_nr;
+	uint16_t nr_pkts;
+	uint32_t thislen;
+	uint32_t thiscrc;
+};
+
+struct image_pkt {
+	struct image_pkt_hdr hdr;
+	unsigned char data[PKT_SIZE];
+};

+ 396 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/mtd_debug.c

@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham@2d3d.co.za>
+ * 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 author nor the names of other contributors
+ *	  may be used to endorse or promote products derived from this software
+ *	  without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+#define PROGRAM_NAME "mtd_debug"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mtd/mtd-user.h>
+#include "common.h"
+
+/*
+ * MEMGETINFO
+ */
+static int getmeminfo(int fd, struct mtd_info_user *mtd)
+{
+	return ioctl(fd, MEMGETINFO, mtd);
+}
+
+/*
+ * MEMERASE
+ */
+static int memerase(int fd, struct erase_info_user *erase)
+{
+	return ioctl(fd, MEMERASE, erase);
+}
+
+/*
+ * MEMGETREGIONCOUNT
+ * MEMGETREGIONINFO
+ */
+static int getregions(int fd, struct region_info_user *regions, int *n)
+{
+	int i, err;
+	err = ioctl(fd, MEMGETREGIONCOUNT, n);
+	if (err)
+		return err;
+	for (i = 0; i < *n; i++) {
+		regions[i].regionindex = i;
+		err = ioctl(fd, MEMGETREGIONINFO, &regions[i]);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int erase_flash(int fd, u_int32_t offset, u_int32_t bytes)
+{
+	int err;
+	struct erase_info_user erase;
+	erase.start = offset;
+	erase.length = bytes;
+	err = memerase(fd, &erase);
+	if (err < 0) {
+		perror("MEMERASE");
+		return 1;
+	}
+	fprintf(stderr, "Erased %d bytes from address 0x%.8x in flash\n", bytes, offset);
+	return 0;
+}
+
+static void printsize(u_int32_t x)
+{
+	int i;
+	static const char *flags = "KMGT";
+	printf("%u ", x);
+	for (i = 0; x >= 1024 && flags[i] != '\0'; i++)
+		x /= 1024;
+	i--;
+	if (i >= 0)
+		printf("(%u%c)", x, flags[i]);
+}
+
+static int flash_to_file(int fd, off_t offset, size_t len, const char *filename)
+{
+	u_int8_t *buf = NULL;
+	int outfd, err;
+	int size = len * sizeof(u_int8_t);
+	int n = len;
+
+	if (offset != lseek(fd, offset, SEEK_SET)) {
+		perror("lseek()");
+		return 1;
+	}
+	outfd = creat(filename, 0666);
+	if (outfd < 0) {
+		perror("creat()");
+		return 1;
+	}
+
+retry:
+	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
+#define BUF_SIZE	(64 * 1024 * sizeof(u_int8_t))
+		fprintf(stderr, "%s: malloc(%#x)\n", __func__, size);
+		if (size != BUF_SIZE) {
+			size = BUF_SIZE;
+			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
+			goto retry;
+		}
+		perror("malloc()");
+		goto fail;
+	}
+	do {
+		if (n <= size)
+			size = n;
+		err = read(fd, buf, size);
+		if (err < 0) {
+			fprintf(stderr, "%s: read, size %#x, n %#x\n", __func__, size, n);
+			perror("read()");
+			goto fail;
+		}
+		if (err < size) {
+			fprintf(stderr, "%s: short read, requested %#x, read %#x\n", __func__, size, err);
+		}
+		err = write(outfd, buf, err);
+		if (err < 0) {
+			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
+			perror("write()");
+			goto fail;
+		}
+		if (err != size) {
+			fprintf(stderr, "Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n", filename, err, size);
+			goto fail;
+		}
+		n -= size;
+	} while (n > 0);
+
+	if (buf != NULL)
+		free(buf);
+	close(outfd);
+	printf("Copied %zu bytes from address 0x%.8llx in flash to %s\n", len, (unsigned long long)offset, filename);
+	return 0;
+fail:
+	close(outfd);
+	free(buf);
+	return 1;
+}
+
+static int file_to_flash(int fd, off_t offset, u_int32_t len,
+			 const char *filename)
+{
+	u_int8_t *buf = NULL;
+	FILE *fp;
+	int err;
+	int size = len * sizeof(u_int8_t);
+	int n = len;
+
+	if (offset != lseek(fd, offset, SEEK_SET)) {
+		perror("lseek()");
+		return 1;
+	}
+	if ((fp = fopen(filename, "r")) == NULL) {
+		perror("fopen()");
+		return 1;
+	}
+retry:
+	if ((buf = (u_int8_t *) malloc(size)) == NULL) {
+		fprintf(stderr, "%s: malloc(%#x) failed\n", __func__, size);
+		if (size != BUF_SIZE) {
+			size = BUF_SIZE;
+			fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
+			goto retry;
+		}
+		perror("malloc()");
+		fclose(fp);
+		return 1;
+	}
+	do {
+		if (n <= size)
+			size = n;
+		if (fread(buf, size, 1, fp) != 1 || ferror(fp)) {
+			fprintf(stderr, "%s: fread, size %#x, n %#x\n", __func__, size, n);
+			perror("fread()");
+			free(buf);
+			fclose(fp);
+			return 1;
+		}
+		err = write(fd, buf, size);
+		if (err < 0) {
+			fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
+			perror("write()");
+			free(buf);
+			fclose(fp);
+			return 1;
+		}
+		n -= size;
+	} while (n > 0);
+
+	if (buf != NULL)
+		free(buf);
+	fclose(fp);
+	printf("Copied %d bytes from %s to address 0x%.8llx in flash\n", len, filename, (unsigned long long)offset);
+	return 0;
+}
+
+static int showinfo(int fd)
+{
+	int i, err, n;
+	struct mtd_info_user mtd;
+	static struct region_info_user region[1024];
+
+	err = getmeminfo(fd, &mtd);
+	if (err < 0) {
+		perror("MEMGETINFO");
+		return 1;
+	}
+
+	err = getregions(fd, region, &n);
+	if (err < 0) {
+		perror("MEMGETREGIONCOUNT");
+		return 1;
+	}
+
+	printf("mtd.type = ");
+	switch (mtd.type) {
+		case MTD_ABSENT:
+			printf("MTD_ABSENT");
+			break;
+		case MTD_RAM:
+			printf("MTD_RAM");
+			break;
+		case MTD_ROM:
+			printf("MTD_ROM");
+			break;
+		case MTD_NORFLASH:
+			printf("MTD_NORFLASH");
+			break;
+		case MTD_NANDFLASH:
+			printf("MTD_NANDFLASH");
+			break;
+		case MTD_MLCNANDFLASH:
+			printf("MTD_MLCNANDFLASH");
+			break;
+		case MTD_DATAFLASH:
+			printf("MTD_DATAFLASH");
+			break;
+		case MTD_UBIVOLUME:
+			printf("MTD_UBIVOLUME");
+			break;
+		default:
+			printf("(unknown type - new MTD API maybe?)");
+	}
+
+	printf("\nmtd.flags = ");
+	if (mtd.flags == MTD_CAP_ROM)
+		printf("MTD_CAP_ROM");
+	else if (mtd.flags == MTD_CAP_RAM)
+		printf("MTD_CAP_RAM");
+	else if (mtd.flags == MTD_CAP_NORFLASH)
+		printf("MTD_CAP_NORFLASH");
+	else if (mtd.flags == MTD_CAP_NANDFLASH)
+		printf("MTD_CAP_NANDFLASH");
+	else {
+		int first = 1;
+		static struct {
+			const char *name;
+			int value;
+		} flags[] =
+		{
+			{ "MTD_WRITEABLE", MTD_WRITEABLE },
+			{ "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
+			{ "MTD_NO_ERASE", MTD_NO_ERASE },
+			{ "MTD_POWERUP_LOCK", MTD_POWERUP_LOCK },
+			{ NULL, -1 }
+		};
+		for (i = 0; flags[i].name != NULL; i++) {
+			if (mtd.flags & flags[i].value) {
+				if (first) {
+					printf("%s", flags[i].name);
+					first = 0;
+				} else {
+					printf(" | %s", flags[i].name);
+				}
+			}
+		}
+	}
+
+	printf("\nmtd.size = ");
+	printsize(mtd.size);
+
+	printf("\nmtd.erasesize = ");
+	printsize(mtd.erasesize);
+
+	printf("\nmtd.writesize = ");
+	printsize(mtd.writesize);
+
+	printf("\nmtd.oobsize = ");
+	printsize(mtd.oobsize);
+
+	printf("\nregions = %d\n\n", n);
+
+	for (i = 0; i < n; i++) {
+		printf("region[%d].offset = 0x%.8x\n"
+				"region[%d].erasesize = ",
+				i, region[i].offset, i);
+		printsize(region[i].erasesize);
+		printf("\nregion[%d].numblocks = %d\n"
+				"region[%d].regionindex = %d\n",
+				i, region[i].numblocks,
+				i, region[i].regionindex);
+	}
+	return 0;
+}
+
+static NORETURN void showusage(void)
+{
+	fprintf(stderr, "usage: %1$s info <device>\n"
+			"       %1$s read <device> <offset> <len> <dest-filename>\n"
+			"       %1$s write <device> <offset> <len> <source-filename>\n"
+			"       %1$s erase <device> <offset> <len>\n",
+			PROGRAM_NAME);
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+	int err = 0, fd;
+	int open_flag;
+
+	enum {
+		OPT_INFO,
+		OPT_READ,
+		OPT_WRITE,
+		OPT_ERASE
+	} option = OPT_INFO;
+
+	/* parse command-line options */
+	if (argc == 3 && !strcmp(argv[1], "info"))
+		option = OPT_INFO;
+	else if (argc == 6 && !strcmp(argv[1], "read"))
+		option = OPT_READ;
+	else if (argc == 6 && !strcmp(argv[1], "write"))
+		option = OPT_WRITE;
+	else if (argc == 5 && !strcmp(argv[1], "erase"))
+		option = OPT_ERASE;
+	else
+		showusage();
+
+	/* open device */
+	open_flag = (option == OPT_INFO || option == OPT_READ) ? O_RDONLY : O_RDWR;
+	if ((fd = open(argv[2], O_SYNC | open_flag)) < 0)
+		errmsg_die("open()");
+
+	switch (option) {
+		case OPT_INFO:
+			showinfo(fd);
+			break;
+		case OPT_READ:
+			err = flash_to_file(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
+			break;
+		case OPT_WRITE:
+			err = file_to_flash(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
+			break;
+		case OPT_ERASE:
+			err = erase_flash(fd, strtoul(argv[3], NULL, 0), strtoul(argv[4], NULL, 0));
+			break;
+	}
+
+	/* close device */
+	if (close(fd) < 0)
+		errmsg_die("close()");
+
+	return err;
+}

+ 195 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/mtdpart.c

@@ -0,0 +1,195 @@
+/*
+ *  mtdpart.c
+ *
+ *  Copyright 2015 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This utility adds or removes a partition from an MTD device.
+ */
+
+#define PROGRAM_NAME "mtdpart"
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/blkpg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: %1$s add [OPTION] <MTD_DEVICE> <PART_NAME> <START> <SIZE>\n"
+"       %1$s del [OPTION] <MTD_DEVICE> <PART_NUMBER>\n"
+"Adds a partition to an MTD device, or remove an existing partition from it.\n"
+"\n"
+"  -h, --help    Display this help and exit\n"
+"  -V, --version Output version information and exit\n"
+"\n"
+"START location and SIZE of the partition are in bytes. They should align on\n"
+"eraseblock size.\n",
+	PROGRAM_NAME
+	);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+/* Command arguments */
+
+typedef enum {
+	COMMAND_ADD,
+	COMMAND_DEL
+} command_type;
+
+static command_type		command;		/* add or del */
+static const char		*mtddev;		/* mtd device name */
+static const char		*part_name;		/* partition name */
+static int			part_no;		/* partition number */
+static long long		start_addr;		/* start address */
+static long long		length;			/* partition size */
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "hV";
+		static const struct option long_options[] = {
+			{"version", no_argument, 0, 'V'},
+			{"help", no_argument, 0, 'h'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 'V':
+				display_version();
+				break;
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case '?':
+				error++;
+				break;
+		}
+	}
+
+	if ((argc - optind) < 3 || error)
+		display_help(EXIT_FAILURE);
+
+	const char *s_command = argv[optind++];
+	mtddev = argv[optind++];
+
+	if (strcmp(s_command, "del") == 0 && (argc - optind) == 1) {
+		const char *s_part_no = argv[optind++];
+
+		long tmp = simple_strtol(s_part_no, &error);
+		if (tmp < 0)
+		       errmsg_die("Can't specify negative partition number: %ld",
+				  tmp);
+		if (tmp > INT_MAX)
+		       errmsg_die("Partition number exceeds INT_MAX: %ld",
+				  tmp);
+
+		part_no = tmp;
+		command = COMMAND_DEL;
+	} else if (strcmp(s_command, "add") == 0 && (argc - optind) == 3) {
+		const char *s_start;
+		const char *s_length;
+
+		part_name = argv[optind++];
+		s_start = argv[optind++];
+		s_length = argv[optind++];
+
+		if (strlen(part_name) >= BLKPG_DEVNAMELTH)
+			errmsg_die("Partition name (%s) should be less than %d characters",
+				   part_name, BLKPG_DEVNAMELTH);
+
+		start_addr = simple_strtoll(s_start, &error);
+		if (start_addr < 0)
+		       errmsg_die("Can't specify negative start offset: %lld",
+				  start_addr);
+
+		length = simple_strtoll(s_length, &error);
+		if (length < 0)
+		       errmsg_die("Can't specify negative length: %lld",
+				  length);
+
+		command = COMMAND_ADD;
+	} else
+		display_help(EXIT_FAILURE);
+
+	if (error)
+		display_help(EXIT_FAILURE);
+}
+
+
+int main(int argc, char * const argv[])
+{
+	int fd;
+	struct blkpg_partition part;
+	struct blkpg_ioctl_arg arg;
+
+	process_options(argc, argv);
+
+	fd = open(mtddev, O_RDWR | O_CLOEXEC);
+	if (fd == -1)
+		sys_errmsg_die("Cannot open %s", mtddev);
+
+	memset(&part, 0, sizeof(part));
+
+	memset(&arg, 0, sizeof(arg));
+	arg.datalen = sizeof(part);
+	arg.data = &part;
+
+	switch (command) {
+		case COMMAND_ADD:
+			part.start = start_addr;
+			part.length = length;
+			strncpy(part.devname, part_name,
+				sizeof(part.devname) - 1);
+			part.devname[sizeof(part.devname) - 1] = '\0';
+			arg.op = BLKPG_ADD_PARTITION;
+			break;
+		case COMMAND_DEL:
+			part.pno = part_no;
+			arg.op = BLKPG_DEL_PARTITION;
+			break;
+	}
+
+	if (ioctl(fd, BLKPG, &arg))
+		sys_errmsg_die("Failed to issue BLKPG ioctl");
+
+	close(fd);
+
+	/* Exit happy */
+	return EXIT_SUCCESS;
+}

+ 485 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/recv_image.c

@@ -0,0 +1,485 @@
+
+#define PROGRAM_NAME "recv_image"
+#define _XOPEN_SOURCE 500
+#define _BSD_SOURCE	/* struct ip_mreq */
+#define _DEFAULT_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <crc32.h>
+#include "mtd/mtd-user.h"
+#include "mcast_image.h"
+#include "libfec.h"
+
+#include "common.h"
+
+#define WBUF_SIZE 4096
+struct eraseblock {
+	uint32_t flash_offset;
+	unsigned char wbuf[WBUF_SIZE];
+	int wbuf_ofs;
+	int nr_pkts;
+	int *pkt_indices;
+	uint32_t crc;
+};
+
+int main(int argc, char **argv)
+{
+	struct addrinfo *ai;
+	struct addrinfo hints;
+	struct addrinfo *runp;
+	int ret;
+	int sock;
+	ssize_t len;
+	int flfd;
+	struct mtd_info_user meminfo;
+	unsigned char *eb_buf, *decode_buf, **src_pkts;
+	int nr_blocks = 0;
+	int pkts_per_block;
+	int block_nr = -1;
+	uint32_t image_crc = 0;
+	int total_pkts = 0;
+	int ignored_pkts = 0;
+	loff_t mtdoffset = 0;
+	int badcrcs = 0;
+	int duplicates = 0;
+	int file_mode = 0;
+	struct fec_parms *fec = NULL;
+	int i;
+	struct eraseblock *eraseblocks = NULL;
+	uint32_t start_seq = 0;
+	struct timeval start, now;
+	unsigned long fec_time = 0, flash_time = 0, crc_time = 0,
+		rflash_time = 0, erase_time = 0, net_time = 0;
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
+			PROGRAM_NAME);
+		exit(1);
+	}
+	/* Open the device */
+	flfd = open(argv[3], O_RDWR);
+
+	if (flfd >= 0) {
+		/* Fill in MTD device capability structure */
+		if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) {
+			perror("MEMGETINFO");
+			close(flfd);
+			flfd = -1;
+		} else {
+			printf("Receive to MTD device %s with erasesize %d\n",
+			       argv[3], meminfo.erasesize);
+		}
+	} else {
+		/* Try again, as if it's a file */
+		flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
+		if (flfd < 0) {
+			perror("open");
+			exit(1);
+		}
+		meminfo.erasesize = 131072;
+		file_mode = 1;
+		printf("Receive to file %s with (assumed) erasesize %d\n",
+		       argv[3], meminfo.erasesize);
+	}
+
+	pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
+
+	eb_buf = malloc(pkts_per_block * PKT_SIZE);
+	decode_buf = malloc(pkts_per_block * PKT_SIZE);
+	if (!eb_buf && !decode_buf) {
+		fprintf(stderr, "No memory for eraseblock buffer\n");
+		exit(1);
+	}
+	src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
+	if (!src_pkts) {
+		fprintf(stderr, "No memory for decode packet pointers\n");
+		exit(1);
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_ADDRCONFIG;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+	if (ret) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+		exit(1);
+	}
+	runp = ai;
+	for (runp = ai; runp; runp = runp->ai_next) {
+		sock = socket(runp->ai_family, runp->ai_socktype,
+			      runp->ai_protocol);
+		if (sock == -1) {
+			perror("socket");
+			continue;
+		}
+		if (runp->ai_family == AF_INET &&
+		    IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) {
+			struct ip_mreq rq;
+			rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr;
+			rq.imr_interface.s_addr = INADDR_ANY;
+			if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+				perror("IP_ADD_MEMBERSHIP");
+				close(sock);
+				continue;
+			}
+
+		} else if (runp->ai_family == AF_INET6 &&
+			   ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) {
+			struct ipv6_mreq rq;
+			rq.ipv6mr_multiaddr =  ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr;
+			rq.ipv6mr_interface = 0;
+			if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+				perror("IPV6_ADD_MEMBERSHIP");
+				close(sock);
+				continue;
+			}
+		}
+		if (bind(sock, runp->ai_addr, runp->ai_addrlen)) {
+			perror("bind");
+			close(sock);
+			continue;
+		}
+		break;
+	}
+	if (!runp)
+		exit(1);
+
+	while (1) {
+		struct image_pkt thispkt;
+
+		len = read(sock, &thispkt, sizeof(thispkt));
+
+		if (len < 0) {
+			perror("read socket");
+			break;
+		}
+		if (len < sizeof(thispkt)) {
+			fprintf(stderr, "Wrong length %zd bytes (expected %zu)\n",
+				len, sizeof(thispkt));
+			continue;
+		}
+		if (!eraseblocks) {
+			image_crc = thispkt.hdr.totcrc;
+			start_seq = ntohl(thispkt.hdr.pkt_sequence);
+
+			if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
+				fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
+					ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
+				exit(1);
+			}
+			nr_blocks = ntohl(thispkt.hdr.nr_blocks);
+
+			fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
+
+			eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
+			if (!eraseblocks) {
+				fprintf(stderr, "No memory for block map\n");
+				exit(1);
+			}
+			for (i = 0; i < nr_blocks; i++) {
+				eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
+				if (!eraseblocks[i].pkt_indices) {
+					fprintf(stderr, "Failed to allocate packet indices\n");
+					exit(1);
+				}
+				eraseblocks[i].nr_pkts = 0;
+				if (!file_mode) {
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+#if 1 /* Deliberately use bad blocks... test write failures */
+					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+						mtdoffset += meminfo.erasesize;
+					}
+#endif
+				}
+				eraseblocks[i].flash_offset = mtdoffset;
+				mtdoffset += meminfo.erasesize;
+				eraseblocks[i].wbuf_ofs = 0;
+			}
+			gettimeofday(&start, NULL);
+		}
+		if (image_crc != thispkt.hdr.totcrc) {
+			fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n",
+				ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
+			exit(1);
+		}
+
+		block_nr = ntohl(thispkt.hdr.block_nr);
+		if (block_nr >= nr_blocks) {
+			fprintf(stderr, "\nErroneous block_nr %d (> %d)\n",
+				block_nr, nr_blocks);
+			exit(1);
+		}
+		for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
+			if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
+//				printf("Discarding duplicate packet at %08x pkt %d\n",
+//				       block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
+				duplicates++;
+				break;
+			}
+		}
+		if (i < eraseblocks[block_nr].nr_pkts) {
+			continue;
+		}
+
+		if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
+			/* We have a block which we didn't really need */
+			eraseblocks[block_nr].nr_pkts++;
+			ignored_pkts++;
+			continue;
+		}
+
+		if (mtd_crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
+			printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n",
+			       block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
+			       mtd_crc32(-1, thispkt.data, PKT_SIZE),
+			       ntohl(thispkt.hdr.thiscrc));
+			badcrcs++;
+			continue;
+		}
+	pkt_again:
+		eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
+			ntohs(thispkt.hdr.pkt_nr);
+		total_pkts++;
+		if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
+			uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1;
+			long time_msec;
+			gettimeofday(&now, NULL);
+
+			time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
+				(now.tv_sec - start.tv_sec) * 1000;
+
+			printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs    ",
+			       total_pkts, nr_blocks * pkts_per_block,
+			       total_pkts * 100 / nr_blocks / pkts_per_block,
+			       time_msec / 1000,
+			       total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
+			       pkts_sent - total_pkts - duplicates - ignored_pkts,
+			       (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent,
+			       duplicates + ignored_pkts);
+			fflush(stdout);
+		}
+
+		if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
+			/* New packet doesn't full the wbuf */
+			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+			       thispkt.data, PKT_SIZE);
+			eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
+		} else {
+			int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
+			ssize_t wrotelen;
+			static int faked = 1;
+
+			memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+			       thispkt.data, fits);
+			wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
+					  eraseblocks[block_nr].flash_offset);
+
+			if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) {
+				faked = 1;
+				if (wrotelen < 0)
+					perror("\npacket write");
+				else
+					fprintf(stderr, "\nshort write of packet wbuf\n");
+
+				if (!file_mode) {
+					struct erase_info_user erase;
+					/* FIXME: Perhaps we should store pkt crcs and try
+					   to recover data from the offending eraseblock */
+
+					/* We have increased nr_pkts but not yet flash_offset */
+					erase.start = eraseblocks[block_nr].flash_offset &
+						~(meminfo.erasesize - 1);
+					erase.length = meminfo.erasesize;
+
+					printf("Will erase at %08x len %08x (bad write was at %08x)\n",
+					       erase.start, erase.length, eraseblocks[block_nr].flash_offset);
+					if (ioctl(flfd, MEMERASE, &erase)) {
+						perror("MEMERASE");
+						exit(1);
+					}
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+					while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+						printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+						mtdoffset += meminfo.erasesize;
+						if (mtdoffset >= meminfo.size) {
+							fprintf(stderr, "Run out of space on flash\n");
+							exit(1);
+						}
+					}
+					eraseblocks[block_nr].flash_offset = mtdoffset;
+					printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset);
+					total_pkts -= eraseblocks[block_nr].nr_pkts;
+					eraseblocks[block_nr].nr_pkts = 0;
+					eraseblocks[block_nr].wbuf_ofs = 0;
+					mtdoffset += meminfo.erasesize;
+					goto pkt_again;
+				}
+				else /* Usually nothing we can do in file mode */
+					exit(1);
+			}
+			eraseblocks[block_nr].flash_offset += WBUF_SIZE;
+			/* Copy the remainder into the wbuf */
+			memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
+			eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
+		}
+
+		if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
+			eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
+
+			if (total_pkts == nr_blocks * pkts_per_block)
+				break;
+		}
+	}
+	printf("\n");
+	gettimeofday(&now, NULL);
+	net_time = (now.tv_usec - start.tv_usec) / 1000;
+	net_time += (now.tv_sec - start.tv_sec) * 1000;
+	close(sock);
+	for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+		ssize_t rwlen;
+		gettimeofday(&start, NULL);
+		eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
+		rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+
+		gettimeofday(&now, NULL);
+		rflash_time += (now.tv_usec - start.tv_usec) / 1000;
+		rflash_time += (now.tv_sec - start.tv_sec) * 1000;
+		if (rwlen < 0) {
+			perror("read");
+			/* Argh. Perhaps we could go back and try again, but if the flash is
+			   going to fail to read back what we write to it, and the whole point
+			   in this program is to write to it, what's the point? */
+			fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
+			exit(1);
+		}
+
+		memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
+		       eraseblocks[block_nr].wbuf_ofs);
+
+		for (i=0; i < pkts_per_block; i++)
+			src_pkts[i] = &eb_buf[i * PKT_SIZE];
+
+		gettimeofday(&start, NULL);
+		if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
+			/* Eep. This cannot happen */
+			printf("The world is broken. fec_decode() returned error\n");
+			exit(1);
+		}
+		gettimeofday(&now, NULL);
+		fec_time += (now.tv_usec - start.tv_usec) / 1000;
+		fec_time += (now.tv_sec - start.tv_sec) * 1000;
+
+		for (i=0; i < pkts_per_block; i++)
+			memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
+
+		/* Paranoia */
+		gettimeofday(&start, NULL);
+		if (mtd_crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
+			printf("\nCRC mismatch for block #%d: want %08x got %08x\n",
+			       block_nr, eraseblocks[block_nr].crc,
+			       mtd_crc32(-1, decode_buf, meminfo.erasesize));
+			exit(1);
+		}
+		gettimeofday(&now, NULL);
+		crc_time += (now.tv_usec - start.tv_usec) / 1000;
+		crc_time += (now.tv_sec - start.tv_sec) * 1000;
+		start = now;
+
+		if (!file_mode) {
+			struct erase_info_user erase;
+
+			erase.start = eraseblocks[block_nr].flash_offset;
+			erase.length = meminfo.erasesize;
+
+			printf("\rErasing block at %08x...", erase.start);
+
+			if (ioctl(flfd, MEMERASE, &erase)) {
+				perror("MEMERASE");
+				/* This block has dirty data on it. If the erase failed, we're screwed */
+				fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
+				exit(1);
+			}
+			gettimeofday(&now, NULL);
+			erase_time += (now.tv_usec - start.tv_usec) / 1000;
+			erase_time += (now.tv_sec - start.tv_sec) * 1000;
+			start = now;
+		}
+		else printf("\r");
+	write_again:
+		rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+		if (rwlen < meminfo.erasesize) {
+			if (rwlen < 0) {
+				perror("\ndecoded data write");
+			} else
+				fprintf(stderr, "\nshort write of decoded data\n");
+
+			if (!file_mode) {
+				struct erase_info_user erase;
+				erase.start = eraseblocks[block_nr].flash_offset;
+				erase.length = meminfo.erasesize;
+
+				printf("Erasing failed block at %08x\n",
+				       eraseblocks[block_nr].flash_offset);
+
+				if (ioctl(flfd, MEMERASE, &erase)) {
+					perror("MEMERASE");
+					exit(1);
+				}
+				if (mtdoffset >= meminfo.size) {
+					fprintf(stderr, "Run out of space on flash\n");
+					exit(1);
+				}
+				while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+					printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+					mtdoffset += meminfo.erasesize;
+					if (mtdoffset >= meminfo.size) {
+						fprintf(stderr, "Run out of space on flash\n");
+						exit(1);
+					}
+				}
+				printf("Will try again at %08lx...", (long)mtdoffset);
+				eraseblocks[block_nr].flash_offset = mtdoffset;
+
+				goto write_again;
+			}
+			else /* Usually nothing we can do in file mode */
+				exit(1);
+		}
+		gettimeofday(&now, NULL);
+		flash_time += (now.tv_usec - start.tv_usec) / 1000;
+		flash_time += (now.tv_sec - start.tv_sec) * 1000;
+
+		printf("wrote image block %08x (%d pkts)    ",
+		       block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
+		fflush(stdout);
+	}
+	close(flfd);
+	printf("Net rx   %ld.%03lds\n", net_time / 1000, net_time % 1000);
+	printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000);
+	printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
+	printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
+	printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
+	printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000);
+
+	return 0;
+}

+ 303 - 0
EVSE/GPL/mtd-utils-2.1.2/misc-utils/serve_image.c

@@ -0,0 +1,303 @@
+#define PROGRAM_NAME "serve_image"
+#define _POSIX_C_SOURCE 200112L
+
+#include <time.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <crc32.h>
+#include <inttypes.h>
+
+#include <common.h>
+
+#include "mcast_image.h"
+#include "libfec.h"
+
+int tx_rate = 80000;
+int pkt_delay;
+
+#undef RANDOMDROP
+
+int main(int argc, char **argv)
+{
+	struct addrinfo *ai;
+	struct addrinfo hints;
+	struct addrinfo *runp;
+	int ret;
+	int sock;
+	struct image_pkt pktbuf;
+	int rfd;
+	struct stat st;
+	int writeerrors = 0;
+	uint32_t erasesize;
+	unsigned char *image, *blockptr = NULL;
+	uint32_t block_nr, pkt_nr;
+	int nr_blocks;
+	struct timeval then, now, nextpkt;
+	long time_msecs;
+	int pkts_per_block;
+	int total_pkts_per_block;
+	struct fec_parms *fec;
+	unsigned char *last_block;
+	uint32_t *block_crcs;
+	long tosleep;
+	uint32_t sequence = 0;
+
+	if (argc == 6) {
+		tx_rate = atol(argv[5]) * 1024;
+		if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
+			fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
+			exit(1);
+		}
+		argc = 5;
+	}
+	if (argc != 5) {
+		fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
+			PROGRAM_NAME);
+		exit(1);
+	}
+	pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
+	printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
+	printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
+
+	erasesize = atol(argv[4]);
+	if (!erasesize) {
+		fprintf(stderr, "erasesize cannot be zero\n");
+		exit(1);
+	}
+
+	pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
+	total_pkts_per_block = pkts_per_block * 3 / 2;
+
+	/* We have to pad it with zeroes, so can't use it in-place */
+	last_block = malloc(pkts_per_block * PKT_SIZE);
+	if (!last_block) {
+		fprintf(stderr, "Failed to allocate last-block buffer\n");
+		exit(1);
+	}
+
+	fec = fec_new(pkts_per_block, total_pkts_per_block);
+	if (!fec) {
+		fprintf(stderr, "Error initialising FEC\n");
+		exit(1);
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_ADDRCONFIG;
+	hints.ai_socktype = SOCK_DGRAM;
+
+	ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+	if (ret) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+		exit(1);
+	}
+	runp = ai;
+	for (runp = ai; runp; runp = runp->ai_next) {
+		sock = socket(runp->ai_family, runp->ai_socktype,
+			      runp->ai_protocol);
+		if (sock == -1) {
+			perror("socket");
+			continue;
+		}
+		if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
+			break;
+		perror("connect");
+		close(sock);
+	}
+	if (!runp)
+		exit(1);
+
+	rfd = open(argv[3], O_RDONLY);
+	if (rfd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (fstat(rfd, &st)) {
+		perror("fstat");
+		exit(1);
+	}
+
+	if (st.st_size % erasesize) {
+		fprintf(stderr, "Image size %lld bytes is not a multiple of erasesize %d bytes\n",
+				(long long)st.st_size, erasesize);
+		exit(1);
+	}
+	image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
+	if (image == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+
+	nr_blocks = st.st_size / erasesize;
+
+	block_crcs = malloc(nr_blocks * sizeof(uint32_t));
+	if (!block_crcs) {
+		fprintf(stderr, "Failed to allocate memory for CRCs\n");
+		exit(1);
+	}
+
+	memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
+	memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
+
+	printf("Checking CRC....");
+	fflush(stdout);
+
+	pktbuf.hdr.resend = 0;
+	pktbuf.hdr.totcrc = htonl(mtd_crc32(-1, image, st.st_size));
+	pktbuf.hdr.nr_blocks = htonl(nr_blocks);
+	pktbuf.hdr.blocksize = htonl(erasesize);
+	pktbuf.hdr.thislen = htonl(PKT_SIZE);
+	pktbuf.hdr.nr_pkts = htons(total_pkts_per_block);
+
+	printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
+	printf("Checking block CRCs....");
+	fflush(stdout);
+	for (block_nr=0; block_nr < nr_blocks; block_nr++) {
+		printf("\rChecking block CRCS.... %d/%d",
+		       block_nr + 1, nr_blocks);
+		fflush(stdout);
+		block_crcs[block_nr] = mtd_crc32(-1, image + (block_nr * erasesize), erasesize);
+	}
+
+	printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
+	       "Estimated transmit time per cycle: %ds\n",
+	       (long)st.st_size / 1024, (long) st.st_size,
+	       nr_blocks, pkts_per_block,
+	       nr_blocks * pkts_per_block * pkt_delay / 1000000);
+	gettimeofday(&then, NULL);
+	nextpkt = then;
+
+#ifdef RANDOMDROP
+	srand((unsigned)then.tv_usec);
+	printf("Random seed %u\n", (unsigned)then.tv_usec);
+#endif
+	while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
+
+		if (blockptr && pkt_nr == 0) {
+			unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
+			gettimeofday(&now, NULL);
+
+			time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+			time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+			printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
+			       amt_sent / 1024, time_msecs,
+			       amt_sent / 1024 * 1000 / time_msecs);
+			then = now;
+		}
+
+		for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+
+			int actualpkt;
+
+			/* Calculating the redundant FEC blocks is expensive;
+			   the first $pkts_per_block are cheap enough though
+			   because they're just copies. So alternate between
+			   simple and complex stuff, so that we don't start
+			   to choke and fail to keep up with the expected
+			   bitrate in the second half of the sequence */
+			if (block_nr & 1)
+				actualpkt = pkt_nr;
+			else
+				actualpkt = total_pkts_per_block - 1 - pkt_nr;
+
+			blockptr = image + (erasesize * block_nr);
+			if (block_nr == nr_blocks - 1)
+				blockptr = last_block;
+
+			fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
+
+			pktbuf.hdr.thiscrc = htonl(mtd_crc32(-1, pktbuf.data, PKT_SIZE));
+			pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
+			pktbuf.hdr.block_nr = htonl(block_nr);
+			pktbuf.hdr.pkt_nr = htons(actualpkt);
+			pktbuf.hdr.pkt_sequence = htonl(sequence++);
+
+			printf("\rSending data block %08x packet %3d/%d",
+			       block_nr * erasesize,
+			       pkt_nr, total_pkts_per_block);
+
+			if (pkt_nr && !block_nr) {
+				unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
+
+				gettimeofday(&now, NULL);
+
+				time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+				time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+				printf("    (%ld KiB/s)    ",
+				       amt_sent / 1024 * 1000 / time_msecs);
+			}
+
+			fflush(stdout);
+
+#ifdef RANDOMDROP
+			if ((rand() % 1000) < 20) {
+				printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
+				continue;
+			}
+#endif
+			gettimeofday(&now, NULL);
+#if 1
+			tosleep = nextpkt.tv_usec - now.tv_usec +
+				(1000000 * (nextpkt.tv_sec - now.tv_sec));
+
+			/* We need hrtimers for this to actually work */
+			if (tosleep > 0) {
+				struct timespec req;
+
+				req.tv_nsec = (tosleep % 1000000) * 1000;
+				req.tv_sec = tosleep / 1000000;
+
+				nanosleep(&req, NULL);
+			}
+#else
+			while (now.tv_sec < nextpkt.tv_sec ||
+				 (now.tv_sec == nextpkt.tv_sec &&
+				  now.tv_usec < nextpkt.tv_usec)) {
+				gettimeofday(&now, NULL);
+			}
+#endif
+			nextpkt.tv_usec += pkt_delay;
+			if (nextpkt.tv_usec >= 1000000) {
+				nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
+				nextpkt.tv_usec %= 1000000;
+			}
+
+			/* If the time for the next packet has already
+			   passed (by some margin), then we've lost time
+			   Adjust our expected timings accordingly. If
+			   we're only a little way behind, don't slip yet */
+			if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
+					1000000 * (nextpkt.tv_sec - now.tv_sec))) {
+				nextpkt = now;
+			}
+
+			if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
+				perror("write");
+				writeerrors++;
+				if (writeerrors > 10) {
+					fprintf(stderr, "Too many consecutive write errors\n");
+					exit(1);
+				}
+			} else
+				writeerrors = 0;
+
+
+
+		}
+	}
+	munmap(image, st.st_size);
+	close(rfd);
+	close(sock);
+	return 0;
+}

+ 32 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/Makemodule.am

@@ -0,0 +1,32 @@
+nanddump_SOURCES = nand-utils/nanddump.c
+nanddump_LDADD = libmtd.a
+
+nandwrite_SOURCES = nand-utils/nandwrite.c
+nandwrite_LDADD = libmtd.a
+
+nandtest_SOURCES = nand-utils/nandtest.c
+nandtest_LDADD = libmtd.a
+
+nftldump_SOURCES = nand-utils/nftldump.c
+nftldump_LDADD = libmtd.a
+
+nftl_format_SOURCES = nand-utils/nftl_format.c
+nftl_format_LDADD = libmtd.a
+
+NAND_BINS = \
+	nanddump nandwrite nandtest nftldump nftl_format
+
+NAND_SH = \
+	nand-utils/load_nandsim.sh
+
+EXTRA_DIST += $(NAND_SH)
+
+sbin_PROGRAMS += $(NAND_BINS)
+
+if BUILD_TESTS
+if INSTALL_TESTS
+pkglibexec_SCRIPTS += $(NAND_SH)
+else
+noinst_SCRIPTS += $(NAND_SH)
+endif
+endif

+ 127 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/load_nandsim.sh

@@ -0,0 +1,127 @@
+#!/bin/sh -euf
+
+#
+# This script inserts NAND simulator module to emulate NAND flash of specified
+# size.
+#
+# Author: Artem Bityutskiy
+#
+
+fatal()
+{
+        echo "Error: $1" 1>&2
+        exit 1
+}
+
+usage()
+{
+	cat 1>&2 <<EOF
+Load NAND simulator to simulate flash of a specified size.
+
+Usage: ${0##*/} <size in MiB> <eraseblock size in KiB> \\
+       <page size (512 or 2048)>
+
+Only the first parameter is mandatory. Default eraseblock size
+is 16KiB, default NAND page size is 512 bytes.
+
+Only the following combinations are supported:
+--------------------------------------------------
+| size (MiB) | EB size (KiB) | Page size (bytes) |
+--------------------------------------------------
+| 16         | 16            | 512               |
+| 32         | 16            | 512               |
+| 64         | 16            | 512               |
+| 128        | 16            | 512               |
+| 256        | 16            | 512               |
+| 64         | 64            | 2048              |
+| 64         | 128           | 2048              |
+| 64         | 256           | 2048              |
+| 64         | 512           | 2048              |
+| 128        | 64            | 2048              |
+| 128        | 128           | 2048              |
+| 128        | 256           | 2048              |
+| 128        | 512           | 2048              |
+| 256        | 64            | 2048              |
+| 256        | 128           | 2048              |
+| 256        | 256           | 2048              |
+| 256        | 512           | 2048              |
+| 512        | 64            | 2048              |
+| 512        | 128           | 2048              |
+| 512        | 256           | 2048              |
+| 512        | 512           | 2048              |
+| 1024       | 64            | 2048              |
+| 1024       | 128           | 2048              |
+| 1024       | 256           | 2048              |
+| 1024       | 512           | 2048              |
+--------------------------------------------------
+EOF
+}
+
+if grep -q "NAND simulator" /proc/mtd; then
+	fatal "nandsim is already loaded"
+fi
+
+if [ "$#" -lt "1" ]; then
+	usage
+	exit 1
+fi
+
+size="$1"
+eb_size="$2"
+page_size="$3"
+if [ "$#" = "1" ]; then
+	eb_size="16"
+	page_size="512"
+elif [ "$#" = "2" ]; then
+	page_size="512"
+fi
+
+if [ "$page_size" -eq 512 ] && [ "$eb_size" -ne "16" ]; then
+	fatal "only 16KiB eraseblocks are possible in case of 512 bytes page"
+fi
+
+first=
+second=
+third=
+fourth=
+
+if [ "$page_size" -eq "512" ]; then
+	first="0x20"
+	case "$size" in
+	16)  second=0x33 ;;
+	32)  second=0x35 ;;
+	64)  second=0x36 ;;
+	128) second=0x78 ;;
+	256) second=0x71 ;;
+	*) fatal "flash size ${size}MiB is not supported, try 16, 32, 64 or 256"
+	esac
+elif [ "$page_size" -eq "2048" ]; then
+	case "$eb_size" in
+	64)  fourth="0x05" ;;
+	128) fourth="0x15" ;;
+	256) fourth="0x25" ;;
+	512) fourth="0x35" ;;
+	*)   fatal "eraseblock ${eb_size}KiB is not supported"
+	esac
+
+
+	case "$size" in
+	64)   first="0x20"; second="0xa2"; third="0x00 ";;
+	128)  first="0xec"; second="0xa1"; third="0x00 ";;
+	256)  first="0x20"; second="0xaa"; third="0x00 ";;
+	512)  first="0x20"; second="0xac"; third="0x00 ";;
+	1024) first="0xec"; second="0xd3"; third="0x51 ";;
+	*) fatal "unable to emulate ${size}MiB flash with ${eb_size}KiB eraseblock"
+	esac
+else
+	fatal "bad NAND page size ${page_size}KiB, it has to be either 512 or 2048"
+fi
+
+first="first_id_byte=$first"
+second="second_id_byte=$second"
+[ -z "$third" ]  || third="third_id_byte=$third"
+[ -z "$fourth" ] || fourth="fourth_id_byte=$fourth"
+
+modprobe nandsim "$first" "$second" $third $fourth
+
+echo "Loaded NAND simulator (${size}MiB, ${eb_size}KiB eraseblock, $page_size bytes NAND page)"

+ 557 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/nanddump.c

@@ -0,0 +1,557 @@
+/*
+ *  nanddump.c
+ *
+ *  Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org)
+ *                     Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This utility dumps the contents of raw NAND chips or NAND
+ *   chips contained in DoC devices.
+ */
+
+#define PROGRAM_NAME "nanddump"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include "common.h"
+#include <libmtd.h>
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: %s [OPTIONS] MTD-device\n"
+"Dumps the contents of a nand mtd partition.\n"
+"\n"
+"-h         --help               Display this help and exit\n"
+"           --version            Output version information and exit\n"
+"           --bb=METHOD          Choose bad block handling method (see below).\n"
+"-a         --forcebinary        Force printing of binary data to tty\n"
+"-c         --canonicalprint     Print canonical Hex+ASCII dump\n"
+"-f file    --file=file          Dump to file\n"
+"-l length  --length=length      Length\n"
+"-n         --noecc              Read without error correction\n"
+"           --omitoob            Omit OOB data (default)\n"
+"-o         --oob                Dump OOB data\n"
+"-p         --prettyprint        Print nice (hexdump)\n"
+"-q         --quiet              Don't display progress and status messages\n"
+"-s addr    --startaddress=addr  Start address\n"
+"           --skip-bad-blocks-to-start\n"
+"                                Skip bad blocks when seeking to the start address\n"
+"\n"
+"--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':\n"
+"    padbad:  dump flash data, substituting 0xFF for any bad blocks\n"
+"    dumpbad: dump flash data, including any bad blocks\n"
+"    skipbad: dump good data, completely skipping any bad blocks (default)\n",
+	PROGRAM_NAME);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+// Option variables
+
+static bool			pretty_print = false;	// print nice
+static bool			noecc = false;		// don't error correct
+static bool			omitoob = true;		// omit oob data
+static long long		start_addr;		// start address
+static long long		length;			// dump length
+static const char		*mtddev;		// mtd device name
+static const char		*dumpfile;		// dump file name
+static bool			quiet = false;		// suppress diagnostic output
+static bool			canonical = false;	// print nice + ascii
+static bool			forcebinary = false;	// force printing binary to tty
+static bool			skip_bad_blocks_to_start = false;
+
+static enum {
+	padbad,   // dump flash data, substituting 0xFF for any bad blocks
+	dumpbad,  // dump flash data, including any bad blocks
+	skipbad,  // dump good data, completely skipping any bad blocks
+} bb_method = skipbad;
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+	bool oob_default = true;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "hs:f:l:opqncaV";
+		static const struct option long_options[] = {
+			{"version", no_argument, 0, 'V'},
+			{"bb", required_argument, 0, 0},
+			{"omitoob", no_argument, 0, 0},
+			{"skip-bad-blocks-to-start", no_argument, 0, 0 },
+			{"help", no_argument, 0, 'h'},
+			{"forcebinary", no_argument, 0, 'a'},
+			{"canonicalprint", no_argument, 0, 'c'},
+			{"file", required_argument, 0, 'f'},
+			{"oob", no_argument, 0, 'o'},
+			{"prettyprint", no_argument, 0, 'p'},
+			{"startaddress", required_argument, 0, 's'},
+			{"length", required_argument, 0, 'l'},
+			{"noecc", no_argument, 0, 'n'},
+			{"quiet", no_argument, 0, 'q'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF) {
+			break;
+		}
+
+		switch (c) {
+			case 0:
+				switch (option_index) {
+					case 1:
+						/* Handle --bb=METHOD */
+						if (!strcmp(optarg, "padbad"))
+							bb_method = padbad;
+						else if (!strcmp(optarg, "dumpbad"))
+							bb_method = dumpbad;
+						else if (!strcmp(optarg, "skipbad"))
+							bb_method = skipbad;
+						else
+							error++;
+						break;
+					case 2: /* --omitoob */
+						if (oob_default) {
+							oob_default = false;
+							omitoob = true;
+						} else {
+							errmsg_die("--oob and --oomitoob are mutually exclusive");
+						}
+						break;
+					case 3: /* --skip-bad-blocks-to-start */
+						skip_bad_blocks_to_start = true;
+						break;
+				}
+				break;
+			case 'V':
+				display_version();
+				break;
+			case 's':
+				start_addr = simple_strtoll(optarg, &error);
+				break;
+			case 'f':
+				free(dumpfile);
+				dumpfile = xstrdup(optarg);
+				break;
+			case 'l':
+				length = simple_strtoll(optarg, &error);
+				break;
+			case 'o':
+				if (oob_default) {
+					oob_default = false;
+					omitoob = false;
+				} else {
+					errmsg_die("--oob and --oomitoob are mutually exclusive");
+				}
+				break;
+			case 'a':
+				forcebinary = true;
+				break;
+			case 'c':
+				canonical = true;
+				/* fall-through */
+			case 'p':
+				pretty_print = true;
+				break;
+			case 'q':
+				quiet = true;
+				break;
+			case 'n':
+				noecc = true;
+				break;
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case '?':
+				error++;
+				break;
+		}
+	}
+
+	if (start_addr < 0)
+		errmsg_die("Can't specify negative offset with option -s: %lld",
+				start_addr);
+
+	if (length < 0)
+		errmsg_die("Can't specify negative length with option -l: %lld", length);
+
+	if (quiet && pretty_print) {
+		fprintf(stderr, "The quiet and pretty print options are mutually-\n"
+				"exclusive. Choose one or the other.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (forcebinary && pretty_print) {
+		fprintf(stderr, "The forcebinary and pretty print options are\n"
+				"mutually-exclusive. Choose one or the "
+				"other.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help(EXIT_FAILURE);
+
+	mtddev = argv[optind];
+}
+
+#define PRETTY_ROW_SIZE 16
+#define PRETTY_BUF_LEN 80
+
+/**
+ * pretty_dump_to_buffer - formats a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NULL
+ * @pagedump: true - dumping as page format; false - dumping as OOB format
+ * @ascii: dump ascii formatted data next to hexdump
+ * @prefix: address to print before line in a page dump, ignored if !pagedump
+ *
+ * pretty_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * PRETTY_ROW_SIZE bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of unsigned char data, pretty_dump_to_buffer() converts the
+ * input data to a hex/ASCII dump at the supplied memory location. A prefix
+ * is included based on whether we are dumping page or OOB data. The converted
+ * output is always NULL-terminated.
+ *
+ * e.g.
+ *   pretty_dump_to_buffer(data, data_len, prettybuf, linelen, true,
+ *                         false, 256);
+ * produces:
+ *   0x00000100: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
+ * NOTE: This function was adapted from linux kernel, "lib/hexdump.c"
+ */
+static void pretty_dump_to_buffer(const unsigned char *buf, size_t len,
+		char *linebuf, size_t linebuflen, bool pagedump, bool ascii,
+		unsigned long long prefix)
+{
+	static const char hex_asc[] = "0123456789abcdef";
+	unsigned char ch;
+	unsigned int j, lx = 0, ascii_column;
+
+	if (pagedump)
+		lx += sprintf(linebuf, "0x%.8llx: ", prefix);
+	else
+		lx += sprintf(linebuf, "  OOB Data: ");
+
+	if (!len)
+		goto nil;
+	if (len > PRETTY_ROW_SIZE)	/* limit to one line at a time */
+		len = PRETTY_ROW_SIZE;
+
+	for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
+		ch = buf[j];
+		linebuf[lx++] = hex_asc[(ch & 0xf0) >> 4];
+		linebuf[lx++] = hex_asc[ch & 0x0f];
+		linebuf[lx++] = ' ';
+	}
+	if (j)
+		lx--;
+
+	ascii_column = 3 * PRETTY_ROW_SIZE + 14;
+
+	if (!ascii)
+		goto nil;
+
+	/* Spacing between hex and ASCII - ensure at least one space */
+	lx += sprintf(linebuf + lx, "%*s",
+			MAX((int)MIN(linebuflen, ascii_column) - 1 - lx, 1),
+			" ");
+
+	linebuf[lx++] = '|';
+	for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
+		linebuf[lx++] = (isascii(buf[j]) && isprint(buf[j])) ? buf[j]
+			: '.';
+	linebuf[lx++] = '|';
+nil:
+	linebuf[lx++] = '\n';
+	linebuf[lx++] = '\0';
+}
+
+/**
+ * ofd_write - writes whole buffer to the file associated with a descriptor
+ *
+ * On failure an error (negative number) is returned. Otherwise 0 is returned.
+ */
+static int ofd_write(int ofd, const void *buf, size_t nbyte)
+{
+	const unsigned char *data = buf;
+	ssize_t bytes;
+
+	while (nbyte) {
+		bytes = write(ofd, data, nbyte);
+		if (bytes < 0) {
+			int err = -errno;
+
+			sys_errmsg("Unable to write to output");
+
+			return err;
+		}
+		data += bytes;
+		nbyte -= bytes;
+	}
+
+	return 0;
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char * const argv[])
+{
+	long long ofs, end_addr = 0;
+	long long blockstart = 1;
+	int i, fd, ofd = 0, bs, badblock = 0;
+	struct mtd_dev_info mtd;
+	char pretty_buf[PRETTY_BUF_LEN];
+	int firstblock = 1;
+	struct mtd_ecc_stats stat1, stat2;
+	bool eccstats = false;
+	unsigned char *readbuf = NULL, *oobbuf = NULL;
+	libmtd_t mtd_desc;
+	int err;
+
+	process_options(argc, argv);
+
+	/* Initialize libmtd */
+	mtd_desc = libmtd_open();
+	if (!mtd_desc)
+		return errmsg("can't initialize libmtd");
+
+	/* Open MTD device */
+	if ((fd = open(mtddev, O_RDONLY)) == -1) {
+		perror(mtddev);
+		exit(EXIT_FAILURE);
+	}
+
+	/* Fill in MTD device capability structure */
+	if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0)
+		return errmsg("mtd_get_dev_info failed");
+
+	/* Allocate buffers */
+	oobbuf = xmalloc(mtd.oob_size);
+	readbuf = xmalloc(mtd.min_io_size);
+
+	if (noecc)  {
+		if (ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW) != 0) {
+				perror("MTDFILEMODE");
+				goto closeall;
+		}
+	} else {
+		/* check if we can read ecc stats */
+		if (!ioctl(fd, ECCGETSTATS, &stat1)) {
+			eccstats = true;
+			if (!quiet) {
+				fprintf(stderr, "ECC failed: %d\n", stat1.failed);
+				fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
+				fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
+				fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
+			}
+		} else
+			perror("No ECC status information available");
+	}
+
+	/* Open output file for writing. If file name is "-", write to standard
+	 * output. */
+	if (!dumpfile) {
+		ofd = STDOUT_FILENO;
+	} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
+		perror(dumpfile);
+		goto closeall;
+	}
+
+	if (!pretty_print && !forcebinary && isatty(ofd)) {
+		fprintf(stderr, "Not printing binary garbage to tty. Use '-a'\n"
+				"or '--forcebinary' to override.\n");
+		goto closeall;
+	}
+
+	/* Initialize start/end addresses and block size */
+	if (start_addr & (mtd.min_io_size - 1)) {
+		fprintf(stderr, "the start address (-s parameter) is not page-aligned!\n"
+				"The pagesize of this NAND Flash is 0x%x.\n",
+				mtd.min_io_size);
+		goto closeall;
+	}
+	if (skip_bad_blocks_to_start) {
+		long long bbs_offset = 0;
+		while (bbs_offset < start_addr) {
+			err = mtd_is_bad(&mtd, fd, bbs_offset / mtd.eb_size);
+			if (err < 0) {
+				sys_errmsg("%s: MTD get bad block failed", mtddev);
+				goto closeall;
+			} else if (err == 1) {
+				if (!quiet)
+					fprintf(stderr, "Bad block at %llx\n", bbs_offset);
+				start_addr += mtd.eb_size;
+			}
+			bbs_offset += mtd.eb_size;
+		}
+	}
+
+	if (length)
+		end_addr = start_addr + length;
+	if (!length || end_addr > mtd.size)
+		end_addr = mtd.size;
+
+	bs = mtd.min_io_size;
+
+	/* Print informative message */
+	if (!quiet) {
+		fprintf(stderr, "Block size %d, page size %d, OOB size %d\n",
+				mtd.eb_size, mtd.min_io_size, mtd.oob_size);
+		fprintf(stderr,
+				"Dumping data starting at 0x%08llx and ending at 0x%08llx...\n",
+				start_addr, end_addr);
+	}
+
+	/* Dump the flash contents */
+	for (ofs = start_addr; ofs < end_addr; ofs += bs) {
+		/* Check for bad block */
+		if (bb_method == dumpbad) {
+			badblock = 0;
+		} else if (blockstart != (ofs & (~mtd.eb_size + 1)) ||
+				firstblock) {
+			blockstart = ofs & (~mtd.eb_size + 1);
+			firstblock = 0;
+			if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) {
+				errmsg("libmtd: mtd_is_bad");
+				goto closeall;
+			}
+		}
+
+		if (badblock) {
+			/* skip bad block, increase end_addr */
+			if (bb_method == skipbad) {
+				end_addr += mtd.eb_size;
+				ofs += mtd.eb_size - bs;
+				if (end_addr > mtd.size)
+					end_addr = mtd.size;
+				continue;
+			}
+			memset(readbuf, 0xff, bs);
+		} else {
+			/* Read page data and exit on failure */
+			if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
+				errmsg("mtd_read");
+				goto closeall;
+			}
+		}
+
+		/* ECC stats available ? */
+		if (eccstats) {
+			if (ioctl(fd, ECCGETSTATS, &stat2)) {
+				perror("ioctl(ECCGETSTATS)");
+				goto closeall;
+			}
+			if (stat1.failed != stat2.failed)
+				fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
+						" at offset 0x%08llx\n",
+						stat2.failed - stat1.failed, ofs);
+			if (stat1.corrected != stat2.corrected)
+				fprintf(stderr, "ECC: %d corrected bitflip(s) at"
+						" offset 0x%08llx\n",
+						stat2.corrected - stat1.corrected, ofs);
+			stat1 = stat2;
+		}
+
+		/* Write out page data */
+		if (pretty_print) {
+			for (i = 0; i < bs; i += PRETTY_ROW_SIZE) {
+				pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE,
+						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i);
+				err = ofd_write(ofd, pretty_buf, strlen(pretty_buf));
+				if (err)
+					goto closeall;
+			}
+		} else {
+			/* Write requested length if oob is omitted */
+			size_t size_left = end_addr - ofs;
+			if (omitoob && (size_left < bs))
+				err = ofd_write(ofd, readbuf, size_left);
+			else
+				err = ofd_write(ofd, readbuf, bs);
+
+			if (err)
+				goto closeall;
+		}
+
+		if (omitoob)
+			continue;
+
+		if (badblock) {
+			memset(oobbuf, 0xff, mtd.oob_size);
+		} else {
+			/* Read OOB data and exit on failure */
+			if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) {
+				errmsg("libmtd: mtd_read_oob");
+				goto closeall;
+			}
+		}
+
+		/* Write out OOB data */
+		if (pretty_print) {
+			for (i = 0; i < mtd.oob_size; i += PRETTY_ROW_SIZE) {
+				pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i,
+						pretty_buf, PRETTY_BUF_LEN, false, canonical, 0);
+				err = ofd_write(ofd, pretty_buf, strlen(pretty_buf));
+				if (err)
+					goto closeall;
+			}
+		} else {
+			err = ofd_write(ofd, oobbuf, mtd.oob_size);
+			if (err)
+				goto closeall;
+		}
+	}
+
+	/* Close the output file and MTD device, free memory */
+	close(fd);
+	close(ofd);
+	free(oobbuf);
+	free(readbuf);
+
+	/* Exit happy */
+	return EXIT_SUCCESS;
+
+closeall:
+	close(fd);
+	if (ofd > 0 && ofd != STDOUT_FILENO)
+		close(ofd);
+	free(oobbuf);
+	free(readbuf);
+	exit(EXIT_FAILURE);
+}

+ 322 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/nandtest.c

@@ -0,0 +1,322 @@
+#define PROGRAM_NAME "nandtest"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+#include "common.h"
+
+static NORETURN void usage(int status)
+{
+	fprintf(status ? stderr : stdout,
+		"usage: %s [OPTIONS] <device>\n\n"
+		"  -h, --help           Display this help output\n"
+		"  -V, --version        Display version information and exit\n"
+		"  -m, --markbad        Mark blocks bad if they appear so\n"
+		"  -s, --seed           Supply random seed\n"
+		"  -p, --passes         Number of passes\n"
+		"  -r <n>, --reads=<n>  Read & check <n> times per pass\n"
+		"  -o, --offset         Start offset on flash\n"
+		"  -l, --length         Length of flash to test\n"
+		"  -k, --keep           Restore existing contents after test\n",
+		PROGRAM_NAME);
+	exit(status);
+}
+
+struct mtd_info_user meminfo;
+struct mtd_ecc_stats oldstats, newstats;
+int fd;
+int markbad=0;
+int seed;
+
+static int read_and_compare(loff_t ofs, unsigned char *data,
+			    unsigned char *rbuf)
+{
+	ssize_t len;
+	int i;
+
+	len = pread(fd, rbuf, meminfo.erasesize, ofs);
+	if (len < meminfo.erasesize) {
+		printf("\n");
+		if (len)
+			fprintf(stderr, "Short read (%zd bytes)\n", len);
+		else
+			perror("read");
+		exit(1);
+	}
+
+	if (ioctl(fd, ECCGETSTATS, &newstats)) {
+		printf("\n");
+		perror("ECCGETSTATS");
+		close(fd);
+		exit(1);
+	}
+
+	if (newstats.corrected > oldstats.corrected) {
+		printf("\n %d bit(s) ECC corrected at %08x\n",
+				newstats.corrected - oldstats.corrected,
+				(unsigned) ofs);
+		oldstats.corrected = newstats.corrected;
+	}
+	if (newstats.failed > oldstats.failed) {
+		printf("\nECC failed at %08x\n", (unsigned) ofs);
+		oldstats.failed = newstats.failed;
+	}
+
+	printf("\r%08x: checking...", (unsigned)ofs);
+	fflush(stdout);
+
+	if (memcmp(data, rbuf, meminfo.erasesize)) {
+		printf("\n");
+		fprintf(stderr, "compare failed. seed %d\n", seed);
+		for (i=0; i<meminfo.erasesize; i++) {
+			if (data[i] != rbuf[i])
+				printf("Byte 0x%x is %02x should be %02x\n",
+				       i, rbuf[i], data[i]);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf,
+			   int nr_reads)
+{
+	struct erase_info_user er;
+	ssize_t len;
+	int i, read_errs = 0;
+
+	printf("\r%08x: erasing... ", (unsigned)ofs);
+	fflush(stdout);
+
+	er.start = ofs;
+	er.length = meminfo.erasesize;
+
+	if (ioctl(fd, MEMERASE, &er)) {
+		perror("MEMERASE");
+		if (markbad) {
+			printf("Mark block bad at %08lx\n", (long)ofs);
+			ioctl(fd, MEMSETBADBLOCK, &ofs);
+		}
+		return 1;
+	}
+
+	printf("\r%08x: writing...", (unsigned)ofs);
+	fflush(stdout);
+
+	len = pwrite(fd, data, meminfo.erasesize, ofs);
+	if (len < 0) {
+		printf("\n");
+		perror("write");
+		if (markbad) {
+			printf("Mark block bad at %08lx\n", (long)ofs);
+			ioctl(fd, MEMSETBADBLOCK, &ofs);
+		}
+		return 1;
+	}
+	if (len < meminfo.erasesize) {
+		printf("\n");
+		fprintf(stderr, "Short write (%zd bytes)\n", len);
+		exit(1);
+	}
+
+	for (i=1; i<=nr_reads; i++) {
+		printf("\r%08x: reading (%d of %d)...", (unsigned)ofs, i, nr_reads);
+		fflush(stdout);
+		if (read_and_compare(ofs, data, rbuf))
+			read_errs++;
+	}
+	if (read_errs) {
+		fprintf(stderr, "read/check %d of %d failed. seed %d\n", read_errs, nr_reads, seed);
+		return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+	int i;
+	unsigned char *wbuf, *rbuf, *kbuf;
+	int pass;
+	int nr_passes = 1;
+	int nr_reads = 4;
+	int keep_contents = 0;
+	uint32_t offset = 0;
+	uint32_t length = -1;
+	int error = 0;
+
+	seed = time(NULL);
+
+	for (;;) {
+		static const char short_options[] = "hkl:mo:p:r:s:V";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "version", no_argument, 0, 'V' },
+			{ "markbad", no_argument, 0, 'm' },
+			{ "seed", required_argument, 0, 's' },
+			{ "passes", required_argument, 0, 'p' },
+			{ "offset", required_argument, 0, 'o' },
+			{ "length", required_argument, 0, 'l' },
+			{ "reads", required_argument, 0, 'r' },
+			{ "keep", no_argument, 0, 'k' },
+			{0, 0, 0, 0},
+		};
+		int option_index = 0;
+		int c = getopt_long(argc, argv, short_options, long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'h':
+			usage(EXIT_SUCCESS);
+		case 'V':
+			common_print_version();
+			exit(EXIT_SUCCESS);
+			break;
+		case '?':
+			usage(EXIT_FAILURE);
+
+		case 'm':
+			markbad = 1;
+			break;
+
+		case 'k':
+			keep_contents = 1;
+			break;
+
+		case 's':
+			seed = atol(optarg);
+			break;
+
+		case 'p':
+			nr_passes = atol(optarg);
+			break;
+
+		case 'r':
+			nr_reads = atol(optarg);
+			break;
+
+		case 'o':
+			offset = simple_strtoul(optarg, &error);
+			break;
+
+		case 'l':
+			length = simple_strtoul(optarg, &error);
+			break;
+
+		}
+	}
+	if (argc - optind != 1)
+		usage(EXIT_FAILURE);
+	if (error)
+		errmsg_die("Try --help for more information");
+
+	fd = open(argv[optind], O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo)) {
+		perror("MEMGETINFO");
+		close(fd);
+		exit(1);
+	}
+
+	if (length == -1)
+		length = meminfo.size;
+
+	if (offset % meminfo.erasesize) {
+		fprintf(stderr, "Offset %x not multiple of erase size %x\n",
+			offset, meminfo.erasesize);
+		exit(1);
+	}
+	if (length % meminfo.erasesize) {
+		fprintf(stderr, "Length %x not multiple of erase size %x\n",
+			length, meminfo.erasesize);
+		exit(1);
+	}
+	if (length + offset > meminfo.size) {
+		fprintf(stderr, "Length %x + offset %x exceeds device size %x\n",
+			length, offset, meminfo.size);
+		exit(1);
+	}
+
+	wbuf = malloc(meminfo.erasesize * 3);
+	if (!wbuf) {
+		fprintf(stderr, "Could not allocate %d bytes for buffer\n",
+			meminfo.erasesize * 2);
+		exit(1);
+	}
+	rbuf = wbuf + meminfo.erasesize;
+	kbuf = rbuf + meminfo.erasesize;
+
+	if (ioctl(fd, ECCGETSTATS, &oldstats)) {
+		perror("ECCGETSTATS");
+		close(fd);
+		exit(1);
+	}
+
+	printf("ECC corrections: %d\n", oldstats.corrected);
+	printf("ECC failures   : %d\n", oldstats.failed);
+	printf("Bad blocks     : %d\n", oldstats.badblocks);
+	printf("BBT blocks     : %d\n", oldstats.bbtblocks);
+
+	srand(seed);
+
+	for (pass = 0; pass < nr_passes; pass++) {
+		loff_t test_ofs;
+
+		for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) {
+			ssize_t len;
+
+			seed = rand();
+			srand(seed);
+
+			if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) {
+				printf("\rBad block at 0x%08x\n", (unsigned)test_ofs);
+				continue;
+			}
+
+			for (i=0; i<meminfo.erasesize; i++)
+				wbuf[i] = rand();
+
+			if (keep_contents) {
+				printf("\r%08x: reading... ", (unsigned)test_ofs);
+				fflush(stdout);
+
+				len = pread(fd, kbuf, meminfo.erasesize, test_ofs);
+				if (len < meminfo.erasesize) {
+					printf("\n");
+					if (len)
+						fprintf(stderr, "Short read (%zd bytes)\n", len);
+					else
+						perror("read");
+					exit(1);
+				}
+			}
+			if (erase_and_write(test_ofs, wbuf, rbuf, nr_reads))
+				continue;
+			if (keep_contents)
+				erase_and_write(test_ofs, kbuf, rbuf, 1);
+		}
+		printf("\nFinished pass %d successfully\n", pass+1);
+	}
+	/* Return happy */
+	return 0;
+}

+ 620 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/nandwrite.c

@@ -0,0 +1,620 @@
+/*
+ *  nandwrite.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *		  2003 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ *   This utility writes a binary image directly to a NAND flash
+ *   chip or NAND chips contained in DoC devices. This is the
+ *   "inverse operation" of nanddump.
+ *
+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC
+ *	 write oob data only on request
+ *
+ * Bug/ToDo:
+ */
+
+#define PROGRAM_NAME "nandwrite"
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+#include "common.h"
+#include <libmtd.h>
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
+"Writes to the specified MTD device.\n"
+"\n"
+"  -a, --autoplace         Use auto OOB layout\n"
+"  -k, --skip-all-ffs      Skip pages that contain only 0xff bytes\n"
+"  -m, --markbad           Mark blocks bad if write fails\n"
+"  -n, --noecc             Write without ecc\n"
+"  -N, --noskipbad         Write without bad block skipping\n"
+"  -o, --oob               Input contains oob data\n"
+"  -O, --onlyoob           Input contains oob data and only write the oob part\n"
+"  -s addr, --start=addr   Set output start address (default is 0)\n"
+"  --skip-bad-blocks-to-start"
+"                          Skip bad blocks when seeking to the start address\n"
+"  -p, --pad               Pad writes to page size\n"
+"  -b, --blockalign=1|2|4  Set multiple of eraseblocks to align to\n"
+"      --input-skip=length Skip |length| bytes of the input file\n"
+"      --input-size=length Only read |length| bytes of the input file\n"
+"  -q, --quiet             Don't display progress messages\n"
+"  -h, --help              Display this help and exit\n"
+"  -V, --version           Output version information and exit\n"
+	);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("Copyright (C) 2003 Thomas Gleixner \n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+static const char	*standard_input = "-";
+static const char	*mtd_device, *img;
+static long long	mtdoffset = 0;
+static long long	inputskip = 0;
+static long long	inputsize = 0;
+static bool		quiet = false;
+static bool		writeoob = false;
+static bool		onlyoob = false;
+static bool		markbad = false;
+static bool		noecc = false;
+static bool		autoplace = false;
+static bool		skipallffs = false;
+static bool		noskipbad = false;
+static bool		pad = false;
+static bool		skip_bad_blocks_to_start = false;
+static int		blockalign = 1; /* default to using actual block size */
+
+static void process_options(int argc, char * const argv[])
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char short_options[] = "hb:mnNoOpqs:akV";
+		static const struct option long_options[] = {
+			/* Order of these args with val==0 matters; see option_index. */
+			{"version", no_argument, 0, 'V'},
+			{"input-skip", required_argument, 0, 0},
+			{"input-size", required_argument, 0, 0},
+			{"skip-bad-blocks-to-start", no_argument, 0, 0},
+			{"help", no_argument, 0, 'h'},
+			{"blockalign", required_argument, 0, 'b'},
+			{"markbad", no_argument, 0, 'm'},
+			{"noecc", no_argument, 0, 'n'},
+			{"noskipbad", no_argument, 0, 'N'},
+			{"oob", no_argument, 0, 'o'},
+			{"onlyoob", no_argument, 0, 'O'},
+			{"pad", no_argument, 0, 'p'},
+			{"quiet", no_argument, 0, 'q'},
+			{"start", required_argument, 0, 's'},
+			{"autoplace", no_argument, 0, 'a'},
+			{"skip-all-ffs", no_argument, 0, 'k'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 0:
+			switch (option_index) {
+			case 1: /* --input-skip */
+				inputskip = simple_strtoll(optarg, &error);
+				break;
+			case 2: /* --input-size */
+				inputsize = simple_strtoll(optarg, &error);
+				break;
+			case 3: /* --skip-bad-blocks-to-start */
+				skip_bad_blocks_to_start = true;
+				break;
+			}
+			break;
+		case 'V':
+			display_version();
+			break;
+		case 'q':
+			quiet = true;
+			break;
+		case 'n':
+			noecc = true;
+			break;
+		case 'N':
+			noskipbad = true;
+			break;
+		case 'm':
+			markbad = true;
+			break;
+		case 'o':
+			writeoob = true;
+			break;
+		case 'O':
+			writeoob = true;
+			onlyoob = true;
+			break;
+		case 'p':
+			pad = true;
+			break;
+		case 's':
+			mtdoffset = simple_strtoll(optarg, &error);
+			break;
+		case 'b':
+			blockalign = atoi(optarg);
+			break;
+		case 'a':
+			autoplace = true;
+			break;
+		case 'k':
+			skipallffs = true;
+			break;
+		case 'h':
+			display_help(EXIT_SUCCESS);
+			break;
+		case '?':
+			error++;
+			break;
+		}
+	}
+
+	if (mtdoffset < 0)
+		errmsg_die("Can't specify negative device offset with option"
+				" -s: %lld", mtdoffset);
+
+	if (blockalign <= 0)
+		errmsg_die("Can't specify negative or zero blockalign with "
+				"option -b: %d", blockalign);
+
+	if (!is_power_of_2(blockalign))
+		errmsg_die("Can't specify a non-power-of-two blockalign with "
+				"option -b: %d", blockalign);
+
+	if (autoplace && noecc)
+		errmsg_die("Autoplacement and no-ECC are mutually exclusive");
+
+	if (!onlyoob && (pad && writeoob))
+		errmsg_die("Can't pad when oob data is present");
+
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * There must be at least the MTD device node positional
+	 * argument remaining and, optionally, the input file.
+	 */
+
+	if (argc < 1 || argc > 2 || error)
+		display_help(EXIT_FAILURE);
+
+	mtd_device = argv[0];
+
+	/*
+	 * Standard input may be specified either explictly as "-" or
+	 * implicity by simply omitting the second of the two
+	 * positional arguments.
+	 */
+
+	img = ((argc == 2) ? argv[1] : standard_input);
+}
+
+static void erase_buffer(void *buffer, size_t size)
+{
+	const uint8_t kEraseByte = 0xff;
+
+	if (buffer != NULL && size > 0)
+		memset(buffer, kEraseByte, size);
+}
+
+static int is_virt_block_bad(struct mtd_dev_info *mtd, int fd,
+				long long offset)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < blockalign; ++i) {
+		ret = mtd_is_bad(mtd, fd, offset / mtd->eb_size + i);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char * const argv[])
+{
+	int fd = -1;
+	int ifd = -1;
+	int pagelen;
+	long long imglen = 0;
+	long long blockstart = -1;
+	struct mtd_dev_info mtd;
+	int ret;
+	bool failed = true;
+	/* contains all the data read from the file so far for the current eraseblock */
+	unsigned char *filebuf = NULL;
+	size_t filebuf_max = 0;
+	size_t filebuf_len = 0;
+	/* points to the current page inside filebuf */
+	unsigned char *writebuf = NULL;
+	/* points to the OOB for the current page in filebuf */
+	unsigned char *oobbuf = NULL;
+	libmtd_t mtd_desc;
+	int ebsize_aligned;
+	uint8_t write_mode;
+
+	process_options(argc, argv);
+
+	/* Open the device */
+	if ((fd = open(mtd_device, O_RDWR)) == -1)
+		sys_errmsg_die("%s", mtd_device);
+
+	mtd_desc = libmtd_open();
+	if (!mtd_desc)
+		errmsg_die("can't initialize libmtd");
+
+	/* Fill in MTD device capability structure */
+	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
+		errmsg_die("mtd_get_dev_info failed");
+
+	/*
+	 * Pretend erasesize is specified number of blocks - to match jffs2
+	 *   (virtual) block size
+	 * Use this value throughout unless otherwise necessary
+	 */
+	ebsize_aligned = mtd.eb_size * blockalign;
+
+	if (mtdoffset & (mtd.min_io_size - 1))
+		errmsg_die("The start address is not page-aligned !\n"
+			   "The pagesize of this NAND Flash is 0x%x.\n",
+			   mtd.min_io_size);
+
+	/* Select OOB write mode */
+	if (noecc)
+		write_mode = MTD_OPS_RAW;
+	else if (autoplace)
+		write_mode = MTD_OPS_AUTO_OOB;
+	else
+		write_mode = MTD_OPS_PLACE_OOB;
+
+	if (noecc)  {
+		ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
+		if (ret) {
+			switch (errno) {
+			case ENOTTY:
+				errmsg_die("ioctl MTDFILEMODE is missing");
+			default:
+				sys_errmsg_die("MTDFILEMODE");
+			}
+		}
+	}
+
+	/* Determine if we are reading from standard input or from a file. */
+	if (strcmp(img, standard_input) == 0)
+		ifd = STDIN_FILENO;
+	else
+		ifd = open(img, O_RDONLY);
+
+	if (ifd == -1) {
+		perror(img);
+		goto closeall;
+	}
+
+	pagelen = mtd.min_io_size + ((writeoob) ? mtd.oob_size : 0);
+
+	if (ifd == STDIN_FILENO) {
+		imglen = inputsize ? : pagelen;
+		if (inputskip) {
+			errmsg("seeking stdin not supported");
+			goto closeall;
+		}
+	} else {
+		if (!inputsize) {
+			struct stat st;
+			if (fstat(ifd, &st)) {
+				sys_errmsg("unable to stat input image");
+				goto closeall;
+			}
+			imglen = st.st_size - inputskip;
+		} else
+			imglen = inputsize;
+
+		if (inputskip && lseek(ifd, inputskip, SEEK_CUR) == -1) {
+			sys_errmsg("lseek input by %lld failed", inputskip);
+			goto closeall;
+		}
+	}
+
+	/* Check, if file is page-aligned */
+	if (!pad && (imglen % pagelen) != 0) {
+		fprintf(stderr, "Input file is not page-aligned. Use the padding "
+				 "option.\n");
+		goto closeall;
+	}
+
+	/* Skip bad blocks on the way to the start address if necessary */
+	if (skip_bad_blocks_to_start) {
+		long long bbs_offset = 0;
+		while (bbs_offset < mtdoffset) {
+			ret = is_virt_block_bad(&mtd, fd, bbs_offset);
+			if (ret < 0) {
+				sys_errmsg("%s: MTD get bad block failed", mtd_device);
+				goto closeall;
+			} else if (ret == 1) {
+				if (!quiet)
+					fprintf(stderr, "Bad block at %llx, %u block(s) "
+						"from %llx will be skipped\n",
+						bbs_offset, blockalign, bbs_offset);
+				mtdoffset += ebsize_aligned;
+			}
+			bbs_offset += ebsize_aligned;
+		}
+	}
+
+	/* Check, if length fits into device */
+	if ((imglen / pagelen) * mtd.min_io_size > mtd.size - mtdoffset) {
+		fprintf(stderr, "Image %lld bytes, NAND page %d bytes, OOB area %d"
+				" bytes, device size %lld bytes\n",
+				imglen, pagelen, mtd.oob_size, mtd.size);
+		sys_errmsg("Input file does not fit into device");
+		goto closeall;
+	}
+
+	/*
+	 * Allocate a buffer big enough to contain all the data (OOB included)
+	 * for one eraseblock. The order of operations here matters; if ebsize
+	 * and pagelen are large enough, then "ebsize_aligned * pagelen" could
+	 * overflow a 32-bit data type.
+	 */
+	filebuf_max = ebsize_aligned / mtd.min_io_size * pagelen;
+	filebuf = xmalloc(filebuf_max);
+	erase_buffer(filebuf, filebuf_max);
+
+	/*
+	 * Get data from input and write to the device while there is
+	 * still input to read and we are still within the device
+	 * bounds. Note that in the case of standard input, the input
+	 * length is simply a quasi-boolean flag whose values are page
+	 * length or zero.
+	 */
+	while ((imglen > 0 || writebuf < filebuf + filebuf_len)
+		&& mtdoffset < mtd.size) {
+		/*
+		 * New eraseblock, check for bad block(s)
+		 * Stay in the loop to be sure that, if mtdoffset changes because
+		 * of a bad block, the next block that will be written to
+		 * is also checked. Thus, we avoid errors if the block(s) after the
+		 * skipped block(s) is also bad (number of blocks depending on
+		 * the blockalign).
+		 */
+		while (blockstart != (mtdoffset & (~ebsize_aligned + 1))) {
+			blockstart = mtdoffset & (~ebsize_aligned + 1);
+
+			/*
+			 * if writebuf == filebuf, we are rewinding so we must
+			 * not reset the buffer but just replay it
+			 */
+			if (writebuf != filebuf) {
+				erase_buffer(filebuf, filebuf_len);
+				filebuf_len = 0;
+				writebuf = filebuf;
+			}
+
+			if (!quiet)
+				fprintf(stdout, "Writing data to block %lld at offset 0x%llx\n",
+						 blockstart / ebsize_aligned, blockstart);
+
+			if (noskipbad)
+				continue;
+
+			ret = is_virt_block_bad(&mtd, fd, blockstart);
+
+			if (ret < 0) {
+				sys_errmsg("%s: MTD get bad block failed", mtd_device);
+				goto closeall;
+			} else if (ret == 1) {
+				if (!quiet)
+					fprintf(stderr,
+						"Bad block at %llx, %u block(s) "
+						"will be skipped\n",
+						blockstart, blockalign);
+
+				mtdoffset = blockstart + ebsize_aligned;
+
+				if (mtdoffset > mtd.size) {
+					errmsg("too many bad blocks, cannot complete request");
+					goto closeall;
+				}
+			}
+		}
+
+		/* Read more data from the input if there isn't enough in the buffer */
+		if (writebuf + mtd.min_io_size > filebuf + filebuf_len) {
+			size_t readlen = mtd.min_io_size;
+			size_t alreadyread = (filebuf + filebuf_len) - writebuf;
+			size_t tinycnt = alreadyread;
+			ssize_t cnt = 0;
+
+			while (tinycnt < readlen) {
+				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
+				if (cnt == 0) { /* EOF */
+					break;
+				} else if (cnt < 0) {
+					perror("File I/O error on input");
+					goto closeall;
+				}
+				tinycnt += cnt;
+			}
+
+			/* No padding needed - we are done */
+			if (tinycnt == 0) {
+				/*
+				 * For standard input, set imglen to 0 to signal
+				 * the end of the "file". For nonstandard input,
+				 * leave it as-is to detect an early EOF.
+				 */
+				if (ifd == STDIN_FILENO)
+					imglen = 0;
+
+				break;
+			}
+
+			/* Padding */
+			if (tinycnt < readlen) {
+				if (!pad) {
+					fprintf(stderr, "Unexpected EOF. Expecting at least "
+							"%zu more bytes. Use the padding option.\n",
+							readlen - tinycnt);
+					goto closeall;
+				}
+				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
+			}
+
+			filebuf_len += readlen - alreadyread;
+			if (ifd != STDIN_FILENO) {
+				imglen -= tinycnt - alreadyread;
+			} else if (cnt == 0) {
+				/* No more bytes - we are done after writing the remaining bytes */
+				imglen = 0;
+			}
+		}
+
+		if (writeoob) {
+			oobbuf = writebuf + mtd.min_io_size;
+
+			/* Read more data for the OOB from the input if there isn't enough in the buffer */
+			if (oobbuf + mtd.oob_size > filebuf + filebuf_len) {
+				size_t readlen = mtd.oob_size;
+				size_t alreadyread = (filebuf + filebuf_len) - oobbuf;
+				size_t tinycnt = alreadyread;
+				ssize_t cnt;
+
+				while (tinycnt < readlen) {
+					cnt = read(ifd, oobbuf + tinycnt, readlen - tinycnt);
+					if (cnt == 0) { /* EOF */
+						break;
+					} else if (cnt < 0) {
+						perror("File I/O error on input");
+						goto closeall;
+					}
+					tinycnt += cnt;
+				}
+
+				if (tinycnt < readlen) {
+					fprintf(stderr, "Unexpected EOF. Expecting at least "
+							"%zu more bytes for OOB\n", readlen - tinycnt);
+					goto closeall;
+				}
+
+				filebuf_len += readlen - alreadyread;
+				if (ifd != STDIN_FILENO) {
+					imglen -= tinycnt - alreadyread;
+				} else if (cnt == 0) {
+					/* No more bytes - we are done after writing the remaining bytes */
+					imglen = 0;
+				}
+			}
+		}
+
+		ret = 0;
+		if (!skipallffs || !buffer_check_pattern(writebuf, mtd.min_io_size, 0xff)) {
+			/* Write out data */
+			ret = mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size,
+					mtdoffset % mtd.eb_size,
+					onlyoob ? NULL : writebuf,
+					onlyoob ? 0 : mtd.min_io_size,
+					writeoob ? oobbuf : NULL,
+					writeoob ? mtd.oob_size : 0,
+					write_mode);
+		}
+
+		if (ret) {
+			if (errno != EIO) {
+				sys_errmsg("%s: MTD write failure", mtd_device);
+				goto closeall;
+			}
+
+			/* Must rewind to blockstart if we can */
+			writebuf = filebuf;
+
+			fprintf(stderr, "Erasing failed write from %#08llx to %#08llx\n",
+				blockstart, blockstart + ebsize_aligned - 1);
+
+			if (mtd_erase_multi(mtd_desc, &mtd, fd,
+					blockstart / mtd.eb_size, blockalign)) {
+				int errno_tmp = errno;
+				sys_errmsg("%s: MTD Erase failure", mtd_device);
+				if (errno_tmp != EIO)
+					goto closeall;
+			}
+
+			if (markbad) {
+				fprintf(stderr, "Marking block at %08llx bad\n",
+						mtdoffset & (~mtd.eb_size + 1));
+				if (mtd_mark_bad(&mtd, fd, mtdoffset / mtd.eb_size)) {
+					sys_errmsg("%s: MTD Mark bad block failure", mtd_device);
+					goto closeall;
+				}
+			}
+			mtdoffset = blockstart + ebsize_aligned;
+
+			continue;
+		}
+		mtdoffset += mtd.min_io_size;
+		writebuf += pagelen;
+	}
+
+	failed = false;
+
+closeall:
+	if (ifd > 0 && ifd != STDIN_FILENO)
+		close(ifd);
+	libmtd_close(mtd_desc);
+	free(filebuf);
+	close(fd);
+
+	if (failed || (ifd != STDIN_FILENO && imglen > 0)
+		   || (writebuf < filebuf + filebuf_len))
+		sys_errmsg_die("Data was only partially written due to error");
+
+	/* Return happy */
+	return EXIT_SUCCESS;
+}

+ 445 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/nftl_format.c

@@ -0,0 +1,445 @@
+/*
+ * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ToDo:
+ *	1. UnitSizeFactor != 0xFF cases
+ *	2. test, test, and test !!!
+ */
+
+#define PROGRAM_NAME "nftl_format"
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+#include "common.h"
+
+unsigned char BadUnitTable[MAX_ERASE_ZONES];
+unsigned char *readbuf;
+unsigned char *writebuf[4];
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct NFTLMediaHeader *NFTLhdr;
+struct INFTLMediaHeader *INFTLhdr;
+
+static int do_oobcheck = 1;
+static int do_rwecheck = 1;
+
+static const struct option long_opts[] = {
+	{"version", no_argument, 0, 'V'},
+	{"help", no_argument, 0, 'h'},
+	{0, 0, 0, 0},
+};
+
+static unsigned char check_block_1(unsigned long block)
+{
+	unsigned char oobbuf[16];
+	struct mtd_oob_buf oob = { 0, 16, oobbuf };
+
+	oob.start = block * meminfo.erasesize;
+	if (ioctl(fd, MEMREADOOB, &oob))
+		return ZONE_BAD_ORIGINAL;
+
+	if(oobbuf[5] == 0)
+		return ZONE_BAD_ORIGINAL;
+
+	oob.start = block * meminfo.erasesize + 512 /* FIXME */;
+	if (ioctl(fd, MEMREADOOB, &oob))
+		return ZONE_BAD_ORIGINAL;
+
+	if(oobbuf[5] == 0)
+		return ZONE_BAD_ORIGINAL;
+
+	return ZONE_GOOD;
+}
+
+static unsigned char check_block_2(unsigned long block)
+{
+	unsigned long ofs = block * meminfo.erasesize;
+	unsigned long blockofs;
+
+	/* Erase test */
+	erase.start = ofs;
+
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pread_nocheck(fd, readbuf, 512, ofs + blockofs);
+		if (memcmp(readbuf, writebuf[0], 512)) {
+			/* Block wasn't 0xff after erase */
+			printf(": Block not 0xff after erase\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+
+		pwrite_nocheck(fd, writebuf[1], 512, blockofs + ofs);
+		pread_nocheck(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[1], 512)) {
+			printf(": Block not zero after clearing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	/* Write test */
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Second erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pwrite_nocheck(fd, writebuf[2], 512, blockofs + ofs);
+		pread_nocheck(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[2], 512)) {
+			printf(": Block not 0x5a after writing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Third erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+		pwrite_nocheck(fd, writebuf[3], 512, blockofs + ofs);
+		pread_nocheck(fd, readbuf, 512, blockofs + ofs);
+		if (memcmp(readbuf, writebuf[3], 512)) {
+			printf(": Block not 0xa5 after writing\n");
+			return ZONE_BAD_ORIGINAL;
+		}
+	}
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+		printf(": Fourth erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+	return ZONE_GOOD;
+}
+
+static unsigned char erase_block(unsigned long block)
+{
+	unsigned char status;
+	int ret;
+
+	status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
+	erase.start = block * meminfo.erasesize;
+
+	if (status != ZONE_GOOD) {
+		printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
+		fflush(stdout);
+		return status;
+	}
+
+	printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
+	fflush(stdout);
+
+	if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
+		printf(": Erase failed (%s)\n", strerror(errno));
+		return ZONE_BAD_ORIGINAL;
+	}
+
+	if (do_rwecheck) {
+		printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
+		fflush(stdout);
+		status = check_block_2(block);
+		if (status != ZONE_GOOD) {
+			printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
+			fflush(stdout);
+		}
+	}
+	return status;
+}
+
+static int checkbbt(void)
+{
+	unsigned char bbt[512];
+	unsigned char bits;
+	int i, addr;
+
+	if (pread_nocheck(fd, bbt, 512, 0x800) < 0) {
+		printf("%s: failed to read BBT, errno=%d\n", PROGRAM_NAME, errno);
+		return (-1);
+	}
+
+
+	for (i = 0; (i < 512); i++) {
+		addr = i / 4;
+		bits = 0x3 << ((i % 4) * 2);
+		if ((bbt[addr] & bits) == 0) {
+			BadUnitTable[i] = ZONE_BAD_ORIGINAL;
+		}
+	}
+
+	return (0);
+}
+
+static NORETURN void usage(int rc)
+{
+	fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME);
+	exit(rc);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("Copyright (C) 2005 Thomas Gleixner \n"
+			"\n"
+			"%1$s comes with NO WARRANTY\n"
+			"to the extent permitted by law.\n"
+			"\n"
+			"You may redistribute copies of %1$s\n"
+			"under the terms of the GNU General Public Licence.\n"
+			"See the file `COPYING' for more information.\n",
+			PROGRAM_NAME);
+	exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+	unsigned long startofs = 0, part_size = 0;
+	unsigned long ezones = 0, ezone = 0, bad_zones = 0;
+	unsigned char unit_factor = 0xFF;
+	long MediaUnit1 = -1, MediaUnit2 = -1;
+	long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
+	unsigned char oobbuf[16];
+	struct mtd_oob_buf oob = {0, 16, oobbuf};
+	char *mtddevice;
+	const char *nftl;
+	int c, do_inftl = 0, do_bbt = 0;
+	int idx = 0;
+
+	if (argc < 2)
+		usage(EXIT_FAILURE);
+
+	nftl = "NFTL";
+
+	while ((c = getopt_long(argc, argv, "?hibV", long_opts, &idx)) != -1) {
+		switch (c) {
+			case 'i':
+				nftl = "INFTL";
+				do_inftl = 1;
+				break;
+			case 'b':
+				do_bbt = 1;
+				break;
+			case 'h':
+			case '?':
+				usage(EXIT_SUCCESS);
+			case 'V':
+				display_version();
+				break;
+			default:
+				usage(EXIT_FAILURE);
+		}
+	}
+
+	mtddevice = argv[optind++];
+	if (argc > optind) {
+		startofs = strtoul(argv[optind++], NULL, 0);
+	}
+	if (argc > optind) {
+		part_size = strtoul(argv[optind++], NULL, 0);
+	}
+
+	// Open and size the device
+	if ((fd = open(mtddevice, O_RDWR)) < 0) {
+		perror("Open flash device");
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		close(fd);
+		return 1;
+	}
+
+	switch (meminfo.erasesize) {
+		case 0x1000:
+		case 0x2000:
+		case 0x4000:
+		case 0x8000:
+			break;
+		default:
+			printf("Unrecognized Erase size, 0x%x - I'm confused\n",
+					meminfo.erasesize);
+			close(fd);
+			return 1;
+	}
+	writebuf[0] = malloc(meminfo.erasesize * 5);
+	if (!writebuf[0]) {
+		printf("Malloc failed\n");
+		close(fd);
+		return 1;
+	}
+	writebuf[1] = writebuf[0] + meminfo.erasesize;
+	writebuf[2] = writebuf[1] + meminfo.erasesize;
+	writebuf[3] = writebuf[2] + meminfo.erasesize;
+	readbuf = writebuf[3] + meminfo.erasesize;
+	memset(writebuf[0], 0xff, meminfo.erasesize);
+	memset(writebuf[1], 0x00, meminfo.erasesize);
+	memset(writebuf[2], 0x5a, meminfo.erasesize);
+	memset(writebuf[3], 0xa5, meminfo.erasesize);
+	memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
+
+	if (part_size == 0 || (part_size > meminfo.size - startofs))
+		/* the user doest not or incorrectly specify NFTL partition size */
+		part_size = meminfo.size - startofs;
+
+	erase.length = meminfo.erasesize;
+	ezones = part_size / meminfo.erasesize;
+
+	if (ezones > MAX_ERASE_ZONES) {
+		/* Ought to change the UnitSizeFactor. But later. */
+		part_size = meminfo.erasesize * MAX_ERASE_ZONES;
+		ezones = MAX_ERASE_ZONES;
+		unit_factor = 0xFF;
+	}
+
+	/* If using device BBT then parse that now */
+	if (do_bbt) {
+		checkbbt();
+		do_oobcheck = 0;
+		do_rwecheck = 0;
+	}
+
+	/* Phase 1. Erasing and checking each erase zones in the NFTL partition.
+	   N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
+	printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
+			startofs, startofs + part_size);
+	for (ezone = startofs / meminfo.erasesize;
+			ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+		if (BadUnitTable[ezone] != ZONE_GOOD)
+			continue;
+		if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
+			if (MediaUnit1 == -1) {
+				MediaUnit1 = ezone;
+			} else if (MediaUnit2 == -1) {
+				MediaUnit2 = ezone;
+			}
+		} else {
+			bad_zones++;
+		}
+	}
+	printf("\n");
+
+	/* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
+	   by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
+	if (do_inftl) {
+		unsigned long maxzones, pezstart, pezend, numvunits;
+
+		INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
+		strcpy(INFTLhdr->bootRecordID, "BNAND");
+		INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
+		INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
+		INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
+		INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
+		INFTLhdr->FormatFlags = cpu_to_le32(0);
+		INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
+		INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
+		/*
+		 * Calculate number of virtual units we will have to work
+		 * with. I am calculating out the known bad units here, not
+		 * sure if that is what M-Systems do...
+		 */
+		MediaUnit2 = MediaUnit1;
+		MediaUnitOff2 = 4096;
+		maxzones = meminfo.size / meminfo.erasesize;
+		pezstart = startofs / meminfo.erasesize + 1;
+		pezend = startofs / meminfo.erasesize + ezones - 1;
+		numvunits = (ezones - 2) * PERCENTUSED / 100;
+		for (ezone = pezstart; ezone < maxzones; ezone++) {
+			if (BadUnitTable[ezone] != ZONE_GOOD) {
+				if (numvunits > 1)
+					numvunits--;
+			}
+		}
+
+		INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
+		INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
+		INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
+		INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
+		INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
+		INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
+		INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
+
+	} else {
+
+		NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
+		strcpy(NFTLhdr->DataOrgID, "ANAND");
+		NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
+		NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
+		/* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
+		NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
+		NFTLhdr->UnitSizeFactor = unit_factor;
+	}
+
+	/* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
+	printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
+	pwrite_nocheck(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
+	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+		pwrite_nocheck(fd, BadUnitTable + ezone, 512,
+				(MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
+	}
+
+#if 0
+	printf("  MediaHeader contents:\n");
+	printf("    NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
+	printf("    FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
+	printf("    FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
+			le32_to_cpu(NFTLhdr->FormattedSize)/512);
+#endif
+	printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
+	pwrite_nocheck(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
+	for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+		pwrite_nocheck(fd, BadUnitTable + ezone, 512,
+				(MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
+	}
+
+	/* UCI #1 for newly erased Erase Unit */
+	memset(oobbuf, 0xff, 16);
+	oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
+	oobbuf[8]  = (do_inftl) ? 0x00 : 0x03;
+	oobbuf[12] = oobbuf[14] = 0x69;
+	oobbuf[13] = oobbuf[15] = 0x3c;
+
+	/* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
+	   by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
+	   but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
+	/* Phase 3. Writing Unit Control Information for each Erase Unit */
+	printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
+	for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+		/* write UCI #1 to each Erase Unit */
+		if (BadUnitTable[ezone] != ZONE_GOOD)
+			continue;
+		oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
+		if (ioctl(fd, MEMWRITEOOB, &oob))
+			printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
+	}
+
+	exit(0);
+}

+ 280 - 0
EVSE/GPL/mtd-utils-2.1.2/nand-utils/nftldump.c

@@ -0,0 +1,280 @@
+/*
+ * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ToDo:
+ *	1. UnitSizeFactor != 0xFF cases
+ *	2. test, test, and test !!!
+ */
+
+#define PROGRAM_NAME "nftldump"
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd_swab.h>
+
+#include "common.h"
+
+static struct NFTLMediaHeader MedHead[2];
+static mtd_info_t meminfo;
+
+static struct nftl_oob oobbuf;
+static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
+
+static int fd, ofd = -1;;
+static int NumMedHeads;
+
+static unsigned char BadUnitTable[MAX_ERASE_ZONES];
+
+#define SWAP16(x) do { x = le16_to_cpu(x); } while(0)
+#define SWAP32(x) do { x = le32_to_cpu(x); } while(0)
+
+/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
+static unsigned short *VUCtable;
+
+/* FixMe: make this dynamic allocated */
+#define ERASESIZE 0x2000
+#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
+static union nftl_uci UCItable[NUMVUNITS][3];
+
+static unsigned short nextEUN(unsigned short curEUN)
+{
+	return UCItable[curEUN][0].a.ReplUnitNum;
+}
+
+static unsigned int find_media_headers(void)
+{
+	int i;
+	static unsigned long ofs = 0;
+
+	NumMedHeads = 0;
+	while (ofs < meminfo.size) {
+		pread_nocheck(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
+		if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
+			SWAP16(MedHead[NumMedHeads].NumEraseUnits);
+			SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
+			SWAP32(MedHead[NumMedHeads].FormattedSize);
+
+			if (NumMedHeads == 0) {
+				printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
+				printf("NumEraseUnits:    %d\n",
+						MedHead[NumMedHeads].NumEraseUnits);
+				printf("FirstPhysicalEUN: %d\n",
+						MedHead[NumMedHeads].FirstPhysicalEUN);
+				printf("Formatted Size:   %d\n",
+						MedHead[NumMedHeads].FormattedSize);
+				printf("UnitSizeFactor:   0x%x\n",
+						MedHead[NumMedHeads].UnitSizeFactor);
+
+				/* read BadUnitTable, I don't know why pread() does not work for
+				   larger (7680 bytes) chunks */
+				for (i = 0; i < MAX_ERASE_ZONES; i += 512)
+					pread_nocheck(fd, &BadUnitTable[i], 512, ofs + 512 + i);
+			} else
+				printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
+			NumMedHeads++;
+		}
+
+		ofs += meminfo.erasesize;
+		if (NumMedHeads == 2) {
+			if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
+				printf("warning: NFTL Media Header is not consistent with "
+						"Spare NFTL Media Header\n");
+			}
+			break;
+		}
+	}
+
+	/* allocate Virtual Unit Chain table for this NFTL partition */
+	VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
+	return NumMedHeads;
+}
+
+static void dump_erase_units(void)
+{
+	int i, j;
+	unsigned long ofs;
+
+	for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
+			MedHead[0].NumEraseUnits; i++) {
+		/* For each Erase Unit */
+		ofs = i * meminfo.erasesize;
+
+		/* read the Unit Control Information */
+		for (j = 0; j < 3; j++) {
+			oob.start = ofs + (j * 512);
+			if (ioctl(fd, MEMREADOOB, &oob))
+				printf("MEMREADOOB at %lx: %s\n",
+						(unsigned long) oob.start, strerror(errno));
+			memcpy(&UCItable[i][j], &oobbuf.u, 8);
+		}
+		if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
+			printf("EraseMark not present in unit %d: %x\n",
+					i, UCItable[i][1].b.EraseMark);
+		} else {
+			/* a properly formatted unit */
+			SWAP16(UCItable[i][0].a.VirtUnitNum);
+			SWAP16(UCItable[i][0].a.ReplUnitNum);
+			SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
+			SWAP16(UCItable[i][0].a.SpareReplUnitNum);
+			SWAP32(UCItable[i][1].b.WearInfo);
+			SWAP16(UCItable[i][1].b.EraseMark);
+			SWAP16(UCItable[i][1].b.EraseMark1);
+			SWAP16(UCItable[i][2].c.FoldMark);
+			SWAP16(UCItable[i][2].c.FoldMark1);
+
+			if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
+				/* If this is the first in a chain, store the EUN in the VUC table */
+				if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
+					printf("Duplicate start of chain for VUC %d: "
+							"Unit %d replaces Unit %d\n",
+							UCItable[i][0].a.VirtUnitNum & 0x7fff,
+							i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
+				}
+				VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
+			}
+		}
+
+		switch (BadUnitTable[i]) {
+			case ZONE_BAD_ORIGINAL:
+				printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
+				continue;
+			case ZONE_BAD_MARKED:
+				printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
+				continue;
+		}
+
+		/* ZONE_GOOD */
+		if (UCItable[i][0].a.VirtUnitNum == 0xffff)
+			printf("Unit %d is free\n", i);
+		else
+			printf("Unit %d is in chain %d and %s a replacement\n", i,
+					UCItable[i][0].a.VirtUnitNum & 0x7fff,
+					UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
+	}
+}
+
+static void dump_virtual_units(void)
+{
+	int i, j;
+	char readbuf[512];
+
+	for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
+		unsigned short curEUN = VUCtable[i];
+
+		printf("Virtual Unit #%d: ", i);
+		if (!curEUN) {
+			printf("Not present\n");
+			continue;
+		}
+		printf("%d", curEUN);
+
+		/* walk through the Virtual Unit Chain */
+		while ((curEUN = nextEUN(curEUN)) != 0xffff) {
+			printf(", %d", curEUN & 0x7fff);
+		}
+		printf("\n");
+
+		if (ofd != -1) {
+			/* Actually write out the data */
+			for (j = 0; j < meminfo.erasesize / 512; j++) {
+				/* For each sector in the block */
+				unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
+				unsigned int status;
+
+				if (thisEUN == 0xffff) thisEUN = 0;
+
+				while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
+					oob.start = (thisEUN * ERASESIZE) + (j * 512);
+					ioctl(fd, MEMREADOOB, &oob);
+					status = oobbuf.b.Status | oobbuf.b.Status1;
+
+					switch (status) {
+						case SECTOR_FREE:
+							/* This is still free. Don't look any more */
+							thisEUN = 0;
+							break;
+
+						case SECTOR_USED:
+							/* SECTOR_USED. This is a good one. */
+							lastgoodEUN = thisEUN;
+							break;
+					}
+
+					/* Find the next erase unit in this chain, if any */
+					if (thisEUN)
+						thisEUN = nextEUN(thisEUN) & 0x7fff;
+				}
+
+				if (lastgoodEUN == 0xffff)
+					memset(readbuf, 0, 512);
+				else
+					pread_nocheck(fd, readbuf, 512,
+							(lastgoodEUN * ERASESIZE) + (j * 512));
+
+				write_nocheck(ofd, readbuf, 512);
+			}
+
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: %s <device> [<outfile>]\n", PROGRAM_NAME);
+		exit(1);
+	}
+	fd = open(argv[1], O_RDONLY);
+	if (fd == -1) {
+		perror("open flash");
+		exit (1);
+	}
+
+	if (argc > 2) {
+		ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
+		if (ofd == -1)
+			perror ("open outfile");
+	}
+
+	/* get size information of the MTD device */
+	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+		perror("ioctl(MEMGETINFO)");
+		close(fd);
+		return 1;
+	}
+
+	while (find_media_headers() != 0) {
+		dump_erase_units();
+		dump_virtual_units();
+		free(VUCtable);
+	}
+
+	exit(0);
+}

+ 10 - 0
EVSE/GPL/mtd-utils-2.1.2/nor-utils/Makemodule.am

@@ -0,0 +1,10 @@
+rfddump_SOURCES = nor-utils/rfddump.c
+rfddump_LDADD = libmtd.a
+
+rfdformat_SOURCES = nor-utils/rfdformat.c
+rfdformat_LDADD = libmtd.a
+
+NOR_BINS = \
+	rfddump rfdformat
+
+sbin_PROGRAMS += $(NOR_BINS)

+ 335 - 0
EVSE/GPL/mtd-utils-2.1.2/nor-utils/rfddump.c

@@ -0,0 +1,335 @@
+/*
+ * rfddump.c
+ *
+ * Copyright (C) 2005 Sean Young <sean@mess.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#define PROGRAM_NAME "rfddump"
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+#include <mtd_swab.h>
+
+#include "common.h"
+
+/* next is an array of mapping for each corresponding sector */
+#define RFD_MAGIC		0x9193
+#define HEADER_MAP_OFFSET       3
+#define SECTOR_DELETED          0x0000
+#define SECTOR_ZERO             0xfffe
+#define SECTOR_FREE             0xffff
+
+#define SECTOR_SIZE             512
+
+#define SECTORS_PER_TRACK	63
+
+
+struct rfd {
+	int block_size;
+	int block_count;
+	int header_sectors;
+	int data_sectors;
+	int header_size;
+	uint16_t *header;
+	int sector_count;
+	int *sector_map;
+	const char *mtd_filename;
+	const char *out_filename;
+	int verbose;
+};
+
+static void display_help(int status)
+{
+	printf("Usage: %s [OPTIONS] MTD-device filename\n"
+			"Dumps the contents of a resident flash disk\n"
+			"\n"
+			"-h         --help               display this help and exit\n"
+			"-V         --version            output version information and exit\n"
+			"-v         --verbose		Be verbose\n"
+			"-b size    --blocksize          Block size (defaults to erase unit)\n",
+			PROGRAM_NAME);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("This is free software; see the source for copying conditions.  There is NO\n"
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+	exit(0);
+}
+
+static void process_options(int argc, char *argv[], struct rfd *rfd)
+{
+	int error = 0;
+
+	rfd->block_size = 0;
+	rfd->verbose = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hvVb:";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "version", no_argument, 0, 'V', },
+			{ "blocksize", required_argument, 0, 'b' },
+			{ "verbose", no_argument, 0, 'v' },
+			{ NULL, 0, 0, 0 }
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case 'V':
+				display_version();
+				break;
+			case 'v':
+				rfd->verbose = 1;
+				break;
+			case 'b':
+				rfd->block_size = atoi(optarg);
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 2 || error)
+		display_help(EXIT_FAILURE);
+
+	rfd->mtd_filename = argv[optind];
+	rfd->out_filename = argv[optind + 1];
+}
+
+static int build_block_map(struct rfd *rfd, int fd, int block)
+{
+	int  i;
+	int sectors;
+
+	if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
+			!= rfd->header_size) {
+		return -1;
+	}
+
+	if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
+		if (rfd->verbose)
+			printf("Block #%02d: Magic missing\n", block);
+
+		return 0;
+	}
+
+	sectors =  0;
+	for (i=0; i<rfd->data_sectors; i++) {
+		uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
+
+		if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
+			continue;
+
+		if (entry == SECTOR_ZERO)
+			entry = 0;
+
+		if (entry >= rfd->sector_count) {
+			fprintf(stderr, "%s: warning: sector %d out of range\n",
+					rfd->mtd_filename, entry);
+			continue;
+		}
+
+		if (rfd->sector_map[entry] != -1) {
+			fprintf(stderr, "%s: warning: more than one entry "
+					"for sector %d\n", rfd->mtd_filename, entry);
+			continue;
+		}
+
+		rfd->sector_map[entry] = rfd->block_size * block +
+			(i + rfd->header_sectors) * SECTOR_SIZE;
+		sectors++;
+	}
+
+	if (rfd->verbose)
+		printf("Block #%02d: %d sectors\n", block, sectors);
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd, sectors_per_block;
+	mtd_info_t mtd_info;
+	struct rfd rfd;
+	int i, blocks_found;
+	int out_fd = 0;
+	uint8_t sector[512];
+	int blank, rc, cylinders;
+
+	process_options(argc, argv, &rfd);
+
+	fd = open(rfd.mtd_filename, O_RDONLY);
+	if (fd == -1) {
+		perror(rfd.mtd_filename);
+		return 1;
+	}
+
+	if (rfd.block_size == 0) {
+		if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+			perror(rfd.mtd_filename);
+			close(fd);
+			return 1;
+		}
+
+		if (mtd_info.type != MTD_NORFLASH) {
+			fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
+			close(fd);
+			return 2;
+		}
+
+		sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
+
+		rfd.block_size = mtd_info.erasesize;
+		rfd.block_count = mtd_info.size / mtd_info.erasesize;
+	} else {
+		struct stat st;
+
+		if (fstat(fd, &st) == -1) {
+			perror(rfd.mtd_filename);
+			close(fd);
+			return 1;
+		}
+
+		if (st.st_size % SECTOR_SIZE)
+			fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
+
+		sectors_per_block = rfd.block_size / SECTOR_SIZE;
+
+		if (st.st_size % rfd.block_size)
+			fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
+
+		rfd.block_count = st.st_size / rfd.block_size;
+
+		if (!rfd.block_count) {
+			fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
+			close(fd);
+			return 2;
+		}
+	}
+
+	rfd.header_sectors =
+		((HEADER_MAP_OFFSET + sectors_per_block) *
+		 sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+	rfd.data_sectors = sectors_per_block - rfd.header_sectors;
+	cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
+		/ SECTORS_PER_TRACK;
+	rfd.sector_count = cylinders * SECTORS_PER_TRACK;
+	rfd.header_size =
+		(HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
+
+	rfd.header = malloc(rfd.header_size);
+	if (!rfd.header) {
+		perror(PROGRAM_NAME);
+		close(fd);
+		return 2;
+	}
+	rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
+	if (!rfd.sector_map) {
+		perror(PROGRAM_NAME);
+		close(fd);
+		free(rfd.sector_map);
+		return 2;
+	}
+
+	rfd.mtd_filename = rfd.mtd_filename;
+
+	for (i=0; i<rfd.sector_count; i++)
+		rfd.sector_map[i] = -1;
+
+	for (blocks_found=i=0; i<rfd.block_count; i++) {
+		rc = build_block_map(&rfd, fd, i);
+		if (rc > 0)
+			blocks_found++;
+		if (rc < 0)
+			goto err;
+	}
+
+	if (!blocks_found) {
+		fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
+		goto err;
+	}
+
+	for (i=0; i<rfd.sector_count; i++) {
+		if (rfd.sector_map[i] != -1)
+			break;
+	}
+
+	if (i == rfd.sector_count) {
+		fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
+		goto err;
+	}
+
+	out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+	if (out_fd == -1) {
+		perror(rfd.out_filename);
+		goto err;
+	}
+
+	blank = 0;
+	for (i=0; i<rfd.sector_count; i++) {
+		if (rfd.sector_map[i] == -1) {
+			memset(sector, 0, SECTOR_SIZE);
+			blank++;
+		} else {
+			if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
+					!= SECTOR_SIZE) {
+				perror(rfd.mtd_filename);
+				goto err;
+			}
+		}
+
+		if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
+			perror(rfd.out_filename);
+			goto err;
+		}
+	}
+
+	if (rfd.verbose)
+		printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
+
+	close(out_fd);
+	close(fd);
+	free(rfd.header);
+	free(rfd.sector_map);
+
+	return 0;
+
+err:
+	if (out_fd > 0)
+		close(out_fd);
+
+	close(fd);
+	free(rfd.header);
+	free(rfd.sector_map);
+
+	return 2;
+}

+ 158 - 0
EVSE/GPL/mtd-utils-2.1.2/nor-utils/rfdformat.c

@@ -0,0 +1,158 @@
+/*
+ * rfdformat.c
+ *
+ * Copyright (C) 2005 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is very easy: just erase all the blocks and put the magic at
+ * the beginning of each block.
+ */
+
+#define PROGRAM_NAME "rfdformat"
+
+#define _XOPEN_SOURCE 500 /* For pread/pwrite */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+
+#include "common.h"
+
+static void display_help(int status)
+{
+	printf("Usage: %s [OPTIONS] MTD-device\n"
+			"Formats NOR flash for resident flash disk\n"
+			"\n"
+			"-h         --help               display this help and exit\n"
+			"-V         --version            output version information and exit\n",
+			PROGRAM_NAME);
+	exit(status);
+}
+
+static void display_version(void)
+{
+	common_print_version();
+	printf("This is free software; see the source for copying conditions.  There is NO\n"
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+	exit(0);
+}
+
+static void process_options(int argc, char *argv[], const char **mtd_filename)
+{
+	int error = 0;
+
+	for (;;) {
+		int option_index = 0;
+		static const char *short_options = "hV";
+		static const struct option long_options[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "version", no_argument, 0, 'V', },
+			{ NULL, 0, 0, 0 }
+		};
+
+		int c = getopt_long(argc, argv, short_options,
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+			case 'h':
+				display_help(EXIT_SUCCESS);
+				break;
+			case 'V':
+				display_version();
+				break;
+			case '?':
+				error = 1;
+				break;
+		}
+	}
+
+	if ((argc - optind) != 1 || error)
+		display_help(EXIT_FAILURE);
+
+	*mtd_filename = argv[optind];
+}
+
+int main(int argc, char *argv[])
+{
+	static const uint8_t magic[] = { 0x93, 0x91 };
+	int fd, block_count, i;
+	struct mtd_info_user mtd_info;
+	char buf[512];
+	const char *mtd_filename;
+
+	process_options(argc, argv, &mtd_filename);
+
+	fd = open(mtd_filename, O_RDWR);
+	if (fd == -1) {
+		perror(mtd_filename);
+		return 1;
+	}
+
+	if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+		perror(mtd_filename);
+		close(fd);
+		return 1;
+	}
+
+	if (mtd_info.type != MTD_NORFLASH) {
+		fprintf(stderr, "%s: not NOR flash\n", mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	if (mtd_info.size > 32*1024*1024) {
+		fprintf(stderr, "%s: flash larger than 32MiB not supported\n",
+				mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	block_count = mtd_info.size / mtd_info.erasesize;
+
+	if (block_count < 2) {
+		fprintf(stderr, "%s: at least two erase units required\n",
+				mtd_filename);
+		close(fd);
+		return 2;
+	}
+
+	for (i=0; i<block_count; i++) {
+		struct erase_info_user erase_info;
+
+		erase_info.start = i * mtd_info.erasesize;
+		erase_info.length = mtd_info.erasesize;
+
+		if (ioctl(fd, MEMERASE, &erase_info) != 0) {
+			snprintf(buf, sizeof(buf), "%s: erase", mtd_filename);
+			perror(buf);
+			close(fd);
+			return 2;
+		}
+
+		if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize)
+				!= sizeof(magic)) {
+			snprintf(buf, sizeof(buf), "%s: write", mtd_filename);
+			perror(buf);
+			close(fd);
+			return 2;
+		}
+	}
+
+	close(fd);
+
+	return 0;
+}

+ 4 - 0
EVSE/GPL/mtd-utils-2.1.2/release/sbin/flash_eraseall

@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "${0##*/} has been replaced by \`flash_erase <mtddev> 0 0\`; please use it" 1>&2
+[ $# -ne 0 ] && set -- "$@" 0 0
+exec flash_erase "$@"

+ 268 - 0
EVSE/GPL/mtd-utils-2.1.2/release/share/man/man1/mkfs.jffs2.1

@@ -0,0 +1,268 @@
+.TH MKFS.JFFS2 1
+.SH NAME
+mkfs.jffs2 \- Create a JFFS2 file system image from directory
+.SH SYNOPSIS
+.B mkfs.jffs2
+[
+.B -p,--pad[=SIZE]
+]
+[
+.B -r,-d,--root
+.I directory
+]
+[
+.B -s,--pagesize=SIZE
+]
+[
+.B -e,--eraseblock=SIZE
+]
+[
+.B -c,--cleanmarker=SIZE
+]
+[
+.B -n,--no-cleanmarkers
+]
+[
+.B -o,--output
+.I image.jffs2
+]
+[
+.B -l,--little-endian
+]
+[
+.B -b,--big-endian
+]
+[
+.B -D,--devtable=FILE
+]
+[
+.B -f,--faketime
+]
+[
+.B -q,--squash
+]
+[
+.B -U,--squash-uids
+]
+[
+.B -P,--squash-perms
+]
+[
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -y,--compressor-priority=PRIORITY:NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
+.B -h,--help
+]
+[
+.B -v,--verbose
+]
+[
+.B -V,--version
+]
+[
+.B -i,--incremental
+.I image.jffs2
+]
+
+.SH DESCRIPTION
+The program
+.B mkfs.jffs2
+creates a JFFS2 (Second Journalling Flash File System) file system
+image and writes the resulting image to the file specified by the
+.B -o
+option or by default to the standard output, unless the standard
+output is a terminal device in which case mkfs.jffs2 will abort.
+
+The file system image is created using the files and directories
+contained in the directory specified by the option
+.B -r
+or the present directory, if the
+.B -r
+option is not specified.
+
+Each block of the files to be placed into the file system image
+are compressed using one of the available compressors depending
+on the selected compression mode.
+
+File systems are created with the same endianness as the host,
+unless the
+.B -b
+or
+.B -l
+options are specified.  JFFS2 driver in the 2.4 Linux kernel only
+supported images having the same endianness as the CPU. As of 2.5.48,
+the kernel can be changed with a #define to accept images of the
+non-native endianness. Full bi-endian support in the kernel is not
+planned.
+
+It is unlikely that JFFS2 images are useful except in conjuction
+with the MTD (Memory Technology Device) drivers in the Linux
+kernel, since the JFFS2 file system driver in the kernel requires
+MTD devices.
+.SH OPTIONS
+Options that take SIZE arguments can be specified as either
+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000).
+.TP
+.B -p, --pad[=SIZE]
+Pad output to SIZE bytes with 0xFF.  If SIZE is not specified,
+the output is padded to the end of the final erase block.
+.TP
+.B -r, -d, --root=DIR
+Build file system from directory DIR.  The default is the current
+directory.
+.TP
+.B -s, --pagesize=SIZE
+Use page size SIZE.  The default is 4 KiB.  This size is the
+maximum size of a data node.  Set according to target system's memory
+management page size (NOTE: this is NOT related to NAND page size).
+.TP
+.B -e, --eraseblock=SIZE
+Use erase block size SIZE.  The default is 64 KiB.  If you use a erase
+block size different than the erase block size of the target MTD
+device, JFFS2 may not perform optimally. If the SIZE specified is
+below 4096, the units are assumed to be KiB.
+.TP
+.B -c, --cleanmarker=SIZE
+Write \'CLEANMARKER\' nodes with the size specified. It is not
+normally appropriate to specify a size other than the default 12
+bytes.
+.TP
+.B -n, --no-cleanmarkers
+Do not write \'CLEANMARKER\' nodes to the beginning of each erase
+block. This option can be useful for creating JFFS2 images for
+use on NAND flash, and for creating images which are to be used
+on a variety of hardware with differing eraseblock sizes.
+.TP
+.B -o, --output=FILE
+Write JFFS2 image to file FILE.  Default is the standard output.
+.TP
+.B -l, --little-endian
+Create a little-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -b, --big-endian
+Create a big-endian JFFS2 image.  Default is to make an image
+with the same endianness as the host.
+.TP
+.B -D, --devtable=FILE
+Use the named FILE as a device table file, for including devices and
+changing permissions in the created image when the user does not have
+appropriate permissions to create them on the file system used as
+source.
+.TP
+.B -f, --faketime
+Change all file timestamps to \'0\' for regression testing.
+.TP
+.B -q, --squash
+Squash permissions and owners, making all files be owned by root and
+removing write permission for \'group\' and \'other\'.
+.TP
+.B -U, --squash-uids
+Squash owners making all files be owned by root.
+.TP
+.B -P, --squash-perms
+Squash permissions, removing write permission for \'group\' and \'other\'.
+.TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
+.B -m, --compression-mode=MODE
+Set the default compression mode. The default mode is
+.B priority
+which tries the compressors in a predefinied order and chooses the first
+successful one. The alternatives are:
+.B none
+(mkfs will not compress) and
+.B size
+(mkfs will try all compressor and chooses the one which have the smallest result).
+.TP
+.B -x, --disable-compressor=NAME
+Disable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -X, --enable-compressor=NAME
+Enable a compressor. Use
+.B -L
+to see the list of the available compressors and their default states.
+.TP
+.B -y, --compressor-priority=PRIORITY:NAME
+Set the priority of a compressor. Use
+.B -L
+to see the list of the available compressors and their default priority.
+Priorities are used by priority compression mode.
+.TP
+.B -L, --list-compressors
+Show the list of the available compressors and their states.
+.TP
+.B -t, --test-compression
+Call decompress after every compress - and compare the result with the original data -, and
+some other check.
+.TP
+.B -h, --help
+Display help text.
+.TP
+.B -v, --verbose
+Verbose operation.
+.TP
+.B -V, --version
+Display version information.
+.TP
+.B -i, --incremental=FILE
+Generate an appendage image for FILE. If FILE is written to flash and flash
+is appended with the output, then it seems as if it was one thing.
+
+.SH LIMITATIONS
+The format and grammar of the device table file does not allow it to
+create symbolic links when the symbolic links are not already present
+in the root working directory.
+
+However, symbolic links may be specified in the device table file
+using the \fIl\fR type for the purposes of setting their permissions
+and ownership.
+.SH BUGS
+JFFS2 limits device major and minor numbers to 8 bits each.  Some
+consider this a bug.
+
+.B mkfs.jffs2
+does not properly handle hard links in the input directory structure.
+Currently, hard linked files will be expanded to multiple identical
+files in the output image.
+.SH AUTHORS
+David Woodhouse
+.br
+Manual page written by David Schleef <ds@schleef.org>
+.SH SEE ALSO
+.BR mkfs (8),
+.BR mkfs.jffs (1),
+.BR fakeroot (1)

+ 112 - 0
EVSE/GPL/mtd-utils-2.1.2/release/share/man/man8/lsmtd.8

@@ -0,0 +1,112 @@
+.TH LSMTD 8 "April 2017" "mtd-utils"
+.SH NAME
+lsmtd \- list memory technology devices
+.SH SYNOPSIS
+.B lsmtd
+[options]
+.RI [ device ...]
+.SH DESCRIPTION
+.B lsmtd
+lists information about all available or the specified MTD and UBI devices.
+The
+.B lsmtd
+command reads the
+.B sysfs
+filesystem to gather information. Alternatively, the
+.B procfs
+filesystem and ioctl interfaces are used, should the sysfs filesytem not
+be available.
+.PP
+The command prints all MTD and UBI devices in a pretty-printed list format by
+default.
+.PP
+The default output is subject to change. So whenever possible, you should
+avoid using default outputs in your scripts. Always explicitly define expected
+columns by using
+.B \-\-output
+.I columns-list
+in environments where a stable output is required.
+.PP
+Use
+.B "lsmtd --help"
+to get a list of all available columns.
+.SH OPTIONS
+.TP
+.BR \-b , " \-\-bytes"
+Print columns with size quantities (e.g. erase block size) in bytes instead
+of a human-readable format.
+.TP
+.BR \-h , " \-\-help"
+Display a help text and exit.
+.TP
+.BR \-i , " \-\-ascii"
+Only use ascii characters for pretty printing.
+.TP
+.BR \-J , " \-\-json"
+Use JSON output format. All potentially unsafe characters in string values are
+escaped with JSON escape sequences or hex-escaped (\\u<code>).
+.TP
+.BR \-l , " \-\-list"
+Use a pretty-printed list output format (default).
+.TP
+.BR \-m , " \-\-no-ubi"
+Do not display information about UBI devices or volumes.
+.TP
+.BR \-n , " \-\-noheadings"
+Do not print column headings when using raw or list output format.
+.TP
+.BR \-o , " \-\-output " \fIlist\fP
+Specify which output columns to print.  Use
+.B \-\-help
+to get a list of all supported columns.
+
+The default list of columns may be extended if \fIlist\fP is
+specified in the format \fI+list\fP (e.g. \fBlsmtd -o +EB-SIZE\fP).
+.TP
+.BR \-O , " \-\-output\-all "
+Output all available columns.
+.TP
+.BR \-P , " \-\-pairs"
+Produce output in the form of key="value" pairs.
+All potentially unsafe characters are hex-escaped (\\x<code>).
+.TP
+.BR \-r , " \-\-raw"
+Produce output in raw format. All potentially unsafe characters are
+hex-escaped (\\x<code>).
+.TP
+.BR \-u , " \-\-si\-units"
+Display human readable sizes as powers of ten rather than powers of two.
+.TP
+.BR \-V , " \-\-version"
+Print version information and exit.
+.TP
+.BR \-x , " \-\-sort " \fIcolumn\fP
+Sort output lines by \fIcolumn\fP.
+.SH NOTES
+If the
+.B \-\-bytes
+option is not specified, the JSON output format prints sizes as string values
+even if they do not have a suffix.
+.SH AUTHORS
+.nf
+David Oberhollenzer <david.oberhollenzer@sigma-star.at>
+.fi
+.SH REPORTING BUGS
+Report mtd-utils bugs to the Linux mtd mailing list.
+.TP
+Linux mtd mailing list: <linux-mtd@lists.infradead.org>
+.TP
+Linux mtd home page: <http://www.linux-mtd.infradead.org/>
+.SH AVAILABILITY
+The lsmtd command is part of the mtd-utils package and is available from
+ftp://ftp.infradead.org/pub/mtd-utils/.
+.SH COPYRIGHT
+Copyright \(co 2017 David Oberhollenzer - sigma star gmbh
+.br
+License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.
+.br
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+.SH SEE ALSO
+.BR lsblk (8),
+.BR ls (1)

+ 136 - 0
EVSE/GPL/mtd-utils-2.1.2/release/share/man/man8/ubinize.8

@@ -0,0 +1,136 @@
+.TH UBINIZE 8 "September 2016" "mtd-utils"
+.SH NAME
+ubinize \- a tool for generating UBI images
+.SH SYNOPSIS
+.B ubinize
+[-o filename] [-p <bytes>] [-m <bytes>] [-s <bytes>] [-O <num>] [-e <num>]
+[-x <num>] [-Q <num>] [-v] [-h] [-V] [--output=<filename>] [--peb-size=<bytes>]
+[--min-io-size=<bytes>] [--sub-page-size=<bytes>] [--vid-hdr-offset=<num>]
+[--erase-counter=<num>] [--ubi-ver=<num>] [--image-seq=<num>] [--verbose]
+[--help] [--version] ini-file
+.SH DESCRIPTION
+An UBI image may contain one or more UBI volumes which have to be defined in
+the input configuration ini-file. The ini file defines all the UBI volumes \-
+their characteristics and the contents, but it does not define the
+characteristics of the flash the UBI image is generated for. Instead, the
+flash characteristics are defined via the command-line options. Note, if not
+sure about some of the command-line parameters, do not specify them and let
+the utility use default values.
+.SH OPTIONS
+.TP
+.BR \-o , " \-\-output=\fIfile\fP"
+Specify output file
+.TP
+.BR \-p , " \-\-peb\-size=\fIbytes\fP"
+Size of the physical eraseblock of the flash this UBI image is created for
+in bytes, kilobytes (KiB), or megabytes (MiB). This parameter is mandatory.
+.TP
+.BR \-m , " \-\-min\-io-size=\fIbytes\fP"
+Minimum input/output unit size of the flash in bytes
+.TP
+.BR \-s , " \-\-sub\-page\-size=\fIbytes\fP"
+Minimum input/output unit used for UBI headers, e.g. sub-page size in case
+of NAND flash (equivalent to the minimum input/output unit size by default).
+.TP
+.BR \-O , " \-\-vid\-hdr\-offset=\fInum\fP"
+Offset if the VID header from start of the physical eraseblock (default is the
+next minimum I/O unit or sub-page after the EC header)
+.TP
+.BR \-e , " \-\-erase\-counter=\fInum\fP"
+The erase counter value to put to EC headers (default is 0).
+.TP
+.BR \-x , " \-\-ubi\-ver=\fInum\fP"
+UBI version number to put to EC headers (default is 1).
+.TP
+.BR \-Q , " \-\-image\-seq=\fInum\fP"
+32-bit UBI image sequence number to use (by default a random number is picked).
+.TP
+.BR \-v , " \-\-verbose"
+Be verbose.
+.TP
+.BR \-h , " \-\-help"
+Print a help message and exit.
+.TP
+.BR \-V , " \-\-version"
+Print program version and exit.
+.SH EXAMPLE
+ubinize -o ubi.img -p 16KiB -m 512 -s 256 cfg.ini
+
+Create UBI image \fIubi.img\fP as described by configuration file
+\fIcfg.ini\fP.
+
+A physical erase block on the flash is \fI16KiB\fP in size and has \fI512\fP
+byte pages with \fI256\fP byte sub-pages.
+.SH INI-FILE FORMAT
+The input configuration ini-file describes all the volumes which have to
+be included to the output UBI image. Each volume is described in its own
+section which may be named arbitrarily. The section consists on
+"key=value" pairs, for example:
+.PP
+.in +4n
+.nf
+[jffs2\-volume]
+mode=ubi
+image=../jffs2.img
+vol_id=1
+vol_size=30MiB
+vol_type=dynamic
+vol_name=jffs2_volume
+vol_flags=autoresize
+vol_alignment=1
+.fi
+.in
+
+This example configuration file tells the utility to create an UBI image
+with one volume with ID 1, volume size 30MiB, the volume is dynamic, has
+name \fIjffs2_volume\fP, \fIautoresize\fP volume flag, and alignment 1.
+
+The \fBimage=../jffs2.img\fP line tells the utility to take the contents of
+the volume from the \fB../jffs2.img\fP file. The size of the image file has
+to be less or equivalent to the volume size (30MiB).
+
+The \fBmode=ubi\fP line is mandatory and just tells that the section describes
+an UBI volume \- other section modes may be added in the future.
+
+Notes:
+.IP \[bu] 4
+Size in vol_size might be specified kilobytes (KiB), megabytes (MiB),
+gigabytes (GiB) or bytes (no modifier).
+.IP \[bu]
+If "vol_size" key is absent, the volume size is assumed to be
+equivalent to the size of the image file (defined by "image" key).
+.IP \[bu]
+If the "image" is absent, the volume is assumed to be empty
+.IP \[bu]
+Volume alignment must not be greater than the logical eraseblock size.
+.IP \[bu]
+One ini file may contain arbitrary number of sections, the utility will
+put all the volumes which are described by these section to the output
+UBI image file.
+.SH AUTHORS
+.nf
+Man page written by David Oberhollenzer, based on the help text of
+the ubinize utility written by Artem Bityutskiy and Oliver Lohmann.
+.fi
+.SH REPORTING BUGS
+Report mtd-utils bugs to the Linux mtd mailing list.
+.TP
+Linux mtd mailing list: <linux-mtd@lists.infradead.org>
+.TP
+Linux mtd home page: <http://www.linux-mtd.infradead.org/>
+.SH AVAILABILITY
+The ubinize command is part of the mtd-utils package and is available from
+ftp://ftp.infradead.org/pub/mtd-utils/.
+.SH COPYRIGHT
+Copyright \(co International Business Machines Corp., 2006
+.br
+Copyright \(co 2008 Nokia Corporation
+.br
+Copyright \(co 2016 sigma star gmbh
+
+License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.
+.br
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+.SH SEE ALSO
+.BR mkfs.jffs2 (1)

+ 86 - 0
EVSE/GPL/mtd-utils-2.1.2/tests/fs-tests/Makemodule.am

@@ -0,0 +1,86 @@
+integck_SOURCES = tests/fs-tests/integrity/integck.c
+integck_LDADD = libubi.a libmissing.a
+integck_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/ubi-utils/include
+
+test_1_SOURCES = tests/fs-tests/simple/test_1.c tests/fs-tests/lib/tests.c
+test_1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+test_2_SOURCES = tests/fs-tests/simple/test_2.c tests/fs-tests/lib/tests.c
+test_2_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+ftrunc_SOURCES = tests/fs-tests/simple/ftrunc.c tests/fs-tests/lib/tests.c
+ftrunc_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+perf_SOURCES = tests/fs-tests/simple/perf.c tests/fs-tests/lib/tests.c
+perf_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+orph_SOURCES = tests/fs-tests/simple/orph.c tests/fs-tests/lib/tests.c
+orph_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+stress_1_SOURCES = tests/fs-tests/stress/atoms/stress_1.c
+stress_1_SOURCES += tests/fs-tests/lib/tests.c
+stress_1_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+stress_2_SOURCES = tests/fs-tests/stress/atoms/stress_2.c
+stress_2_SOURCES += tests/fs-tests/lib/tests.c
+stress_2_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+stress_3_SOURCES = tests/fs-tests/stress/atoms/stress_3.c
+stress_3_SOURCES += tests/fs-tests/lib/tests.c
+stress_3_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+pdfrun_SOURCES = tests/fs-tests/stress/atoms/pdfrun.c
+pdfrun_SOURCES += tests/fs-tests/lib/tests.c
+pdfrun_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+rndwrite00_SOURCES = tests/fs-tests/stress/atoms/rndwrite00.c
+rndwrite00_SOURCES += tests/fs-tests/lib/tests.c
+rndwrite00_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+fwrite00_SOURCES = tests/fs-tests/stress/atoms/fwrite00.c
+fwrite00_SOURCES += tests/fs-tests/lib/tests.c
+fwrite00_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+rmdir00_SOURCES = tests/fs-tests/stress/atoms/rmdir00.c
+rmdir00_SOURCES += tests/fs-tests/lib/tests.c
+rmdir00_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+rndrm00_SOURCES = tests/fs-tests/stress/atoms/rndrm00.c
+rndrm00_SOURCES += tests/fs-tests/lib/tests.c
+rndrm00_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+rndrm99_SOURCES = tests/fs-tests/stress/atoms/rndrm99.c
+rndrm99_SOURCES += tests/fs-tests/lib/tests.c
+rndrm99_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+gcd_hupper_SOURCES = tests/fs-tests/stress/atoms/gcd_hupper.c
+gcd_hupper_SOURCES += tests/fs-tests/lib/tests.c
+gcd_hupper_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/tests/fs-tests/lib
+
+fstest_monitor_SOURCES = tests/fs-tests/utils/fstest_monitor.c
+
+free_space_SOURCES = tests/fs-tests/utils/free_space.c
+
+FSTEST_BINS = \
+	integck test_1 test_2 ftrunc perf orph \
+	stress_1 stress_2 stress_3 pdfrun gcd_hupper \
+	rndwrite00 fwrite00 rmdir00 rndrm00 rndrm99 \
+	fstest_monitor free_space
+
+FSTEST_SH = \
+	tests/fs-tests/fs_help_all.sh tests/fs-tests/fs_run_all.sh \
+	tests/fs-tests/stress/fs_stress00.sh \
+	tests/fs-tests/stress/fs_stress01.sh
+
+FSTEST_HEADER = \
+	tests/fs-tests/lib/tests.h
+
+EXTRA_DIST += $(FSTEST_HEADER)
+
+if INSTALL_TESTS
+pkglibexec_SCRIPTS += $(FSTEST_SH)
+pkglibexec_PROGRAMS += $(FSTEST_BINS)
+else
+noinst_SCRIPTS += $(FSTEST_SH)
+noinst_PROGRAMS += $(FSTEST_BINS)
+endif

Some files were not shown because too many files changed in this diff