summaryrefslogtreecommitdiff
path: root/package/nand
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2010-02-07 20:12:57 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2010-02-07 20:12:57 +0100
commit2bbfadac526c7880720e518e0fdd84ac0ca601bd (patch)
tree5d7ca7982b47e2fe7ea4ef6ed5f461f3ffce83d7 /package/nand
parent6daa792eab1488d013fefc5eb7e4d01f40f38687 (diff)
parent2e44499238125dbecbbf17222496ebba315cc90c (diff)
resolve conflicts
Diffstat (limited to 'package/nand')
-rw-r--r--package/nand/Makefile12
-rw-r--r--package/nand/src/nand.c581
-rw-r--r--package/nand/src/nanddump.c421
-rw-r--r--package/nand/src/nandwrite.c647
4 files changed, 585 insertions, 1076 deletions
diff --git a/package/nand/Makefile b/package/nand/Makefile
index 0f24fab25..1e54d3387 100644
--- a/package/nand/Makefile
+++ b/package/nand/Makefile
@@ -5,7 +5,7 @@ include ${TOPDIR}/rules.mk
PKG_NAME:= nand
PKG_VERSION:= 1.0
-PKG_RELEASE:= 1
+PKG_RELEASE:= 3
PKG_DESCR:= NAND utility
PKG_SECTION:= base
@@ -25,15 +25,11 @@ INSTALL_STYLE:= manual
do-build:
mkdir -p ${WRKBUILD}
- ${CP} ./src/* ${WRKBUILD}
- ${TARGET_CC} ${TCPPFLAGS} ${TCFLAGS} -o ${WRKBUILD}/nandwrite \
- ${WRKBUILD}/nandwrite.c
- ${TARGET_CC} ${TCPPFLAGS} ${TCFLAGS} -o ${WRKBUILD}/nanddump \
- ${WRKBUILD}/nanddump.c
+ ${TARGET_CC} -Wall ${TCPPFLAGS} ${TCFLAGS} -o ${WRKBUILD}/nand \
+ ./src/nand.c
do-install:
${INSTALL_DIR} ${IDIR_NAND}/sbin
- ${INSTALL_BIN} ${WRKBUILD}/nandwrite ${IDIR_NAND}/sbin
- ${INSTALL_BIN} ${WRKBUILD}/nanddump ${IDIR_NAND}/sbin
+ ${INSTALL_BIN} ${WRKBUILD}/nand ${IDIR_NAND}/sbin
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/nand/src/nand.c b/package/nand/src/nand.c
new file mode 100644
index 000000000..0d5d7f0e4
--- /dev/null
+++ b/package/nand/src/nand.c
@@ -0,0 +1,581 @@
+/*
+ * nand - simple nand memory technology device manipulation tool
+ *
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.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.
+ *
+ * The code is based on the mtd-utils nandwrite and flash_erase_all.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <error.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.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/mount.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <getopt.h>
+
+#include "mtd/mtd-user.h"
+#include <linux/reboot.h>
+
+int nand_open(const char *, int);
+int nand_erase(const char *);
+int nand_info(const char *);
+int nand_write(const char*, const char *, int);
+void usage(void) __attribute__((noreturn));
+
+#define MAX_PAGE_SIZE 4096
+#define MAX_OOB_SIZE 128
+
+static unsigned char writebuf[MAX_PAGE_SIZE];
+static unsigned char oobbuf[MAX_OOB_SIZE];
+static unsigned char oobreadbuf[MAX_OOB_SIZE];
+
+static struct nand_oobinfo autoplace_oobinfo = {
+ .useecc = MTD_NANDECC_AUTOPLACE
+};
+
+static void erase_buffer(void *buffer, size_t size)
+{
+ const uint8_t kEraseByte = 0xff;
+
+ if (buffer != NULL && size > 0) {
+ memset(buffer, kEraseByte, size);
+ }
+}
+
+int nand_open(const char *nand, int flags) {
+
+ FILE *fp;
+ char dev[PATH_MAX];
+ int i;
+
+ if ((fp = fopen("/proc/mtd", "r"))) {
+ while (fgets(dev, sizeof(dev), fp)) {
+ if (sscanf(dev, "mtd%d:", &i) && strstr(dev, nand)) {
+ snprintf(dev, sizeof(dev), "/dev/mtd%d", i);
+ fclose(fp);
+ return open(dev, flags);
+ }
+ }
+ fclose(fp);
+ }
+
+ return open(nand, flags);
+}
+
+int nand_info(const char *nand) {
+
+ int fd, ret;
+ mtd_info_t nandinfo;
+ struct nand_oobinfo oobinfo;
+ loff_t offset;
+
+ if ((fd = nand_open(nand, O_RDONLY)) < 0) {
+ fprintf(stderr, "nand: unable to open MTD device %s\n", nand);
+ return 1;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &nandinfo) != 0) {
+ fprintf(stderr, "nand: unable to get MTD device info from %s\n", nand);
+ return 1;
+ }
+
+ if (nandinfo.type == MTD_NANDFLASH) {
+ fprintf(stdout, "MTD devise is NAND\n");
+ } else {
+ fprintf(stdout, "MTD devise is NOT NAND\n");
+ return 1;
+ }
+
+ fprintf(stdout, "NAND block/erase size is: %u\n", nandinfo.erasesize);
+ fprintf(stdout, "NAND page size is: %u\n", nandinfo.writesize);
+ fprintf(stdout, "NAND OOB size is: %u\n", nandinfo.oobsize);
+ fprintf(stdout, "NAND partition size is: %u\n", nandinfo.size);
+
+ for (offset = 0; offset < nandinfo.size; offset += nandinfo.erasesize) {
+ ret = ioctl(fd, MEMGETBADBLOCK, &offset);
+ if (ret > 0) {
+ printf("\nSkipping bad block at %llu\n", offset);
+ continue;
+ } else if (ret < 0) {
+ if (errno == EOPNOTSUPP) {
+ fprintf(stderr, "Bad block check not available\n");
+ return 1;
+ }
+ }
+ }
+
+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) {
+ fprintf(stderr, "Unable to get NAND oobinfo\n");
+ return 1;
+ }
+
+ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+ fprintf(stdout, "NAND device/driver supports autoplacement of OOB\n");
+ }
+
+ return 0;
+}
+
+int nand_erase(const char *nand) {
+
+ mtd_info_t meminfo;
+ struct nand_oobinfo oobinfo;
+ int fd, clmpos, clmlen;
+ erase_info_t erase;
+
+ clmpos = 0;
+ clmlen = 8;
+
+ erase_buffer(oobbuf, sizeof(oobbuf));
+
+ if ((fd = nand_open(nand, O_RDWR)) < 0) {
+ fprintf(stderr, "nand: %s: unable to open MTD device\n", nand);
+ return 1;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ fprintf(stderr, "nand: %s: unable to get MTD device info\n", nand);
+ return 1;
+ }
+
+ erase.length = meminfo.erasesize;
+
+ for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) {
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ fprintf(stderr, "\nnand: %s: MTD Erase failure: %s\n", nand, strerror(errno));
+ continue;
+ }
+
+ struct mtd_oob_buf oob;
+
+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) {
+ fprintf(stderr, "Unable to get NAND oobinfo\n");
+ return 1;
+ }
+
+ if (oobinfo.useecc != MTD_NANDECC_AUTOPLACE) {
+ fprintf(stderr, "NAND device/driver does not support autoplacement of OOB\n");
+ return 1;
+ }
+
+ if (!oobinfo.oobfree[0][1]) {
+ fprintf(stderr, "Autoplacement selected and no empty space in oob\n");
+ return 1;
+ }
+ clmpos = oobinfo.oobfree[0][0];
+ clmlen = oobinfo.oobfree[0][1];
+ if (clmlen > 8)
+ clmlen = 8;
+
+ //fprintf(stdout, "Using clmlen: %d clmpos: %d\n", clmlen, clmpos);
+
+ oob.ptr = oobbuf;
+ oob.start = erase.start + clmpos;
+ oob.length = clmlen;
+ if (ioctl (fd, MEMWRITEOOB, &oob) != 0) {
+ fprintf(stderr, "\nnand: %s: MTD writeoob failure: %s\n", nand, strerror(errno));
+ continue;
+ }
+ }
+ return 0;
+}
+
+int nand_write(const char *img, const char *nand, int quiet) {
+
+ static bool pad = true;
+ static const char *standard_input = "-";
+ static bool autoplace = true;
+ static bool markbad = true;
+ static int mtdoffset = 0;
+ int cnt = 0;
+ int fd = -1;
+ int ifd = -1;
+ int imglen = 0, pagelen;
+ bool baderaseblock = false;
+ int blockstart = -1;
+ struct mtd_info_user meminfo;
+ struct mtd_oob_buf oob;
+ loff_t offs;
+ int ret, readlen;
+ int oobinfochanged = 0;
+ struct nand_oobinfo old_oobinfo;
+
+ erase_buffer(oobbuf, sizeof(oobbuf));
+
+ /* Open the device */
+ if ((fd = nand_open(nand, O_RDWR | O_SYNC)) == -1) {
+ perror(nand);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit (EXIT_FAILURE);
+ }
+
+ if (autoplace) {
+ /* Read the current oob info */
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (EXIT_FAILURE);
+ }
+
+ // autoplace ECC ?
+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
+
+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (EXIT_FAILURE);
+ }
+ oobinfochanged = 1;
+ }
+ }
+
+ oob.length = meminfo.oobsize;
+ oob.ptr = oobbuf;
+
+ /* 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 restoreoob;
+ }
+
+ pagelen = meminfo.writesize;
+
+ /*
+ * For the standard input case, the input size is merely an
+ * invariant placeholder and is set to the write page
+ * size. Otherwise, just use the input file size.
+ */
+
+ if (ifd == STDIN_FILENO) {
+ imglen = pagelen;
+ } else {
+ imglen = lseek(ifd, 0, SEEK_END);
+ lseek (ifd, 0, SEEK_SET);
+ }
+
+ // 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;
+ }
+
+ // Check, if length fits into device
+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %u bytes\n",
+ imglen, pagelen, meminfo.writesize, meminfo.size);
+ perror ("Input file does not fit into device");
+ goto closeall;
+ }
+
+ /*
+ * 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 && (mtdoffset < meminfo.size)) {
+ // new eraseblock , check for bad block(s)
+ // Stay in the loop to be sure if the mtdoffset changes because
+ // of a bad block, that the next block that will be written to
+ // is also checked. Thus avoiding errors if the block(s) after the
+ // skipped block(s) is also bad
+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
+ blockstart = mtdoffset & (~meminfo.erasesize + 1);
+ offs = blockstart;
+ baderaseblock = false;
+ if (quiet < 2)
+ fprintf (stdout, "Writing data to block %d at offset 0x%x\n",
+ blockstart / meminfo.erasesize, blockstart);
+
+ /* Check all the blocks in an erase block for bad blocks */
+ do {
+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+ if (ret == 1) {
+ baderaseblock = true;
+ if (!quiet)
+ fprintf (stderr, "Bad block at %x "
+ "from %x will be skipped\n",
+ (int) offs, blockstart);
+ }
+
+ if (baderaseblock) {
+ mtdoffset = blockstart + meminfo.erasesize;
+ }
+ offs += meminfo.erasesize;
+ } while ( offs < blockstart + meminfo.erasesize );
+
+ }
+
+ readlen = meminfo.writesize;
+
+ if (ifd != STDIN_FILENO) {
+ int tinycnt = 0;
+
+ if (pad && (imglen < readlen))
+ {
+ readlen = imglen;
+ erase_buffer(writebuf + readlen, meminfo.writesize - readlen);
+ }
+
+ /* Read Page Data from input file */
+ 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 file");
+ goto closeall;
+ }
+ tinycnt += cnt;
+ }
+ } else {
+ int tinycnt = 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 stdin");
+ goto closeall;
+ }
+ tinycnt += cnt;
+ }
+
+ /* No padding needed - we are done */
+ if (tinycnt == 0) {
+ imglen = 0;
+ break;
+ }
+
+ /* No more bytes - we are done after writing the remaining bytes */
+ if (cnt == 0) {
+ imglen = 0;
+ }
+
+ /* Padding */
+ if (pad && (tinycnt < readlen)) {
+ erase_buffer(writebuf + tinycnt, meminfo.writesize - tinycnt);
+ }
+ }
+
+ /* Write out the Page data */
+ if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
+ int rewind_blocks;
+ off_t rewind_bytes;
+ erase_info_t erase;
+
+ perror ("pwrite");
+ /* Must rewind to blockstart if we can */
+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
+ perror("lseek");
+ fprintf(stderr, "Failed to seek backwards to recover from write error\n");
+ goto closeall;
+ }
+ erase.start = blockstart;
+ erase.length = meminfo.erasesize;
+ fprintf(stderr, "Erasing failed write from %08lx-%08lx\n",
+ (long)erase.start, (long)erase.start+erase.length-1);
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ perror("MEMERASE");
+ goto closeall;
+ }
+
+ if (markbad) {
+ loff_t bad_addr = mtdoffset & (~(meminfo.erasesize) + 1);
+ fprintf(stderr, "Marking block at %08lx bad\n", (long)bad_addr);
+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
+ perror("MEMSETBADBLOCK");
+ /* But continue anyway */
+ }
+ }
+ mtdoffset = blockstart + meminfo.erasesize;
+ imglen += rewind_blocks * meminfo.writesize;
+
+ continue;
+ }
+ if (ifd != STDIN_FILENO) {
+ imglen -= readlen;
+ }
+ mtdoffset += meminfo.writesize;
+ }
+
+closeall:
+ close(ifd);
+
+restoreoob:
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ close(fd);
+
+ if ((ifd != STDIN_FILENO) && (imglen > 0)) {
+ perror ("Data was only partially written due to error\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Return happy */
+ return EXIT_SUCCESS;
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: nand [<options> ...] <command> [<arguments> ...] <device>\n\n"
+ "The device is in the format of mtdX (eg: mtd4) or its label.\n"
+ "nand recognises these commands:\n"
+ " erase erase all data on device\n"
+ " info print information about device\n"
+ " write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
+ "Following options are available:\n"
+ " -q quiet mode\n"
+ " -r reboot after successful command\n"
+ "Example: To write linux.img to mtd partition labeled as linux\n"
+ " mtd write linux.img linux\n\n");
+ exit(1);
+}
+
+int main(int argc, char **argv) {
+
+ int ch, quiet, boot;
+ char *device;
+ enum {
+ CMD_INFO,
+ CMD_ERASE,
+ CMD_WRITE,
+ } cmd;
+
+ boot = 0;
+ quiet = 0;
+
+ while ((ch = getopt(argc, argv, "Fqr:")) != -1)
+ switch (ch) {
+ case 'F':
+ quiet = 1;
+ /* FALLTHROUGH */
+ case 'q':
+ quiet++;
+ break;
+ case 'r':
+ boot = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
+ cmd = CMD_ERASE;
+ device = argv[1];
+ } else if ((strcmp(argv[0], "info") == 0) && (argc == 2)) {
+ cmd = CMD_INFO;
+ device = argv[1];
+ } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
+ cmd = CMD_WRITE;
+ device = argv[2];
+ } else {
+ usage();
+ }
+
+ sync();
+
+ switch (cmd) {
+ case CMD_INFO:
+ if (quiet < 2)
+ fprintf(stderr, "Info about %s ...\n", device);
+ nand_info(device);
+ break;
+ case CMD_ERASE:
+ if (quiet < 2)
+ fprintf(stderr, "Erasing %s ...\n", device);
+ nand_erase(device);
+ break;
+ case CMD_WRITE:
+ if (quiet < 2)
+ fprintf(stderr, "Writing from %s to %s ... ", argv[1], device);
+ nand_erase(device);
+ nand_write(argv[1], device, quiet);
+ if (quiet < 2)
+ fprintf(stderr, "\n");
+ break;
+ }
+
+ sync();
+
+ if (boot) {
+ fprintf(stderr, "\nRebooting ... ");
+ fflush(stdout);
+ fflush(stderr);
+ syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
+ }
+
+ return 0;
+}
diff --git a/package/nand/src/nanddump.c b/package/nand/src/nanddump.c
deleted file mode 100644
index 678d6847a..000000000
--- a/package/nand/src/nanddump.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * 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 _GNU_SOURCE
-#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>
-
-#define PROGRAM "nanddump"
-#define VERSION "$Revision: 1.29 $"
-
-static struct nand_oobinfo none_oobinfo = {
- .useecc = MTD_NANDECC_OFF,
-};
-
-static void display_help (void)
-{
- printf(
-"Usage: nanddump [OPTIONS] MTD-device\n"
-"Dumps the contents of a nand mtd partition.\n"
-"\n"
-" --help Display this help and exit\n"
-" --version Output version information and exit\n"
-"-f file --file=file Dump to file\n"
-"-i --ignoreerrors Ignore errors\n"
-"-l length --length=length Length\n"
-"-n --noecc Read without error correction\n"
-"-o --omitoob Omit oob data\n"
-"-b --omitbad Omit bad blocks from the dump\n"
-"-p --prettyprint Print nice (hexdump)\n"
-"-q --quiet Don't display progress and status messages\n"
-"-s addr --startaddress=addr Start address\n"
- );
- exit(EXIT_SUCCESS);
-}
-
-static void display_version (void)
-{
- printf(PROGRAM " " VERSION "\n"
- "\n"
- PROGRAM " comes with NO WARRANTY\n"
- "to the extent permitted by law.\n"
- "\n"
- "You may redistribute copies of " PROGRAM "\n"
- "under the terms of the GNU General Public Licence.\n"
- "See the file `COPYING' for more information.\n");
- exit(EXIT_SUCCESS);
-}
-
-// Option variables
-
-static bool ignoreerrors = false; // ignore errors
-static bool pretty_print = false; // print nice in ascii
-static bool noecc = false; // don't error correct
-static bool omitoob = false; // omit oob data
-static unsigned long start_addr; // start address
-static unsigned long length; // dump length
-static const char *mtddev; // mtd device name
-static const char *dumpfile; // dump file name
-static bool omitbad = false;
-static bool quiet = false; // suppress diagnostic output
-
-static void process_options (int argc, char * const argv[])
-{
- int error = 0;
-
- for (;;) {
- int option_index = 0;
- static const char *short_options = "bs:f:il:opqn";
- static const struct option long_options[] = {
- {"help", no_argument, 0, 0},
- {"version", no_argument, 0, 0},
- {"file", required_argument, 0, 'f'},
- {"ignoreerrors", no_argument, 0, 'i'},
- {"prettyprint", no_argument, 0, 'p'},
- {"omitoob", no_argument, 0, 'o'},
- {"omitbad", no_argument, 0, 'b'},
- {"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 0:
- display_help();
- break;
- case 1:
- display_version();
- break;
- }
- break;
- case 'b':
- omitbad = true;
- break;
- case 's':
- start_addr = strtol(optarg, NULL, 0);
- break;
- case 'f':
- if (!(dumpfile = strdup(optarg))) {
- perror("stddup");
- exit(EXIT_FAILURE);
- }
- break;
- case 'i':
- ignoreerrors = true;
- break;
- case 'l':
- length = strtol(optarg, NULL, 0);
- break;
- case 'o':
- omitoob = true;
- break;
- case 'p':
- pretty_print = true;
- break;
- case 'q':
- quiet = true;
- break;
- case 'n':
- noecc = true;
- break;
- case '?':
- error++;
- break;
- }
- }
-
- 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 ((argc - optind) != 1 || error)
- display_help ();
-
- mtddev = argv[optind];
-}
-
-/*
- * Buffers for reading data from flash
- */
-static unsigned char readbuf[4096];
-static unsigned char oobbuf[128];
-
-/*
- * Main program
- */
-int main(int argc, char * const argv[])
-{
- unsigned long ofs, end_addr = 0;
- unsigned long long blockstart = 1;
- int ret, i, fd, ofd, bs, badblock = 0;
- struct mtd_oob_buf oob = {0, 16, oobbuf};
- mtd_info_t meminfo;
- char pretty_buf[80];
- int oobinfochanged = 0 ;
- struct nand_oobinfo old_oobinfo;
- struct mtd_ecc_stats stat1, stat2;
- bool eccstats = false;
-
- process_options(argc, argv);
-
- /* Open MTD device */
- if ((fd = open(mtddev, O_RDONLY)) == -1) {
- perror(mtddev);
- exit (EXIT_FAILURE);
- }
-
- /* Fill in MTD device capability structure */
- if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
- perror("MEMGETINFO");
- close(fd);
- exit (EXIT_FAILURE);
- }
-
- /* Make sure device page sizes are valid */
- if (!(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
- !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
- !(meminfo.oobsize == 32 && meminfo.writesize == 1024) &&
- !(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
- !(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
- fprintf(stderr, "Unknown flash (not normal NAND)\n");
- close(fd);
- exit(EXIT_FAILURE);
- }
- /* Read the real oob length */
- oob.length = meminfo.oobsize;
-
- if (noecc) {
- ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
- if (ret == 0) {
- oobinfochanged = 2;
- } else {
- switch (errno) {
- case ENOTTY:
- if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMGETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- oobinfochanged = 1;
- break;
- default:
- perror ("MTDFILEMODE");
- close (fd);
- exit (EXIT_FAILURE);
- }
- }
- } 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);
- close(fd);
- exit(EXIT_FAILURE);
- }
-
- /* Initialize start/end addresses and block size */
- if (length)
- end_addr = start_addr + length;
- if (!length || end_addr > meminfo.size)
- end_addr = meminfo.size;
-
- bs = meminfo.writesize;
-
- /* Print informative message */
-
- if (!quiet) {
- fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
- meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
- fprintf(stderr,
- "Dumping data starting at 0x%08x and ending at 0x%08x...\n",
- (unsigned int) start_addr, (unsigned int) end_addr);
- }
- /* Dump the flash contents */
- for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
-
- // new eraseblock , check for bad block
- if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
- blockstart = ofs & (~meminfo.erasesize + 1);
- if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
- perror("ioctl(MEMGETBADBLOCK)");
- goto closeall;
- }
- }
-
- if (badblock) {
- if (omitbad)
- continue;
- memset (readbuf, 0xff, bs);
- } else {
- /* Read page data and exit on failure */
- if (pread(fd, readbuf, bs, ofs) != bs) {
- perror("pread");
- 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%08lx\n",
- stat2.failed - stat1.failed, ofs);
- if (stat1.corrected != stat2.corrected)
- fprintf(stderr, "ECC: %d corrected bitflip(s) at"
- " offset 0x%08lx\n",
- stat2.corrected - stat1.corrected, ofs);
- stat1 = stat2;
- }
-
- /* Write out page data */
- if (pretty_print) {
- for (i = 0; i < bs; i += 16) {
- sprintf(pretty_buf,
- "0x%08x: %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- (unsigned int) (ofs + i), readbuf[i],
- readbuf[i+1], readbuf[i+2],
- readbuf[i+3], readbuf[i+4],
- readbuf[i+5], readbuf[i+6],
- readbuf[i+7], readbuf[i+8],
- readbuf[i+9], readbuf[i+10],
- readbuf[i+11], readbuf[i+12],
- readbuf[i+13], readbuf[i+14],
- readbuf[i+15]);
- write(ofd, pretty_buf, 60);
- }
- } else
- write(ofd, readbuf, bs);
-
-
-
- if (omitoob)
- continue;
-
- if (badblock) {
- memset (readbuf, 0xff, meminfo.oobsize);
- } else {
- /* Read OOB data and exit on failure */
- oob.start = ofs;
- if (ioctl(fd, MEMREADOOB, &oob) != 0) {
- perror("ioctl(MEMREADOOB)");
- goto closeall;
- }
- }
-
- /* Write out OOB data */
- if (pretty_print) {
- if (meminfo.oobsize < 16) {
- sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
- "%02x %02x\n",
- oobbuf[0], oobbuf[1], oobbuf[2],
- oobbuf[3], oobbuf[4], oobbuf[5],
- oobbuf[6], oobbuf[7]);
- write(ofd, pretty_buf, 48);
- continue;
- }
-
- for (i = 0; i < meminfo.oobsize; i += 16) {
- sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- oobbuf[i], oobbuf[i+1], oobbuf[i+2],
- oobbuf[i+3], oobbuf[i+4], oobbuf[i+5],
- oobbuf[i+6], oobbuf[i+7], oobbuf[i+8],
- oobbuf[i+9], oobbuf[i+10], oobbuf[i+11],
- oobbuf[i+12], oobbuf[i+13], oobbuf[i+14],
- oobbuf[i+15]);
- write(ofd, pretty_buf, 60);
- }
- } else
- write(ofd, oobbuf, meminfo.oobsize);
- }
-
- /* reset oobinfo */
- if (oobinfochanged == 1) {
- if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- close(fd);
- close(ofd);
- return EXIT_FAILURE;
- }
- }
- /* Close the output file and MTD device */
- close(fd);
- close(ofd);
-
- /* Exit happy */
- return EXIT_SUCCESS;
-
-closeall:
- /* The new mode change is per file descriptor ! */
- if (oobinfochanged == 1) {
- if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- }
- }
- close(fd);
- close(ofd);
- exit(EXIT_FAILURE);
-}
diff --git a/package/nand/src/nandwrite.c b/package/nand/src/nandwrite.c
deleted file mode 100644
index 0b2a9ee8b..000000000
--- a/package/nand/src/nandwrite.c
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * 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 _GNU_SOURCE
-#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"
-
-#define PROGRAM "nandwrite"
-#define VERSION "$Revision: 1.32 $"
-
-#define MAX_PAGE_SIZE 4096
-#define MAX_OOB_SIZE 128
-
-/*
- * Buffer array used for writing data
- */
-static unsigned char writebuf[MAX_PAGE_SIZE];
-static unsigned char oobbuf[MAX_OOB_SIZE];
-static unsigned char oobreadbuf[MAX_OOB_SIZE];
-
-// oob layouts to pass into the kernel as default
-static struct nand_oobinfo none_oobinfo = {
- .useecc = MTD_NANDECC_OFF,
-};
-
-static struct nand_oobinfo jffs2_oobinfo = {
- .useecc = MTD_NANDECC_PLACE,
- .eccbytes = 6,
- .eccpos = { 0, 1, 2, 3, 6, 7 }
-};
-
-static struct nand_oobinfo yaffs_oobinfo = {
- .useecc = MTD_NANDECC_PLACE,
- .eccbytes = 6,
- .eccpos = { 8, 9, 10, 13, 14, 15}
-};
-
-static struct nand_oobinfo autoplace_oobinfo = {
- .useecc = MTD_NANDECC_AUTOPLACE
-};
-
-static void display_help (void)
-{
- printf(
-"Usage: nandwrite [OPTION] MTD_DEVICE [INPUTFILE|-]\n"
-"Writes to the specified MTD device.\n"
-"\n"
-" -a, --autoplace Use auto oob layout\n"
-" -j, --jffs2 Force jffs2 oob layout (legacy support)\n"
-" -y, --yaffs Force yaffs oob layout (legacy support)\n"
-" -f, --forcelegacy Force legacy support on autoplacement-enabled mtd\n"
-" device\n"
-" -m, --markbad Mark blocks bad if write fails\n"
-" -n, --noecc Write without ecc\n"
-" -o, --oob Image contains oob data\n"
-" -s addr, --start=addr Set start address (default is 0)\n"
-" -p, --pad Pad to page size\n"
-" -b, --blockalign=1|2|4 Set multiple of eraseblocks to align to\n"
-" -q, --quiet Don't display progress messages\n"
-" --help Display this help and exit\n"
-" --version Output version information and exit\n"
- );
- exit (EXIT_SUCCESS);
-}
-
-static void display_version (void)
-{
- printf(PROGRAM " " VERSION "\n"
- "\n"
- "Copyright (C) 2003 Thomas Gleixner \n"
- "\n"
- PROGRAM " comes with NO WARRANTY\n"
- "to the extent permitted by law.\n"
- "\n"
- "You may redistribute copies of " PROGRAM "\n"
- "under the terms of the GNU General Public Licence.\n"
- "See the file `COPYING' for more information.\n");
- exit (EXIT_SUCCESS);
-}
-
-static const char *standard_input = "-";
-static const char *mtd_device, *img;
-static int mtdoffset = 0;
-static bool quiet = false;
-static bool writeoob = false;
-static bool autoplace = false;
-static bool markbad = false;
-static bool forcejffs2 = false;
-static bool forceyaffs = false;
-static bool forcelegacy = false;
-static bool noecc = false;
-static bool pad = false;
-static int blockalign = 1; /*default to using 16K block size */
-
-static void process_options (int argc, char * const argv[])
-{
- int error = 0;
-
- for (;;) {
- int option_index = 0;
- static const char *short_options = "ab:fjmnopqs:y";
- static const struct option long_options[] = {
- {"help", no_argument, 0, 0},
- {"version", no_argument, 0, 0},
- {"autoplace", no_argument, 0, 'a'},
- {"blockalign", required_argument, 0, 'b'},
- {"forcelegacy", no_argument, 0, 'f'},
- {"jffs2", no_argument, 0, 'j'},
- {"markbad", no_argument, 0, 'm'},
- {"noecc", no_argument, 0, 'n'},
- {"oob", no_argument, 0, 'o'},
- {"pad", no_argument, 0, 'p'},
- {"quiet", no_argument, 0, 'q'},
- {"start", required_argument, 0, 's'},
- {"yaffs", no_argument, 0, 'y'},
- {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 0:
- display_help();
- break;
- case 1:
- display_version();
- break;
- }
- break;
- case 'q':
- quiet = true;
- break;
- case 'a':
- autoplace = true;
- break;
- case 'j':
- forcejffs2 = true;
- break;
- case 'y':
- forceyaffs = true;
- break;
- case 'f':
- forcelegacy = true;
- break;
- case 'n':
- noecc = true;
- break;
- case 'm':
- markbad = true;
- break;
- case 'o':
- writeoob = true;
- break;
- case 'p':
- pad = true;
- break;
- case 's':
- mtdoffset = strtol (optarg, NULL, 0);
- break;
- case 'b':
- blockalign = atoi (optarg);
- break;
- case '?':
- error++;
- break;
- }
- }
-
- if (mtdoffset < 0) {
- fprintf(stderr, "Can't specify a negative device offset `%d'\n",
- mtdoffset);
- exit (EXIT_FAILURE);
- }
-
- 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 ();
-
- 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);
- }
-}
-
-/*
- * Main program
- */
-int main(int argc, char * const argv[])
-{
- int cnt = 0;
- int fd = -1;
- int ifd = -1;
- int imglen = 0, pagelen;
- bool baderaseblock = false;
- int blockstart = -1;
- struct mtd_info_user meminfo;
- struct mtd_oob_buf oob;
- loff_t offs;
- int ret, readlen;
- int oobinfochanged = 0;
- struct nand_oobinfo old_oobinfo;
- int readcnt = 0;
-
- process_options(argc, argv);
-
- erase_buffer(oobbuf, sizeof(oobbuf));
-
- if (pad && writeoob) {
- fprintf(stderr, "Can't pad when oob data is present.\n");
- exit (EXIT_FAILURE);
- }
-
- /* Open the device */
- if ((fd = open(mtd_device, O_RDWR)) == -1) {
- perror(mtd_device);
- exit (EXIT_FAILURE);
- }
-
- /* Fill in MTD device capability structure */
- if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
- perror("MEMGETINFO");
- close(fd);
- exit (EXIT_FAILURE);
- }
-
- /* Set erasesize to specified number of blocks - to match jffs2
- * (virtual) block size */
- meminfo.erasesize *= blockalign;
-
- /* Make sure device page sizes are valid */
- if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
- !(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
- !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
- !(meminfo.oobsize == 128 && meminfo.writesize == 4096)) {
- fprintf(stderr, "Unknown flash (not normal NAND)\n");
- close(fd);
- exit (EXIT_FAILURE);
- }
-
- if (autoplace) {
- /* Read the current oob info */
- if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMGETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
-
- // autoplace ECC ?
- if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
-
- if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- oobinfochanged = 1;
- }
- }
-
- if (noecc) {
- ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
- if (ret == 0) {
- oobinfochanged = 2;
- } else {
- switch (errno) {
- case ENOTTY:
- if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMGETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- oobinfochanged = 1;
- break;
- default:
- perror ("MTDFILEMODE");
- close (fd);
- exit (EXIT_FAILURE);
- }
- }
- }
-
- /*
- * force oob layout for jffs2 or yaffs ?
- * Legacy support
- */
- if (forcejffs2 || forceyaffs) {
- struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
-
- if (autoplace) {
- fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n");
- goto restoreoob;
- }
- if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {
- fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
- goto restoreoob;
- }
- if (meminfo.oobsize == 8) {
- if (forceyaffs) {
- fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
- goto restoreoob;
- }
- /* Adjust number of ecc bytes */
- jffs2_oobinfo.eccbytes = 3;
- }
-
- if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {
- perror ("MEMSETOOBSEL");
- goto restoreoob;
- }
- }
-
- oob.length = meminfo.oobsize;
- oob.ptr = noecc ? oobreadbuf : oobbuf;
-
- /* 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 restoreoob;
- }
-
- /* For now, don't allow writing oob when reading from standard input. */
- if (ifd == STDIN_FILENO && writeoob) {
- fprintf(stderr, "Can't write oob when reading from standard input.\n");
- goto closeall;
- }
-
- pagelen = meminfo.writesize + ((writeoob) ? meminfo.oobsize : 0);
-
- /*
- * For the standard input case, the input size is merely an
- * invariant placeholder and is set to the write page
- * size. Otherwise, just use the input file size.
- *
- * TODO: Add support for the -l,--length=length option (see
- * previous discussion by Tommi Airikka <tommi.airikka@ericsson.com> at
- * <http://lists.infradead.org/pipermail/linux-mtd/2008-September/
- * 022913.html>
- */
-
- if (ifd == STDIN_FILENO) {
- imglen = pagelen;
- } else {
- imglen = lseek(ifd, 0, SEEK_END);
- lseek (ifd, 0, SEEK_SET);
- }
-
- // 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;
- }
-
- // Check, if length fits into device
- if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
- fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %u bytes\n",
- imglen, pagelen, meminfo.writesize, meminfo.size);
- perror ("Input file does not fit into device");
- goto closeall;
- }
-
- /*
- * 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 && (mtdoffset < meminfo.size)) {
- // new eraseblock , check for bad block(s)
- // Stay in the loop to be sure if the mtdoffset changes because
- // of a bad block, that the next block that will be written to
- // is also checked. Thus avoiding errors if the block(s) after the
- // skipped block(s) is also bad (number of blocks depending on
- // the blockalign
- while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
- blockstart = mtdoffset & (~meminfo.erasesize + 1);
- offs = blockstart;
- baderaseblock = false;
- if (!quiet)
- fprintf (stdout, "Writing data to block %d at offset 0x%x\n",
- blockstart / meminfo.erasesize, blockstart);
-
- /* Check all the blocks in an erase block for bad blocks */
- do {
- if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
- perror("ioctl(MEMGETBADBLOCK)");
- goto closeall;
- }
- if (ret == 1) {
- baderaseblock = true;
- if (!quiet)
- fprintf (stderr, "Bad block at %x, %u block(s) "
- "from %x will be skipped\n",
- (int) offs, blockalign, blockstart);
- }
-
- if (baderaseblock) {
- mtdoffset = blockstart + meminfo.erasesize;
- }
- offs += meminfo.erasesize / blockalign ;
- } while ( offs < blockstart + meminfo.erasesize );
-
- }
-
- readlen = meminfo.writesize;
-
- if (ifd != STDIN_FILENO) {
- int tinycnt = 0;
-
- if (pad && (imglen < readlen))
- {
- readlen = imglen;
- erase_buffer(writebuf + readlen, meminfo.writesize - readlen);
- }
-
- /* Read Page Data from input file */
- 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 file");
- goto closeall;
- }
- tinycnt += cnt;
- }
- } else {
- int tinycnt = 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 stdin");
- goto closeall;
- }
- tinycnt += cnt;
- }
-
- /* No padding needed - we are done */
- if (tinycnt == 0) {
- imglen = 0;
- break;
- }
-
- /* No more bytes - we are done after writing the remaining bytes */
- if (cnt == 0) {
- imglen = 0;
- }
-
- /* Padding */
- if (pad && (tinycnt < readlen)) {
- erase_buffer(writebuf + tinycnt, meminfo.writesize - tinycnt);
- }
- }
-
- if (writeoob) {
- int tinycnt = 0;
-
- while(tinycnt < readlen) {
- cnt = read(ifd, oobreadbuf + tinycnt, meminfo.oobsize - tinycnt);
- if (cnt == 0) { // EOF
- break;
- } else if (cnt < 0) {
- perror ("File I/O error on input file");
- goto closeall;
- }
- tinycnt += cnt;
- }
-
- if (!noecc) {
- int i, start, len;
- /*
- * We use autoplacement and have the oobinfo with the autoplacement
- * information from the kernel available
- *
- * Modified to support out of order oobfree segments,
- * such as the layout used by diskonchip.c
- */
- if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
- 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(oobbuf + start,
- oobreadbuf + start,
- len);
- }
- } else {
- /* Set at least the ecc byte positions to 0xff */
- start = old_oobinfo.eccbytes;
- len = meminfo.oobsize - start;
- memcpy(oobbuf + start,
- oobreadbuf + start,
- len);
- }
- }
- /* Write OOB data first, as ecc will be placed in there*/
- oob.start = mtdoffset;
- if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
- perror ("ioctl(MEMWRITEOOB)");
- goto closeall;
- }
- imglen -= meminfo.oobsize;
- }
-
- /* Write out the Page data */
- if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
- int rewind_blocks;
- off_t rewind_bytes;
- erase_info_t erase;
-
- perror ("pwrite");
- /* Must rewind to blockstart if we can */
- rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
- rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
- if (writeoob)
- rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize;
- if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
- perror("lseek");
- fprintf(stderr, "Failed to seek backwards to recover from write error\n");
- goto closeall;
- }
- erase.start = blockstart;
- erase.length = meminfo.erasesize;
- fprintf(stderr, "Erasing failed write from %08lx-%08lx\n",
- (long)erase.start, (long)erase.start+erase.length-1);
- if (ioctl(fd, MEMERASE, &erase) != 0) {
- perror("MEMERASE");
- goto closeall;
- }
-
- if (markbad) {
- loff_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1);
- fprintf(stderr, "Marking block at %08lx bad\n", (long)bad_addr);
- if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
- perror("MEMSETBADBLOCK");
- /* But continue anyway */
- }
- }
- mtdoffset = blockstart + meminfo.erasesize;
- imglen += rewind_blocks * meminfo.writesize;
-
- continue;
- }
- if (ifd != STDIN_FILENO) {
- imglen -= readlen;
- }
- mtdoffset += meminfo.writesize;
- }
-
-closeall:
- close(ifd);
-
-restoreoob:
- if (oobinfochanged == 1) {
- if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
- perror ("MEMSETOOBSEL");
- close (fd);
- exit (EXIT_FAILURE);
- }
- }
-
- close(fd);
-
- if ((ifd != STDIN_FILENO) && (imglen > 0)) {
- perror ("Data was only partially written due to error\n");
- exit (EXIT_FAILURE);
- }
-
- /* Return happy */
- return EXIT_SUCCESS;
-}