mtd/util nandwrite.c,1.3,1.4
gleixner at infradead.org
gleixner at infradead.org
Tue Feb 18 06:35:34 EST 2003
Update of /home/cvs/mtd/util
In directory phoenix.infradead.org:/tmp/cvs-serv13133
Modified Files:
nandwrite.c
Log Message:
overhauled to support ECC layouts, bad block handling
Index: nandwrite.c
===================================================================
RCS file: /home/cvs/mtd/util/nandwrite.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- nandwrite.c 7 Mar 2001 09:34:19 -0000 1.3
+++ nandwrite.c 18 Feb 2003 11:35:32 -0000 1.4
@@ -2,6 +2,7 @@
* nandwrite.c
*
* Copyright (C) 2000 Steven J. Hill (sjhill at cotw.com)
+ * 2003 Thomas Gleixner (tglx at linutronix.de)
*
* $Id$
*
@@ -14,8 +15,10 @@
* 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:
- * How are we going to do with ECC (esp. for "free" pages) ?
*/
#define _GNU_SOURCE
@@ -28,9 +31,14 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
+#include <getopt.h>
#include <asm/types.h>
-#include <linux/mtd/mtd.h>
+#include "linux/mtd/mtd.h"
+#include "linux/mtd/nand.h"
+
+#define PROGRAM "nandwrite"
+#define VERSION "1.2"
/*
* Buffer array used for writing data
@@ -38,25 +46,126 @@
unsigned char writebuf[512];
unsigned char oobbuf[16];
+void display_help (void)
+{
+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
+ "Erases all of the specified MTD device.\n"
+ "\n"
+ " -j, --jffs2 force jffs2 oob layout\n"
+ " -y, --yaffs force yaffs oob layout\n"
+ " -n, --noecc write without ecc\n"
+ " -o, --oob image copntains oob data\n"
+ " -s addr, --start=addr set start address (default is 0)\n"
+ " -q, --quiet don't display progress messages\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n");
+ exit(0);
+}
+
+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(0);
+}
+
+char *mtd_device, *img;
+int mtdoffset = 0;
+int quiet = 0;
+int writeoob = 0;
+int forcejffs2 = 0;
+int forceyaffs = 0;
+int noecc = 0;
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "q";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"oob", no_argument, 0, 'o'},
+ {"start", required_argument, 0, 's'},
+ {"jffs2", no_argument, 0, 'j'},
+ {"yaffs", no_argument, 0, 'y'},
+ {"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 'q':
+ quiet = 1;
+ break;
+ case 'j':
+ forcejffs2 = 1;
+ break;
+ case 'y':
+ forceyaffs = 1;
+ break;
+ case 'n':
+ noecc = 1;
+ break;
+ case 'o':
+ writeoob = 1;
+ break;
+ case 's':
+ mtdoffset = atoi (optarg);
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2 || error)
+ display_help ();
+
+ mtd_device = argv[optind++];
+ img = argv[optind];
+}
+
+
/*
* Main program
*/
int main(int argc, char **argv)
{
- unsigned long ofs;
- int cnt, fd, ifd;
+ int cnt, fd, ifd, imglen, pagelen, blockstart = -1;
mtd_info_t meminfo;
- struct mtd_oob_buf oob = {0, 16, oobbuf};
+ struct mtd_oob_buf oob;
- /* Make sure enough arguments were passed */
- if (argc < 4) {
- printf("usage: %s <mtdname> <input file> <start address>\n",
- argv[0]);
- exit(1);
- }
+ process_options(argc, argv);
/* Open the device */
- if ((fd = open(argv[1], O_RDWR)) == -1) {
+ if ((fd = open(mtd_device, O_RDWR)) == -1) {
perror("open flash");
exit(1);
}
@@ -75,56 +184,130 @@
close(fd);
exit(1);
}
+
+ // write without ecc ?
+ if (noecc) {
+ int oobsel = NAND_NONE_OOB;
+ if (ioctl (fd, MEMSETOOBSEL, &oobsel) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ }
+
+ // force oob layout for jffs2 or yaffs ?
+ if (forcejffs2 || forceyaffs) {
+ int oobsel = forcejffs2 ? NAND_JFFS2_OOB : NAND_YAFFS_OOB;
+ if (ioctl (fd, MEMSETOOBSEL, &oobsel) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ }
+
+ oob.length = meminfo.oobsize;
+ oob.ptr = oobbuf;
/* Open the input file */
- if ((ifd = open(argv[2], O_RDONLY)) == -1) {
+ if ((ifd = open(img, O_RDONLY)) == -1) {
perror("open input file");
close(fd);
close(ifd);
exit(1);
}
- /* Get start address */
- ofs = strtoul(argv[3], NULL, 0);
-
+ // get image length
+ imglen = lseek(ifd, 0, SEEK_END);
+ lseek (ifd, 0, SEEK_SET);
+
+ pagelen = meminfo.oobblock + (writeoob == 1) ? meminfo.oobsize : 0;
+
+ // Check, if file is pagealigned
+ if ( (imglen % pagelen) != 0) {
+ perror ("Input file is not page aligned");
+ close (fd);
+ close (ifd);
+ exit (1);
+ }
+
+ // Check, if length fits into device
+ if ( ((imglen / pagelen) * meminfo.oobblock) > (meminfo.size - mtdoffset)) {
+ perror ("Input file does not fit into device");
+ close (fd);
+ close (ifd);
+ exit (1);
+ }
+
/* Get data from input and write to the device */
- while(1) {
- /* Read Page Data from input file */
- if (!(cnt = read(ifd, writebuf, meminfo.oobblock)))
- /* EOF */
- break;
- else {
- /* Write out the Page data */
- if (pwrite(fd, writebuf, cnt, ofs) != cnt) {
- perror("pwrite");
- close(fd);
- close(ifd);
- exit(1);
+ while(mtdoffset < meminfo.size) {
+ // new eraseblock , check for bad block
+ if (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
+ blockstart = mtdoffset & (~meminfo.erasesize + 1);
+ oob.start = blockstart;
+ if (!quiet)
+ fprintf (stdout, "Writing data to block %x\n", blockstart);
+ if (ioctl(fd, MEMREADOOB, &oob) != 0) {
+ perror("ioctl(MEMREADOOB)");
+ close (ifd);
+ close (fd);
+ exit (1);
+ }
+ if (oobbuf[5] != 0xff) {
+ if (!quiet)
+ fprintf (stderr, "Bad block at %x, will be skipped\n", blockstart);
+ mtdoffset = blockstart + meminfo.erasesize;
+ continue;
}
}
-
- /* Read OOB data from input file, exit on failure */
- if (!read(ifd, oobbuf, meminfo.oobsize)) {
- fprintf(stderr, "Unexpected EOF in input file\n");
- exit(1);
+
+ /* Read Page Data from input file */
+ if ((cnt = read(ifd, writebuf, meminfo.oobblock)) != meminfo.oobblock) {
+ if (cnt == 0) // EOF
+ break;
+ perror ("File I/O error on input file");
+ close (fd);
+ close (ifd);
+ exit (1);
+ }
+
+ if (writeoob) {
+ /* Read OOB data from input file, exit on failure */
+ if ((cnt = read(ifd, oobbuf, meminfo.oobsize)) != meminfo.oobsize) {
+ perror ("File I/O error on input file");
+ close (fd);
+ close (ifd);
+ exit (1);
+ }
+ /* Write OOB data first, as ecc will be placed in there*/
+ oob.start = mtdoffset;
+ if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
+ perror ("ioctl(MEMWRITEOOB)");
+ close (fd);
+ close (ifd);
+ exit (1);
+ }
+ imglen -= meminfo.oobsize;
}
-
- /* Write OOB data */
- oob.start = ofs;
- if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
- perror("ioctl(MEMWRITEOOB)");
- close(fd);
- close(ifd);
- exit(1);
+
+ /* Write out the Page data */
+ if (pwrite(fd, writebuf, meminfo.oobblock, mtdoffset) != meminfo.oobblock) {
+ perror ("pwrite");
+ close (fd);
+ close (ifd);
+ exit (1);
}
-
- /* Increment address counter */
- ofs += meminfo.oobblock;
+ imglen -= meminfo.oobblock;
+ mtdoffset += meminfo.oobblock;
}
/* Close the output file and MTD device */
close(fd);
close(ifd);
+
+ if (imglen > 0) {
+ perror ("Data did not fit into device, due to bad blocks\n");
+ exit (1);
+ }
/* Return happy */
return 0;
More information about the linux-mtd-cvs
mailing list