Patches by Pantelis Antoniou, 16 Apr 2004:
- add support for a new version of an Intracom board and fix
  various other things on others.
- add verify support to the crc32 command (define
  CONFIG_CRC32_VERIFY to enable it)
- fix FEC driver for MPC8xx systems:
  1. fix compilation problems for boards that use dynamic
     allocation of DPRAM
  2. shut down FEC after network transfers
- HUSH parser fixes:
  1. A new test command was added. This is a simplified version of
     the one in the bourne shell.
  2. A new exit command was added which terminates the current
     executing script.
  3. Fixed handing of $? (exit code of last executed command)
diff --git a/common/cmd_mem.c b/common/cmd_mem.c
index f18bfde..8430298 100644
--- a/common/cmd_mem.c
+++ b/common/cmd_mem.c
@@ -963,6 +963,8 @@
 	return 0;
 }
 
+#ifndef CONFIG_CRC32_VERIFY
+
 int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
 	ulong addr, length;
@@ -992,6 +994,62 @@
 	return 0;
 }
 
+#else	/* CONFIG_CRC32_VERIFY */
+
+int do_mem_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	ulong addr, length;
+	ulong crc;
+	ulong *ptr;
+	ulong vcrc; 
+	int verify;
+	int ac;
+	char **av;
+
+	if (argc < 3) {
+  usage:
+		printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	av = argv + 1;
+	ac = argc - 1;
+	if (strcmp(*av, "-v") == 0) {
+		verify = 1;
+		av++;
+		ac--;
+		if (ac < 3)
+			goto usage;
+	} else
+		verify = 0;
+
+	addr = simple_strtoul(*av++, NULL, 16);
+	addr += base_address;
+	length = simple_strtoul(*av++, NULL, 16);
+
+	crc = crc32(0, (const uchar *) addr, length);
+
+	if (!verify) {
+		printf ("CRC32 for %08lx ... %08lx ==> %08lx\n",
+				addr, addr + length - 1, crc);
+		if (ac > 2) {
+			ptr = (ulong *) simple_strtoul (*av++, NULL, 16);
+			*ptr = crc;
+		}
+	} else {
+		vcrc = simple_strtoul(*av++, NULL, 16);
+		if (vcrc != crc) {
+			printf ("CRC32 for %08lx ... %08lx ==> %08lx != %08lx ** ERROR **\n",
+					addr, addr + length - 1, crc, vcrc);
+			return 1;
+		}
+	}
+
+	return 0;
+
+}
+#endif	/* CONFIG_CRC32_VERIFY */
+
 /**************************************************/
 #if (CONFIG_COMMANDS & CFG_CMD_MEMORY)
 U_BOOT_CMD(
@@ -1032,12 +1090,25 @@
 	"[.b, .w, .l] addr1 addr2 count\n    - compare memory\n"
 );
 
+#ifndef CONFIG_CRC32_VERIFY
+
 U_BOOT_CMD(
 	crc32,    4,    1,     do_mem_crc,
 	"crc32   - checksum calculation\n",
 	"address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
 );
 
+#else	/* CONFIG_CRC32_VERIFY */
+
+U_BOOT_CMD(
+	crc32,    5,    1,     do_mem_crc,
+	"crc32   - checksum calculation\n",
+	"address count [addr]\n    - compute CRC32 checksum [save at addr]\n"
+	"-v address count crc\n    - verify crc of memory area\n"
+);
+
+#endif	/* CONFIG_CRC32_VERIFY */
+
 U_BOOT_CMD(
 	base,    2,    1,     do_mem_base,
 	"base    - print or set address offset\n",
diff --git a/common/cmd_pcmcia.c b/common/cmd_pcmcia.c
index 47632e7..7a2ca9e 100644
--- a/common/cmd_pcmcia.c
+++ b/common/cmd_pcmcia.c
@@ -289,7 +289,7 @@
 	return (rc);
 }
 
-#endif / CONFIG_PXA_PCMCIA */
+#endif /* CONFIG_PXA_PCMCIA */
 
 #endif /* CONFIG_I82365 */
 
diff --git a/common/command.c b/common/command.c
index df5d3e9..2b48a1c 100644
--- a/common/command.c
+++ b/common/command.c
@@ -74,6 +74,159 @@
 	"    - echo args to console; \\c suppresses newline\n"
 );
 
+#ifdef CFG_HUSH_PARSER
+
+int
+do_test (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	char **ap;
+	int left, adv, expr, last_expr, neg, last_cmp;
+
+	/* args? */
+	if (argc < 3)
+		return 1;
+
+#if 0
+	{
+		printf("test:");
+		left = 1; 
+		while (argv[left])
+			printf(" %s", argv[left++]);
+	}
+#endif
+	
+	last_expr = 0;
+	left = argc - 1; ap = argv + 1;
+	if (left > 0 && strcmp(ap[0], "!") == 0) {
+		neg = 1;
+		ap++;
+		left--;
+	} else
+		neg = 0;
+
+	expr = -1;
+	last_cmp = -1;
+	last_expr = -1;
+	while (left > 0) {
+
+		if (strcmp(ap[0], "-o") == 0 || strcmp(ap[0], "-a") == 0)
+			adv = 1;
+		else if (strcmp(ap[0], "-z") == 0 || strcmp(ap[0], "-n") == 0)
+			adv = 2;
+		else
+			adv = 3;
+
+		if (left < adv) {
+			expr = 1;
+			break;
+		}
+
+		if (adv == 1) {
+			if (strcmp(ap[0], "-o") == 0) {
+				last_expr = expr;
+				last_cmp = 0;
+			} else if (strcmp(ap[0], "-a") == 0) {
+				last_expr = expr;
+				last_cmp = 1;
+			} else {
+				expr = 1;
+				break;
+			}
+		}
+
+		if (adv == 2) {
+			if (strcmp(ap[0], "-z") == 0)
+				expr = strlen(ap[1]) == 0 ? 0 : 1;
+			else if (strcmp(ap[0], "-n") == 0)
+				expr = strlen(ap[1]) == 0 ? 1 : 0;
+			else {
+				expr = 1;
+				break;
+			}
+
+			if (last_cmp == 0)
+				expr = last_expr || expr;
+			else if (last_cmp == 1)
+				expr = last_expr && expr;
+			last_cmp = -1;
+		}
+
+		if (adv == 3) {
+			if (strcmp(ap[1], "=") == 0)
+				expr = strcmp(ap[0], ap[2]) == 0;
+			else if (strcmp(ap[1], "!=") == 0)
+				expr = strcmp(ap[0], ap[2]) != 0;
+			else if (strcmp(ap[1], ">") == 0)
+				expr = strcmp(ap[0], ap[2]) > 0;
+			else if (strcmp(ap[1], "<") == 0)
+				expr = strcmp(ap[0], ap[2]) < 0;
+			else if (strcmp(ap[1], "-eq") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) == simple_strtol(ap[2], NULL, 10);
+			else if (strcmp(ap[1], "-ne") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) != simple_strtol(ap[2], NULL, 10);
+			else if (strcmp(ap[1], "-lt") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) < simple_strtol(ap[2], NULL, 10);
+			else if (strcmp(ap[1], "-le") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) <= simple_strtol(ap[2], NULL, 10);
+			else if (strcmp(ap[1], "-gt") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) > simple_strtol(ap[2], NULL, 10);
+			else if (strcmp(ap[1], "-ge") == 0)
+				expr = simple_strtol(ap[0], NULL, 10) >= simple_strtol(ap[2], NULL, 10);
+			else {
+				expr = 1;
+				break;
+			}
+
+			if (last_cmp == 0)
+				expr = last_expr || expr;
+			else if (last_cmp == 1)
+				expr = last_expr && expr;
+			last_cmp = -1;
+		}
+
+		ap += adv; left -= adv;
+	}
+
+	if (neg)
+		expr = !expr;
+
+	expr = !expr;
+
+#if 0
+	printf(": returns %d\n", expr);
+#endif
+
+	return expr;
+}
+
+U_BOOT_CMD(
+	test,	CFG_MAXARGS,	1,	do_test,
+ 	"test    - minimal test like /bin/sh\n",
+ 	"[args..]\n"
+	"    - test functionality\n"
+);
+
+int
+do_exit (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int r;
+
+	r = 0;
+	if (argc > 1)
+		r = simple_strtoul(argv[1], NULL, 10);
+
+	return -r - 2;
+}
+
+U_BOOT_CMD(
+	exit,	2,	1,	do_exit,
+ 	"exit    - exit script\n",
+	"    - exit functionality\n"
+);
+
+
+#endif
+
 /*
  * Use puts() instead of printf() to avoid printf buffer overflow
  * for long help messages
diff --git a/common/hush.c b/common/hush.c
index eeb970c..47680ed 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -290,6 +290,7 @@
 unsigned int global_argc;
 #endif
 unsigned int last_return_code;
+int nesting_level;
 #ifndef __U_BOOT__
 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
 #endif
@@ -416,7 +417,9 @@
 static int b_addchr(o_string *o, int ch);
 static void b_reset(o_string *o);
 static int b_addqchr(o_string *o, int ch, int quote);
+#ifndef __U_BOOT__
 static int b_adduint(o_string *o, unsigned int i);
+#endif
 /*  in_str manipulations: */
 static int static_get(struct in_str *i);
 static int static_peek(struct in_str *i);
@@ -936,6 +939,7 @@
 	return p + 1;
 }
 
+#ifndef __U_BOOT__
 static int b_adduint(o_string *o, unsigned int i)
 {
 	int r;
@@ -944,6 +948,7 @@
 	do r=b_addchr(o, *p++); while (r==0 && *p);
 	return r;
 }
+#endif
 
 static int static_get(struct in_str *i)
 {
@@ -1921,6 +1926,10 @@
 		}
 		last_return_code=rcode;
 #else
+		if (rcode < -1) {
+			last_return_code = -rcode - 2;
+			return -2;	/* exit */
+		}
 		last_return_code=(rcode == 0) ? 0 : 1;
 #endif
 #ifndef __U_BOOT__
@@ -2145,6 +2154,10 @@
 }
 #endif
 
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch);
+#endif
+
 /* This is used to get/check local shell variables */
 static char *get_local_var(const char *s)
 {
@@ -2152,6 +2165,12 @@
 
 	if (!s)
 		return NULL;
+
+#ifdef __U_BOOT__
+	if (*s == '$')
+		return get_dollar_var(s[1]);
+#endif
+
 	for (cur = top_vars; cur; cur=cur->next)
 		if(strcmp(cur->name, s)==0)
 			return cur->value;
@@ -2168,12 +2187,19 @@
 	int result=0;
 	struct variables *cur;
 
+#ifdef __U_BOOT__
+	/* might be possible! */
+	if (!isalpha(*s))
+		return -1;
+#endif
+
 	name=strdup(s);
 
 #ifdef __U_BOOT__
 	if (getenv(name) != NULL) {
 		printf ("ERROR: "
 				"There is a global environment variable with the same name.\n");
+		free(name);
 		return -1;
 	}
 #endif
@@ -2278,7 +2304,10 @@
 
 static int is_assignment(const char *s)
 {
-	if (s==NULL || !isalpha(*s)) return 0;
+	if (s == NULL)
+		return 0;
+
+	if (!isalpha(*s)) return 0;
 	++s;
 	while(isalnum(*s) || *s=='_') ++s;
 	return *s=='=';
@@ -2749,15 +2778,35 @@
  * see the bash man page under "Parameter Expansion" */
 static char *lookup_param(char *src)
 {
-	char *p=NULL;
-	if (src) {
+	char *p;
+
+	if (!src)
+		return NULL;
+
 		p = getenv(src);
 		if (!p)
 			p = get_local_var(src);
-	}
+
 	return p;
 }
 
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch)
+{
+	static char buf[40];
+
+	buf[0] = '\0';
+	switch (ch) {
+		case '?':
+			sprintf(buf, "%u", (unsigned int)last_return_code);
+			break;
+		default:
+			return NULL;
+	}
+	return buf;
+}
+#endif
+
 /* return code: 0 for OK, 1 for syntax error */
 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
 {
@@ -2799,7 +2848,15 @@
 			break;
 #endif
 		case '?':
+#ifndef __U_BOOT__
 			b_adduint(dest,last_return_code);
+#else
+			ctx->child->sp++;
+			b_addchr(dest, SPECIAL_VAR_SYMBOL);
+			b_addchr(dest, '$');
+			b_addchr(dest, '?');
+			b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#endif
 			advance = 1;
 			break;
 #ifndef __U_BOOT__
@@ -2885,8 +2942,11 @@
 		if (input->__promptme == 0) return 1;
 #endif
 		next = (ch == '\n') ? 0 : b_peek(input);
-		debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
-			ch,ch,m,dest->quote);
+
+		debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
+			ch >= ' ' ? ch : '.', ch, m,
+			dest->quote, ctx->stack == NULL ? '*' : '.');
+
 		if (m==0 || ((m==1 || m==2) && dest->quote)) {
 			b_addqchr(dest, ch, dest->quote);
 		} else {
@@ -3107,7 +3167,18 @@
 #ifndef __U_BOOT__
 			run_list(ctx.list_head);
 #else
-			if (((code = run_list(ctx.list_head)) == -1))
+			code = run_list(ctx.list_head);
+			if (code == -2) {	/* exit */
+				b_free(&temp);
+				code = 0;
+				/* XXX hackish way to not allow exit from main loop */
+				if (inp->peek == file_peek) {
+					printf("exit not allowed from main input shell.\n");
+					continue;
+				}
+				break;
+			}
+			if (code == -1)
 			    flag_repeat = 0;
 #endif
 		} else {