[U-Boot] [PATCH] cmd_nand.c: converted to new style subcmd handling

Frans Meulenbroeks fransmeulenbroeks at gmail.com
Sun Apr 4 21:53:16 CEST 2010


converted to new style subcmd handling.
partly tested on sheevaplug
read and information commands tested on sheevaplug
(sorry did not want to nuke my device so I did not want to
test things like nand scrub)

Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks at gmail.com>

---

note that nand biterr has no implementation
---
 common/cmd_nand.c |  595 ++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 386 insertions(+), 209 deletions(-)

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 9b0c930..d537b4b 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -204,281 +204,458 @@ static void nand_print_info(int idx)
 	       nand->name, nand->erasesize >> 10);
 }
 
-int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+static int nand_quiet(void)
 {
-	int i, dev, ret = 0;
-	ulong addr, off;
-	size_t size;
-	char *cmd, *s;
-	nand_info_t *nand;
+	const char *quiet_str = getenv("quiet");
 #ifdef CONFIG_SYS_NAND_QUIET
 	int quiet = CONFIG_SYS_NAND_QUIET;
 #else
 	int quiet = 0;
 #endif
-	const char *quiet_str = getenv("quiet");
-
-	/* at least two arguments please */
-	if (argc < 2)
-		goto usage;
-
 	if (quiet_str)
 		quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
+	return quiet;
+}
 
-	cmd = argv[1];
+static nand_info_t *get_nand(void)
+{
+	/* the following commands operate on the current device */
+	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
+	    !nand_info[nand_curr_device].name) {
+		puts("\nno devices available\n");
+		return NULL;
+	}
+	return &nand_info[nand_curr_device];
+}
 
-	if (strcmp(cmd, "info") == 0) {
+static int do_nand_info(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int i;
 
-		putc('\n');
-		for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
-			if (nand_info[i].name)
-				nand_print_info(i);
-		}
-		return 0;
+	putc('\n');
+	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
+		if (nand_info[i].name)
+			nand_print_info(i);
 	}
+	return 0;
+}
 
-	if (strcmp(cmd, "device") == 0) {
+static int do_nand_device(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int dev;
 
-		if (argc < 3) {
-			putc('\n');
-			if ((nand_curr_device < 0) ||
-			    (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
-				puts("no devices available\n");
-			else
-				nand_print_info(nand_curr_device);
-			return 0;
-		}
-		dev = (int)simple_strtoul(argv[2], NULL, 10);
-		if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) {
-			puts("No such device\n");
-			return 1;
-		}
-		printf("Device %d: %s", dev, nand_info[dev].name);
-		puts("... is now current device\n");
-		nand_curr_device = dev;
+	if (argc < 2) {
+		putc('\n');
+		if ((nand_curr_device < 0) ||
+		    (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
+			puts("no devices available\n");
+		else
+			nand_print_info(nand_curr_device);
+		return 0;
+	}
+	dev = (int)simple_strtoul(argv[1], NULL, 10);
+	if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) {
+		puts("No such device\n");
+		return 1;
+	}
+	printf("Device %d: %s", dev, nand_info[dev].name);
+	puts("... is now current device\n");
+	nand_curr_device = dev;
 
 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
-		/*
-		 * Select the chip in the board/cpu specific driver
-		 */
-		board_nand_select_device(nand_info[dev].priv, dev);
+	/*
+	 * Select the chip in the board/cpu specific driver
+	 */
+	board_nand_select_device(nand_info[dev].priv, dev);
 #endif
 
-		return 0;
+	return 0;
+}
+
+static int do_nand_read(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 0;
+	size_t size;
+	ulong off;
+	ulong addr;
+	char *s;
+	nand_info_t *nand;
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	if (argc < 4)
+	{
+		cmd_usage(cmdtp);
+		return 1;
 	}
 
-	if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
-	    strncmp(cmd, "dump", 4) != 0 &&
-	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
-	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
-	    strcmp(cmd, "biterr") != 0 &&
-	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
-		goto usage;
+	addr = (ulong)simple_strtoul(argv[1], NULL, 16);
 
-	/* the following commands operate on the current device */
-	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
-	    !nand_info[nand_curr_device].name) {
-		puts("\nno devices available\n");
+	printf("\nNAND read: ");
+	if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) != 0)
+		return 1;
+
+	s = strchr(argv[0], '.');
+	if (!s || !strcmp(s, ".jffs2") ||
+	    !strcmp(s, ".e") || !strcmp(s, ".i")) {
+		ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr);
+	} else if (!strcmp(s, ".oob")) {
+		/* out-of-band data */
+		mtd_oob_ops_t ops = {
+			.oobbuf = (u8 *)addr,
+			.ooblen = size,
+			.mode = MTD_OOB_RAW
+		};
+
+		ret = nand->read_oob(nand, off, &ops);
+	} else {
+		printf("Unknown nand command suffix '%s'.\n", s);
 		return 1;
 	}
-	nand = &nand_info[nand_curr_device];
 
-	if (strcmp(cmd, "bad") == 0) {
-		printf("\nDevice %d bad blocks:\n", nand_curr_device);
-		for (off = 0; off < nand->size; off += nand->erasesize)
-			if (nand_block_isbad(nand, off))
-				printf("  %08lx\n", off);
-		return 0;
+	printf(" %zu bytes read: %s\n", size, ret ? "ERROR" : "OK");
+
+	return ret == 0 ? 0 : 1;
+}
+
+static int do_nand_write(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 0;
+	size_t size;
+	ulong off;
+	ulong addr;
+	char *s;
+	nand_info_t *nand;
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	if (argc < 4)
+	{
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	addr = (ulong)simple_strtoul(argv[1], NULL, 16);
+
+	printf("\nNAND write: ");
+	if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) != 0)
+		return 1;
+
+	s = strchr(argv[0], '.');
+	if (!s || !strcmp(s, ".jffs2") ||
+	    !strcmp(s, ".e") || !strcmp(s, ".i")) {
+		ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr);
+	} else if (!strcmp(s, ".oob")) {
+		/* out-of-band data */
+		mtd_oob_ops_t ops = {
+			.oobbuf = (u8 *)addr,
+			.ooblen = size,
+			.mode = MTD_OOB_RAW
+		};
+
+		ret = nand->write_oob(nand, off, &ops);
+	} else {
+		printf("Unknown nand command suffix '%s'.\n", s);
+		return 1;
 	}
 
+	printf(" %zu bytes written: %s\n", size, ret ? "ERROR" : "OK");
+
+	return ret == 0 ? 0 : 1;
+}
+
+static int do_nand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
 	/*
 	 * Syntax is:
 	 *   0    1     2       3    4
 	 *   nand erase [clean] [off size]
 	 */
-	if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
-		nand_erase_options_t opts;
-		/* "clean" at index 2 means request to write cleanmarker */
-		int clean = argc > 2 && !strcmp("clean", argv[2]);
-		int o = clean ? 3 : 2;
-		int scrub = !strcmp(cmd, "scrub");
-
-		printf("\nNAND %s: ", scrub ? "scrub" : "erase");
-		/* skip first two or three arguments, look for offset and size */
-		if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
-			return 1;
 
-		memset(&opts, 0, sizeof(opts));
-		opts.offset = off;
-		opts.length = size;
-		opts.jffs2  = clean;
-		opts.quiet  = quiet;
-
-		if (scrub) {
-			puts("Warning: "
-			     "scrub option will erase all factory set "
-			     "bad blocks!\n"
-			     "         "
-			     "There is no reliable way to recover them.\n"
-			     "         "
-			     "Use this command only for testing purposes "
-			     "if you\n"
-			     "         "
-			     "are sure of what you are doing!\n"
-			     "\nReally scrub this NAND flash? <y/N>\n");
-
-			if (getc() == 'y') {
-				puts("y");
-				if (getc() == '\r')
-					opts.scrub = 1;
-				else {
-					puts("scrub aborted\n");
-					return -1;
-				}
-			} else {
-				puts("scrub aborted\n");
-				return -1;
-			}
-		}
-		ret = nand_erase_opts(nand, &opts);
-		printf("%s\n", ret ? "ERROR" : "OK");
+	int ret = 0;
+	size_t size;
+	ulong off;
+	nand_erase_options_t opts;
+	/* "clean" at index 1 means request to write cleanmarker */
+	int clean = argc > 1 && !strcmp("clean", argv[1]);
+	int o = clean ? 2 : 1;
+	nand_info_t *nand;
+	int quiet = nand_quiet();
 
-		return ret == 0 ? 0 : 1;
-	}
+	nand = get_nand();
+	if (!nand)
+		return 1;
 
-	if (strncmp(cmd, "dump", 4) == 0) {
-		if (argc < 3)
-			goto usage;
+	printf("\nNAND erase: ");
+	/* skip first two or three arguments, look for offset and size */
+	if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+		return 1;
 
-		s = strchr(cmd, '.');
-		off = (int)simple_strtoul(argv[2], NULL, 16);
+	memset(&opts, 0, sizeof(opts));
+	opts.offset = off;
+	opts.length = size;
+	opts.jffs2  = clean;
+	opts.quiet  = quiet;
 
-		if (s != NULL && strcmp(s, ".oob") == 0)
-			ret = nand_dump(nand, off, 1);
-		else
-			ret = nand_dump(nand, off, 0);
+	ret = nand_erase_opts(nand, &opts);
+	printf("%s\n", ret ? "ERROR" : "OK");
+
+	return ret == 0 ? 0 : 1;
+}
 
-		return ret == 0 ? 1 : 0;
+static int do_nand_scrub(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	/*
+	 * Syntax is:
+	 *   0    1     2       3    4
+	 *   nand scrub [clean] [off size]
+	 */
 
+	int ret = 0;
+	size_t size;
+	ulong off;
+	nand_erase_options_t opts;
+	/* "clean" at index 1 means request to write cleanmarker */
+	int clean = argc > 1 && !strcmp("clean", argv[1]);
+	int o = clean ? 2 : 1;
+	nand_info_t *nand;
+	int quiet = nand_quiet();
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	printf("\nNAND scrub: ");
+	/* skip first two or three arguments, look for offset and size */
+	if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+		return 1;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.offset = off;
+	opts.length = size;
+	opts.jffs2  = clean;
+	opts.quiet  = quiet;
+
+	puts("Warning: "
+	     "scrub option will erase all factory set "
+	     "bad blocks!\n"
+	     "         "
+	     "There is no reliable way to recover them.\n"
+	     "         "
+	     "Use this command only for testing purposes "
+	     "if you\n"
+	     "         "
+	     "are sure of what you are doing!\n"
+	     "\nReally scrub this NAND flash? <y/N>\n");
+
+	if (getc() == 'y') {
+		puts("y");
+		if (getc() == '\r')
+			opts.scrub = 1;
+		else {
+			puts("scrub aborted\n");
+			return -1;
+		}
+	} else {
+		puts("scrub aborted\n");
+		return -1;
 	}
+	ret = nand_erase_opts(nand, &opts);
+	printf("%s\n", ret ? "ERROR" : "OK");
 
-	if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
-		int read;
+	return ret == 0 ? 0 : 1;
+}
 
-		if (argc < 4)
-			goto usage;
+static int do_nand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong off;
+	nand_info_t *nand;
 
-		addr = (ulong)simple_strtoul(argv[2], NULL, 16);
+	nand = get_nand();
+	if (!nand)
+		return 1;
 
-		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
-		printf("\nNAND %s: ", read ? "read" : "write");
-		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
-			return 1;
+	printf("\nDevice %d bad blocks:\n", nand_curr_device);
+	for (off = 0; off < nand->size; off += nand->erasesize)
+		if (nand_block_isbad(nand, off))
+			printf("  %08lx\n", off);
+	return 0;
+}
 
-		s = strchr(cmd, '.');
-		if (!s || !strcmp(s, ".jffs2") ||
-		    !strcmp(s, ".e") || !strcmp(s, ".i")) {
-			if (read)
-				ret = nand_read_skip_bad(nand, off, &size,
-							 (u_char *)addr);
-			else
-				ret = nand_write_skip_bad(nand, off, &size,
-							  (u_char *)addr);
-		} else if (!strcmp(s, ".oob")) {
-			/* out-of-band data */
-			mtd_oob_ops_t ops = {
-				.oobbuf = (u8 *)addr,
-				.ooblen = size,
-				.mode = MTD_OOB_RAW
-			};
-
-			if (read)
-				ret = nand->read_oob(nand, off, &ops);
-			else
-				ret = nand->write_oob(nand, off, &ops);
-		} else {
-			printf("Unknown nand command suffix '%s'.\n", s);
-			return 1;
-		}
+static int do_nand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 0;
+	ulong off;
+	char *s;
+	nand_info_t *nand;
 
-		printf(" %zu bytes %s: %s\n", size,
-		       read ? "read" : "written", ret ? "ERROR" : "OK");
+	nand = get_nand();
+	if (!nand)
+		return 1;
 
-		return ret == 0 ? 0 : 1;
+	if (argc < 2)
+	{
+		cmd_usage(cmdtp);
+		return 1;
 	}
 
-	if (strcmp(cmd, "markbad") == 0) {
-		argc -= 2;
-		argv += 2;
+	s = strchr(argv[0], '.');
+	off = (int)simple_strtoul(argv[1], NULL, 16);
 
-		if (argc <= 0)
-			goto usage;
+	if (s != NULL && strcmp(s, ".oob") == 0)
+		ret = nand_dump(nand, off, 1);
+	else
+		ret = nand_dump(nand, off, 0);
 
-		while (argc > 0) {
-			addr = simple_strtoul(*argv, NULL, 16);
+	return ret == 0 ? 1 : 0;
+}
 
-			if (nand->block_markbad(nand, addr)) {
-				printf("block 0x%08lx NOT marked "
-					"as bad! ERROR %d\n",
-					addr, ret);
-				ret = 1;
-			} else {
-				printf("block 0x%08lx successfully "
-					"marked as bad\n",
-					addr);
-			}
-			--argc;
-			++argv;
-		}
-		return ret;
-	}
+static int do_nand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 0;
+	ulong addr;
+	nand_info_t *nand;
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
 
-	if (strcmp(cmd, "biterr") == 0) {
-		/* todo */
+	argc--;
+	argv++;
+
+	if (argc <= 0)
+	{
+		cmd_usage(cmdtp);
 		return 1;
 	}
 
-#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
-	if (strcmp(cmd, "lock") == 0) {
-		int tight = 0;
-		int status = 0;
-		if (argc == 3) {
-			if (!strcmp("tight", argv[2]))
-				tight = 1;
-			if (!strcmp("status", argv[2]))
-				status = 1;
-		}
-		if (status) {
-			do_nand_status(nand);
+	while (argc > 0) {
+		addr = simple_strtoul(*argv, NULL, 16);
+
+		if (nand->block_markbad(nand, addr)) {
+			printf("block 0x%08lx NOT marked "
+				"as bad! ERROR %d\n",
+				addr, ret);
+			ret = 1;
 		} else {
-			if (!nand_lock(nand, tight)) {
-				puts("NAND flash successfully locked\n");
-			} else {
-				puts("Error locking NAND flash\n");
-				return 1;
-			}
+			printf("block 0x%08lx successfully "
+				"marked as bad\n",
+				addr);
 		}
-		return 0;
+		argc--;
+		argv++;
 	}
+	return ret;
+}
 
-	if (strcmp(cmd, "unlock") == 0) {
-		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
-			return 1;
+static int do_nand_biterr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	nand_info_t *nand;
 
-		if (!nand_unlock(nand, off, size)) {
-			puts("NAND flash successfully unlocked\n");
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	/* todo */
+	return 1;
+}
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+static int do_nand_lock(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr;
+	size_t size;
+	nand_info_t *nand;
+	int tight = 0;
+	int status = 0;
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	if (argc == 2) {
+		if (!strcmp("tight", argv[1]))
+			tight = 1;
+		if (!strcmp("status", argv[1]))
+			status = 1;
+	}
+	if (status) {
+		do_nand_status(nand);
+	} else {
+		if (!nand_lock(nand, tight)) {
+			puts("NAND flash successfully locked\n");
 		} else {
-			puts("Error unlocking NAND flash, "
-			     "write and erase will probably fail\n");
+			puts("Error locking NAND flash\n");
 			return 1;
 		}
-		return 0;
 	}
+	return 0;
+}
+
+static int do_nand_unlock(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr;
+	size_t size;
+	nand_info_t *nand;
+
+	argc--;
+	argv++;
+
+	nand = get_nand();
+	if (!nand)
+		return 1;
+
+	if (arg_off_size(argc, argv, nand, &off, &size) < 0)
+		return 1;
+
+	if (!nand_unlock(nand, off, size)) {
+		puts("NAND flash successfully unlocked\n");
+	} else {
+		puts("Error unlocking NAND flash, "
+		     "write and erase will probably fail\n");
+		return 1;
+	}
+	return 0;
+}
 #endif
 
-usage:
-	cmd_usage(cmdtp);
-	return 1;
+static cmd_tbl_t cmd_nand_sub[] = {
+	U_BOOT_CMD_MKENT(info, 1, 1, do_nand_info, "", ""),
+	U_BOOT_CMD_MKENT(device, 2, 1, do_nand_device, "", ""),
+	U_BOOT_CMD_MKENT(read, 4, 1, do_nand_read, "", ""),
+	U_BOOT_CMD_MKENT(write, 4, 1, do_nand_write, "", ""),
+	U_BOOT_CMD_MKENT(erase, 4, 1, do_nand_erase, "", ""),
+	U_BOOT_CMD_MKENT(bad, 1, 1, do_nand_bad, "", ""),
+	U_BOOT_CMD_MKENT(dump, 2, 1, do_nand_dump, "", ""),
+	U_BOOT_CMD_MKENT(scrub, 1, 1, do_nand_scrub, "", ""),
+	U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 1, do_nand_markbad, "", ""),
+	U_BOOT_CMD_MKENT(biterr, 2, 1, do_nand_biterr, "", ""),
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+	U_BOOT_CMD_MKENT(lock, 1, 1, do_nand_lock, "", ""),
+	U_BOOT_CMD_MKENT(unlock, 1, 1, do_nand_unlock, "", ""),
+#endif
+};
+
+static int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+	cmd_tbl_t *c;
+
+	/* Strip off leading 'nand' command argument */
+	argc--;
+	argv++;
+
+	c = find_cmd_tbl(argv[0], &cmd_nand_sub[0], ARRAY_SIZE(cmd_nand_sub));
+
+	if (c) {
+		return  c->cmd(cmdtp, flag, argc, argv);
+	} else {
+		cmd_usage(cmdtp);
+		return 1;
+	}
 }
 
 U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
-- 
1.6.4.2



More information about the U-Boot mailing list