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