diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2010-02-07 20:12:57 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2010-02-07 20:12:57 +0100 |
commit | 2bbfadac526c7880720e518e0fdd84ac0ca601bd (patch) | |
tree | 5d7ca7982b47e2fe7ea4ef6ed5f461f3ffce83d7 /package/nand | |
parent | 6daa792eab1488d013fefc5eb7e4d01f40f38687 (diff) | |
parent | 2e44499238125dbecbbf17222496ebba315cc90c (diff) |
resolve conflicts
Diffstat (limited to 'package/nand')
-rw-r--r-- | package/nand/Makefile | 12 | ||||
-rw-r--r-- | package/nand/src/nand.c | 581 | ||||
-rw-r--r-- | package/nand/src/nanddump.c | 421 | ||||
-rw-r--r-- | package/nand/src/nandwrite.c | 647 |
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; -} |