xref: /rk3399_rockchip-uboot/common/main.c (revision 281f69ede28cd3d8be5d62a96b5a0b73e6065858)
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Add to readline cmdline-editing by
6  * (C) Copyright 2005
7  * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27 
28 /* #define	DEBUG	*/
29 
30 #include <common.h>
31 #include <watchdog.h>
32 #include <command.h>
33 #ifdef CONFIG_MODEM_SUPPORT
34 #include <malloc.h>		/* for free() prototype */
35 #endif
36 
37 #ifdef CFG_HUSH_PARSER
38 #include <hush.h>
39 #endif
40 
41 #include <post.h>
42 
43 #ifdef CONFIG_SILENT_CONSOLE
44 DECLARE_GLOBAL_DATA_PTR;
45 #endif
46 
47 #if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
48 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);		/* for do_reset() prototype */
49 #endif
50 
51 extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
52 
53 
54 #define MAX_DELAY_STOP_STR 32
55 
56 static int parse_line (char *, char *[]);
57 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
58 static int abortboot(int);
59 #endif
60 
61 #undef DEBUG_PARSER
62 
63 char        console_buffer[CFG_CBSIZE];		/* console I/O buffer	*/
64 
65 #ifndef CONFIG_CMDLINE_EDITING
66 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
67 static char erase_seq[] = "\b \b";		/* erase sequence	*/
68 static char   tab_seq[] = "        ";		/* used to expand TABs	*/
69 #endif /* CONFIG_CMDLINE_EDITING */
70 
71 #ifdef CONFIG_BOOT_RETRY_TIME
72 static uint64_t endtime = 0;  /* must be set, default is instant timeout */
73 static int      retry_time = -1; /* -1 so can call readline before main_loop */
74 #endif
75 
76 #define	endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
77 
78 #ifndef CONFIG_BOOT_RETRY_MIN
79 #define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
80 #endif
81 
82 #ifdef CONFIG_MODEM_SUPPORT
83 int do_mdm_init = 0;
84 extern void mdm_init(void); /* defined in board.c */
85 #endif
86 
87 /***************************************************************************
88  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
89  * returns: 0 -  no key string, allow autoboot
90  *          1 - got key string, abort
91  */
92 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
93 # if defined(CONFIG_AUTOBOOT_KEYED)
94 static __inline__ int abortboot(int bootdelay)
95 {
96 	int abort = 0;
97 	uint64_t etime = endtick(bootdelay);
98 	struct
99 	{
100 		char* str;
101 		u_int len;
102 		int retry;
103 	}
104 	delaykey [] =
105 	{
106 		{ str: getenv ("bootdelaykey"),  retry: 1 },
107 		{ str: getenv ("bootdelaykey2"), retry: 1 },
108 		{ str: getenv ("bootstopkey"),   retry: 0 },
109 		{ str: getenv ("bootstopkey2"),  retry: 0 },
110 	};
111 
112 	char presskey [MAX_DELAY_STOP_STR];
113 	u_int presskey_len = 0;
114 	u_int presskey_max = 0;
115 	u_int i;
116 
117 #ifdef CONFIG_SILENT_CONSOLE
118 	if (gd->flags & GD_FLG_SILENT) {
119 		/* Restore serial console */
120 		console_assign (stdout, "serial");
121 		console_assign (stderr, "serial");
122 	}
123 #endif
124 
125 #  ifdef CONFIG_AUTOBOOT_PROMPT
126 	printf (CONFIG_AUTOBOOT_PROMPT, bootdelay);
127 #  endif
128 
129 #  ifdef CONFIG_AUTOBOOT_DELAY_STR
130 	if (delaykey[0].str == NULL)
131 		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
132 #  endif
133 #  ifdef CONFIG_AUTOBOOT_DELAY_STR2
134 	if (delaykey[1].str == NULL)
135 		delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
136 #  endif
137 #  ifdef CONFIG_AUTOBOOT_STOP_STR
138 	if (delaykey[2].str == NULL)
139 		delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
140 #  endif
141 #  ifdef CONFIG_AUTOBOOT_STOP_STR2
142 	if (delaykey[3].str == NULL)
143 		delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
144 #  endif
145 
146 	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
147 		delaykey[i].len = delaykey[i].str == NULL ?
148 				    0 : strlen (delaykey[i].str);
149 		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
150 				    MAX_DELAY_STOP_STR : delaykey[i].len;
151 
152 		presskey_max = presskey_max > delaykey[i].len ?
153 				    presskey_max : delaykey[i].len;
154 
155 #  if DEBUG_BOOTKEYS
156 		printf("%s key:<%s>\n",
157 		       delaykey[i].retry ? "delay" : "stop",
158 		       delaykey[i].str ? delaykey[i].str : "NULL");
159 #  endif
160 	}
161 
162 	/* In order to keep up with incoming data, check timeout only
163 	 * when catch up.
164 	 */
165 	while (!abort && get_ticks() <= etime) {
166 		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
167 			if (delaykey[i].len > 0 &&
168 			    presskey_len >= delaykey[i].len &&
169 			    memcmp (presskey + presskey_len - delaykey[i].len,
170 				    delaykey[i].str,
171 				    delaykey[i].len) == 0) {
172 #  if DEBUG_BOOTKEYS
173 				printf("got %skey\n",
174 				       delaykey[i].retry ? "delay" : "stop");
175 #  endif
176 
177 #  ifdef CONFIG_BOOT_RETRY_TIME
178 				/* don't retry auto boot */
179 				if (! delaykey[i].retry)
180 					retry_time = -1;
181 #  endif
182 				abort = 1;
183 			}
184 		}
185 
186 		if (tstc()) {
187 			if (presskey_len < presskey_max) {
188 				presskey [presskey_len ++] = getc();
189 			}
190 			else {
191 				for (i = 0; i < presskey_max - 1; i ++)
192 					presskey [i] = presskey [i + 1];
193 
194 				presskey [i] = getc();
195 			}
196 		}
197 	}
198 #  if DEBUG_BOOTKEYS
199 	if (!abort)
200 		puts ("key timeout\n");
201 #  endif
202 
203 #ifdef CONFIG_SILENT_CONSOLE
204 	if (abort) {
205 		/* permanently enable normal console output */
206 		gd->flags &= ~(GD_FLG_SILENT);
207 	} else if (gd->flags & GD_FLG_SILENT) {
208 		/* Restore silent console */
209 		console_assign (stdout, "nulldev");
210 		console_assign (stderr, "nulldev");
211 	}
212 #endif
213 
214 	return abort;
215 }
216 
217 # else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
218 
219 #ifdef CONFIG_MENUKEY
220 static int menukey = 0;
221 #endif
222 
223 static __inline__ int abortboot(int bootdelay)
224 {
225 	int abort = 0;
226 
227 #ifdef CONFIG_SILENT_CONSOLE
228 	if (gd->flags & GD_FLG_SILENT) {
229 		/* Restore serial console */
230 		console_assign (stdout, "serial");
231 		console_assign (stderr, "serial");
232 	}
233 #endif
234 
235 #ifdef CONFIG_MENUPROMPT
236 	printf(CONFIG_MENUPROMPT, bootdelay);
237 #else
238 	printf("Hit any key to stop autoboot: %2d ", bootdelay);
239 #endif
240 
241 #if defined CONFIG_ZERO_BOOTDELAY_CHECK
242 	/*
243 	 * Check if key already pressed
244 	 * Don't check if bootdelay < 0
245 	 */
246 	if (bootdelay >= 0) {
247 		if (tstc()) {	/* we got a key press	*/
248 			(void) getc();  /* consume input	*/
249 			puts ("\b\b\b 0");
250 			abort = 1; 	/* don't auto boot	*/
251 		}
252 	}
253 #endif
254 
255 	while ((bootdelay > 0) && (!abort)) {
256 		int i;
257 
258 		--bootdelay;
259 		/* delay 100 * 10ms */
260 		for (i=0; !abort && i<100; ++i) {
261 			if (tstc()) {	/* we got a key press	*/
262 				abort  = 1;	/* don't auto boot	*/
263 				bootdelay = 0;	/* no more delay	*/
264 # ifdef CONFIG_MENUKEY
265 				menukey = getc();
266 # else
267 				(void) getc();  /* consume input	*/
268 # endif
269 				break;
270 			}
271 			udelay (10000);
272 		}
273 
274 		printf ("\b\b\b%2d ", bootdelay);
275 	}
276 
277 	putc ('\n');
278 
279 #ifdef CONFIG_SILENT_CONSOLE
280 	if (abort) {
281 		/* permanently enable normal console output */
282 		gd->flags &= ~(GD_FLG_SILENT);
283 	} else if (gd->flags & GD_FLG_SILENT) {
284 		/* Restore silent console */
285 		console_assign (stdout, "nulldev");
286 		console_assign (stderr, "nulldev");
287 	}
288 #endif
289 
290 	return abort;
291 }
292 # endif	/* CONFIG_AUTOBOOT_KEYED */
293 #endif	/* CONFIG_BOOTDELAY >= 0  */
294 
295 /****************************************************************************/
296 
297 void main_loop (void)
298 {
299 #ifndef CFG_HUSH_PARSER
300 	static char lastcommand[CFG_CBSIZE] = { 0, };
301 	int len;
302 	int rc = 1;
303 	int flag;
304 #endif
305 
306 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
307 	char *s;
308 	int bootdelay;
309 #endif
310 #ifdef CONFIG_PREBOOT
311 	char *p;
312 #endif
313 #ifdef CONFIG_BOOTCOUNT_LIMIT
314 	unsigned long bootcount = 0;
315 	unsigned long bootlimit = 0;
316 	char *bcs;
317 	char bcs_set[16];
318 #endif /* CONFIG_BOOTCOUNT_LIMIT */
319 
320 #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
321 	ulong bmp = 0;		/* default bitmap */
322 	extern int trab_vfd (ulong bitmap);
323 
324 #ifdef CONFIG_MODEM_SUPPORT
325 	if (do_mdm_init)
326 		bmp = 1;	/* alternate bitmap */
327 #endif
328 	trab_vfd (bmp);
329 #endif	/* CONFIG_VFD && VFD_TEST_LOGO */
330 
331 #ifdef CONFIG_BOOTCOUNT_LIMIT
332 	bootcount = bootcount_load();
333 	bootcount++;
334 	bootcount_store (bootcount);
335 	sprintf (bcs_set, "%lu", bootcount);
336 	setenv ("bootcount", bcs_set);
337 	bcs = getenv ("bootlimit");
338 	bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
339 #endif /* CONFIG_BOOTCOUNT_LIMIT */
340 
341 #ifdef CONFIG_MODEM_SUPPORT
342 	debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
343 	if (do_mdm_init) {
344 		char *str = strdup(getenv("mdm_cmd"));
345 		setenv ("preboot", str);  /* set or delete definition */
346 		if (str != NULL)
347 			free (str);
348 		mdm_init(); /* wait for modem connection */
349 	}
350 #endif  /* CONFIG_MODEM_SUPPORT */
351 
352 #ifdef CONFIG_VERSION_VARIABLE
353 	{
354 		extern char version_string[];
355 
356 		setenv ("ver", version_string);  /* set version variable */
357 	}
358 #endif /* CONFIG_VERSION_VARIABLE */
359 
360 #ifdef CFG_HUSH_PARSER
361 	u_boot_hush_start ();
362 #endif
363 
364 #ifdef CONFIG_AUTO_COMPLETE
365 	install_auto_complete();
366 #endif
367 
368 #ifdef CONFIG_PREBOOT
369 	if ((p = getenv ("preboot")) != NULL) {
370 # ifdef CONFIG_AUTOBOOT_KEYED
371 		int prev = disable_ctrlc(1);	/* disable Control C checking */
372 # endif
373 
374 # ifndef CFG_HUSH_PARSER
375 		run_command (p, 0);
376 # else
377 		parse_string_outer(p, FLAG_PARSE_SEMICOLON |
378 				    FLAG_EXIT_FROM_LOOP);
379 # endif
380 
381 # ifdef CONFIG_AUTOBOOT_KEYED
382 		disable_ctrlc(prev);	/* restore Control C checking */
383 # endif
384 	}
385 #endif /* CONFIG_PREBOOT */
386 
387 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
388 	s = getenv ("bootdelay");
389 	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
390 
391 	debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
392 
393 # ifdef CONFIG_BOOT_RETRY_TIME
394 	init_cmd_timeout ();
395 # endif	/* CONFIG_BOOT_RETRY_TIME */
396 
397 #ifdef CONFIG_BOOTCOUNT_LIMIT
398 	if (bootlimit && (bootcount > bootlimit)) {
399 		printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
400 		        (unsigned)bootlimit);
401 		s = getenv ("altbootcmd");
402 	}
403 	else
404 #endif /* CONFIG_BOOTCOUNT_LIMIT */
405 		s = getenv ("bootcmd");
406 
407 	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
408 
409 	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
410 # ifdef CONFIG_AUTOBOOT_KEYED
411 		int prev = disable_ctrlc(1);	/* disable Control C checking */
412 # endif
413 
414 # ifndef CFG_HUSH_PARSER
415 		run_command (s, 0);
416 # else
417 		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
418 				    FLAG_EXIT_FROM_LOOP);
419 # endif
420 
421 # ifdef CONFIG_AUTOBOOT_KEYED
422 		disable_ctrlc(prev);	/* restore Control C checking */
423 # endif
424 	}
425 
426 # ifdef CONFIG_MENUKEY
427 	if (menukey == CONFIG_MENUKEY) {
428 	    s = getenv("menucmd");
429 	    if (s) {
430 # ifndef CFG_HUSH_PARSER
431 		run_command (s, 0);
432 # else
433 		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
434 				    FLAG_EXIT_FROM_LOOP);
435 # endif
436 	    }
437 	}
438 #endif /* CONFIG_MENUKEY */
439 #endif	/* CONFIG_BOOTDELAY */
440 
441 #ifdef CONFIG_AMIGAONEG3SE
442 	{
443 	    extern void video_banner(void);
444 	    video_banner();
445 	}
446 #endif
447 
448 	/*
449 	 * Main Loop for Monitor Command Processing
450 	 */
451 #ifdef CFG_HUSH_PARSER
452 	parse_file_outer();
453 	/* This point is never reached */
454 	for (;;);
455 #else
456 	for (;;) {
457 #ifdef CONFIG_BOOT_RETRY_TIME
458 		if (rc >= 0) {
459 			/* Saw enough of a valid command to
460 			 * restart the timeout.
461 			 */
462 			reset_cmd_timeout();
463 		}
464 #endif
465 		len = readline (CFG_PROMPT);
466 
467 		flag = 0;	/* assume no special flags for now */
468 		if (len > 0)
469 			strcpy (lastcommand, console_buffer);
470 		else if (len == 0)
471 			flag |= CMD_FLAG_REPEAT;
472 #ifdef CONFIG_BOOT_RETRY_TIME
473 		else if (len == -2) {
474 			/* -2 means timed out, retry autoboot
475 			 */
476 			puts ("\nTimed out waiting for command\n");
477 # ifdef CONFIG_RESET_TO_RETRY
478 			/* Reinit board to run initialization code again */
479 			do_reset (NULL, 0, 0, NULL);
480 # else
481 			return;		/* retry autoboot */
482 # endif
483 		}
484 #endif
485 
486 		if (len == -1)
487 			puts ("<INTERRUPT>\n");
488 		else
489 			rc = run_command (lastcommand, flag);
490 
491 		if (rc <= 0) {
492 			/* invalid command or not repeatable, forget it */
493 			lastcommand[0] = 0;
494 		}
495 	}
496 #endif /*CFG_HUSH_PARSER*/
497 }
498 
499 #ifdef CONFIG_BOOT_RETRY_TIME
500 /***************************************************************************
501  * initialise command line timeout
502  */
503 void init_cmd_timeout(void)
504 {
505 	char *s = getenv ("bootretry");
506 
507 	if (s != NULL)
508 		retry_time = (int)simple_strtol(s, NULL, 10);
509 	else
510 		retry_time =  CONFIG_BOOT_RETRY_TIME;
511 
512 	if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
513 		retry_time = CONFIG_BOOT_RETRY_MIN;
514 }
515 
516 /***************************************************************************
517  * reset command line timeout to retry_time seconds
518  */
519 void reset_cmd_timeout(void)
520 {
521 	endtime = endtick(retry_time);
522 }
523 #endif
524 
525 #ifdef CONFIG_CMDLINE_EDITING
526 
527 /*
528  * cmdline-editing related codes from vivi.
529  * Author: Janghoon Lyu <nandy@mizi.com>
530  */
531 
532 #if 1	/* avoid redundand code -- wd */
533 #define putnstr(str,n)	do {			\
534 		printf ("%.*s", n, str);	\
535 	} while (0)
536 #else
537 void putnstr(const char *str, size_t n)
538 {
539 	if (str == NULL)
540 		return;
541 
542 	while (n && *str != '\0') {
543 		putc(*str);
544 		str++;
545 		n--;
546 	}
547 }
548 #endif
549 
550 #define CTL_CH(c)		((c) - 'a' + 1)
551 
552 #define MAX_CMDBUF_SIZE		256
553 
554 #define CTL_BACKSPACE		('\b')
555 #define DEL			((char)255)
556 #define DEL7			((char)127)
557 #define CREAD_HIST_CHAR		('!')
558 
559 #define getcmd_putch(ch)	putc(ch)
560 #define getcmd_getch()		getc()
561 #define getcmd_cbeep()		getcmd_putch('\a')
562 
563 #define HIST_MAX		20
564 #define HIST_SIZE		MAX_CMDBUF_SIZE
565 
566 static int hist_max = 0;
567 static int hist_add_idx = 0;
568 static int hist_cur = -1;
569 unsigned hist_num = 0;
570 
571 char* hist_list[HIST_MAX];
572 char hist_lines[HIST_MAX][HIST_SIZE];
573 
574 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
575 
576 static void hist_init(void)
577 {
578 	int i;
579 
580 	hist_max = 0;
581 	hist_add_idx = 0;
582 	hist_cur = -1;
583 	hist_num = 0;
584 
585 	for (i = 0; i < HIST_MAX; i++) {
586 		hist_list[i] = hist_lines[i];
587 		hist_list[i][0] = '\0';
588 	}
589 }
590 
591 static void cread_add_to_hist(char *line)
592 {
593 	strcpy(hist_list[hist_add_idx], line);
594 
595 	if (++hist_add_idx >= HIST_MAX)
596 		hist_add_idx = 0;
597 
598 	if (hist_add_idx > hist_max)
599 		hist_max = hist_add_idx;
600 
601 	hist_num++;
602 }
603 
604 static char* hist_prev(void)
605 {
606 	char *ret;
607 	int old_cur;
608 
609 	if (hist_cur < 0)
610 		return NULL;
611 
612 	old_cur = hist_cur;
613 	if (--hist_cur < 0)
614 		hist_cur = hist_max;
615 
616 	if (hist_cur == hist_add_idx) {
617 		hist_cur = old_cur;
618 		ret = NULL;
619 	} else
620 		ret = hist_list[hist_cur];
621 
622 	return (ret);
623 }
624 
625 static char* hist_next(void)
626 {
627 	char *ret;
628 
629 	if (hist_cur < 0)
630 		return NULL;
631 
632 	if (hist_cur == hist_add_idx)
633 		return NULL;
634 
635 	if (++hist_cur > hist_max)
636 		hist_cur = 0;
637 
638 	if (hist_cur == hist_add_idx) {
639 		ret = "";
640 	} else
641 		ret = hist_list[hist_cur];
642 
643 	return (ret);
644 }
645 
646 #ifndef CONFIG_CMDLINE_EDITING
647 static void cread_print_hist_list(void)
648 {
649 	int i;
650 	unsigned long n;
651 
652 	n = hist_num - hist_max;
653 
654 	i = hist_add_idx + 1;
655 	while (1) {
656 		if (i > hist_max)
657 			i = 0;
658 		if (i == hist_add_idx)
659 			break;
660 		printf("%s\n", hist_list[i]);
661 		n++;
662 		i++;
663 	}
664 }
665 #endif /* CONFIG_CMDLINE_EDITING */
666 
667 #define BEGINNING_OF_LINE() {			\
668 	while (num) {				\
669 		getcmd_putch(CTL_BACKSPACE);	\
670 		num--;				\
671 	}					\
672 }
673 
674 #define ERASE_TO_EOL() {				\
675 	if (num < eol_num) {				\
676 		int tmp;				\
677 		for (tmp = num; tmp < eol_num; tmp++)	\
678 			getcmd_putch(' ');		\
679 		while (tmp-- > num)			\
680 			getcmd_putch(CTL_BACKSPACE);	\
681 		eol_num = num;				\
682 	}						\
683 }
684 
685 #define REFRESH_TO_EOL() {			\
686 	if (num < eol_num) {			\
687 		wlen = eol_num - num;		\
688 		putnstr(buf + num, wlen);	\
689 		num = eol_num;			\
690 	}					\
691 }
692 
693 static void cread_add_char(char ichar, int insert, unsigned long *num,
694 	       unsigned long *eol_num, char *buf, unsigned long len)
695 {
696 	unsigned long wlen;
697 
698 	/* room ??? */
699 	if (insert || *num == *eol_num) {
700 		if (*eol_num > len - 1) {
701 			getcmd_cbeep();
702 			return;
703 		}
704 		(*eol_num)++;
705 	}
706 
707 	if (insert) {
708 		wlen = *eol_num - *num;
709 		if (wlen > 1) {
710 			memmove(&buf[*num+1], &buf[*num], wlen-1);
711 		}
712 
713 		buf[*num] = ichar;
714 		putnstr(buf + *num, wlen);
715 		(*num)++;
716 		while (--wlen) {
717 			getcmd_putch(CTL_BACKSPACE);
718 		}
719 	} else {
720 		/* echo the character */
721 		wlen = 1;
722 		buf[*num] = ichar;
723 		putnstr(buf + *num, wlen);
724 		(*num)++;
725 	}
726 }
727 
728 static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
729 	      unsigned long *eol_num, char *buf, unsigned long len)
730 {
731 	while (strsize--) {
732 		cread_add_char(*str, insert, num, eol_num, buf, len);
733 		str++;
734 	}
735 }
736 
737 static int cread_line(char *buf, unsigned int *len)
738 {
739 	unsigned long num = 0;
740 	unsigned long eol_num = 0;
741 	unsigned long rlen;
742 	unsigned long wlen;
743 	char ichar;
744 	int insert = 1;
745 	int esc_len = 0;
746 	int rc = 0;
747 	char esc_save[8];
748 
749 	while (1) {
750 		rlen = 1;
751 		ichar = getcmd_getch();
752 
753 		if ((ichar == '\n') || (ichar == '\r')) {
754 			putc('\n');
755 			break;
756 		}
757 
758 		/*
759 		 * handle standard linux xterm esc sequences for arrow key, etc.
760 		 */
761 		if (esc_len != 0) {
762 			if (esc_len == 1) {
763 				if (ichar == '[') {
764 					esc_save[esc_len] = ichar;
765 					esc_len = 2;
766 				} else {
767 					cread_add_str(esc_save, esc_len, insert,
768 						      &num, &eol_num, buf, *len);
769 					esc_len = 0;
770 				}
771 				continue;
772 			}
773 
774 			switch (ichar) {
775 
776 			case 'D':	/* <- key */
777 				ichar = CTL_CH('b');
778 				esc_len = 0;
779 				break;
780 			case 'C':	/* -> key */
781 				ichar = CTL_CH('f');
782 				esc_len = 0;
783 				break;	/* pass off to ^F handler */
784 			case 'H':	/* Home key */
785 				ichar = CTL_CH('a');
786 				esc_len = 0;
787 				break;	/* pass off to ^A handler */
788 			case 'A':	/* up arrow */
789 				ichar = CTL_CH('p');
790 				esc_len = 0;
791 				break;	/* pass off to ^P handler */
792 			case 'B':	/* down arrow */
793 				ichar = CTL_CH('n');
794 				esc_len = 0;
795 				break;	/* pass off to ^N handler */
796 			default:
797 				esc_save[esc_len++] = ichar;
798 				cread_add_str(esc_save, esc_len, insert,
799 					      &num, &eol_num, buf, *len);
800 				esc_len = 0;
801 				continue;
802 			}
803 		}
804 
805 		switch (ichar) {
806 		case 0x1b:
807 			if (esc_len == 0) {
808 				esc_save[esc_len] = ichar;
809 				esc_len = 1;
810 			} else {
811 				puts("impossible condition #876\n");
812 				esc_len = 0;
813 			}
814 			break;
815 
816 		case CTL_CH('a'):
817 			BEGINNING_OF_LINE();
818 			break;
819 		case CTL_CH('c'):	/* ^C - break */
820 			*buf = '\0';	/* discard input */
821 			return (-1);
822 		case CTL_CH('f'):
823 			if (num < eol_num) {
824 				getcmd_putch(buf[num]);
825 				num++;
826 			}
827 			break;
828 		case CTL_CH('b'):
829 			if (num) {
830 				getcmd_putch(CTL_BACKSPACE);
831 				num--;
832 			}
833 			break;
834 		case CTL_CH('d'):
835 			if (num < eol_num) {
836 				wlen = eol_num - num - 1;
837 				if (wlen) {
838 					memmove(&buf[num], &buf[num+1], wlen);
839 					putnstr(buf + num, wlen);
840 				}
841 
842 				getcmd_putch(' ');
843 				do {
844 					getcmd_putch(CTL_BACKSPACE);
845 				} while (wlen--);
846 				eol_num--;
847 			}
848 			break;
849 		case CTL_CH('k'):
850 			ERASE_TO_EOL();
851 			break;
852 		case CTL_CH('e'):
853 			REFRESH_TO_EOL();
854 			break;
855 		case CTL_CH('o'):
856 			insert = !insert;
857 			break;
858 		case CTL_CH('x'):
859 			BEGINNING_OF_LINE();
860 			ERASE_TO_EOL();
861 			break;
862 		case DEL:
863 		case DEL7:
864 		case 8:
865 			if (num) {
866 				wlen = eol_num - num;
867 				num--;
868 				memmove(&buf[num], &buf[num+1], wlen);
869 				getcmd_putch(CTL_BACKSPACE);
870 				putnstr(buf + num, wlen);
871 				getcmd_putch(' ');
872 				do {
873 					getcmd_putch(CTL_BACKSPACE);
874 				} while (wlen--);
875 				eol_num--;
876 			}
877 			break;
878 		case CTL_CH('p'):
879 		case CTL_CH('n'):
880 		{
881 			char * hline;
882 
883 			esc_len = 0;
884 
885 			if (ichar == CTL_CH('p'))
886 				hline = hist_prev();
887 			else
888 				hline = hist_next();
889 
890 			if (!hline) {
891 				getcmd_cbeep();
892 				continue;
893 			}
894 
895 			/* nuke the current line */
896 			/* first, go home */
897 			BEGINNING_OF_LINE();
898 
899 			/* erase to end of line */
900 			ERASE_TO_EOL();
901 
902 			/* copy new line into place and display */
903 			strcpy(buf, hline);
904 			eol_num = strlen(buf);
905 			REFRESH_TO_EOL();
906 			continue;
907 		}
908 		default:
909 			cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
910 			break;
911 		}
912 	}
913 	*len = eol_num;
914 	buf[eol_num] = '\0';	/* lose the newline */
915 
916 	if (buf[0] && buf[0] != CREAD_HIST_CHAR)
917 		cread_add_to_hist(buf);
918 	hist_cur = hist_add_idx;
919 
920 	return (rc);
921 }
922 
923 #endif /* CONFIG_CMDLINE_EDITING */
924 
925 /****************************************************************************/
926 
927 /*
928  * Prompt for input and read a line.
929  * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
930  * time out when time goes past endtime (timebase time in ticks).
931  * Return:	number of read characters
932  *		-1 if break
933  *		-2 if timed out
934  */
935 int readline (const char *const prompt)
936 {
937 #ifdef CONFIG_CMDLINE_EDITING
938 	char *p = console_buffer;
939 	unsigned int len=MAX_CMDBUF_SIZE;
940 	static int initted = 0;
941 
942 	if (!initted) {
943 		hist_init();
944 		initted = 1;
945 	}
946 
947 	puts (prompt);
948 
949 	cread_line(p, &len);
950 	return len;
951 #else
952 	char   *p = console_buffer;
953 	int	n = 0;				/* buffer index		*/
954 	int	plen = 0;			/* prompt length	*/
955 	int	col;				/* output column cnt	*/
956 	char	c;
957 
958 	/* print prompt */
959 	if (prompt) {
960 		plen = strlen (prompt);
961 		puts (prompt);
962 	}
963 	col = plen;
964 
965 	for (;;) {
966 #ifdef CONFIG_BOOT_RETRY_TIME
967 		while (!tstc()) {	/* while no incoming data */
968 			if (retry_time >= 0 && get_ticks() > endtime)
969 				return (-2);	/* timed out */
970 		}
971 #endif
972 		WATCHDOG_RESET();		/* Trigger watchdog, if needed */
973 
974 #ifdef CONFIG_SHOW_ACTIVITY
975 		while (!tstc()) {
976 			extern void show_activity(int arg);
977 			show_activity(0);
978 		}
979 #endif
980 		c = getc();
981 
982 		/*
983 		 * Special character handling
984 		 */
985 		switch (c) {
986 		case '\r':				/* Enter		*/
987 		case '\n':
988 			*p = '\0';
989 			puts ("\r\n");
990 			return (p - console_buffer);
991 
992 		case '\0':				/* nul			*/
993 			continue;
994 
995 		case 0x03:				/* ^C - break		*/
996 			console_buffer[0] = '\0';	/* discard input */
997 			return (-1);
998 
999 		case 0x15:				/* ^U - erase line	*/
1000 			while (col > plen) {
1001 				puts (erase_seq);
1002 				--col;
1003 			}
1004 			p = console_buffer;
1005 			n = 0;
1006 			continue;
1007 
1008 		case 0x17:				/* ^W - erase word 	*/
1009 			p=delete_char(console_buffer, p, &col, &n, plen);
1010 			while ((n > 0) && (*p != ' ')) {
1011 				p=delete_char(console_buffer, p, &col, &n, plen);
1012 			}
1013 			continue;
1014 
1015 		case 0x08:				/* ^H  - backspace	*/
1016 		case 0x7F:				/* DEL - backspace	*/
1017 			p=delete_char(console_buffer, p, &col, &n, plen);
1018 			continue;
1019 
1020 		default:
1021 			/*
1022 			 * Must be a normal character then
1023 			 */
1024 			if (n < CFG_CBSIZE-2) {
1025 				if (c == '\t') {	/* expand TABs		*/
1026 #ifdef CONFIG_AUTO_COMPLETE
1027 					/* if auto completion triggered just continue */
1028 					*p = '\0';
1029 					if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
1030 						p = console_buffer + n;	/* reset */
1031 						continue;
1032 					}
1033 #endif
1034 					puts (tab_seq+(col&07));
1035 					col += 8 - (col&07);
1036 				} else {
1037 					++col;		/* echo input		*/
1038 					putc (c);
1039 				}
1040 				*p++ = c;
1041 				++n;
1042 			} else {			/* Buffer full		*/
1043 				putc ('\a');
1044 			}
1045 		}
1046 	}
1047 #endif /* CONFIG_CMDLINE_EDITING */
1048 }
1049 
1050 /****************************************************************************/
1051 
1052 #ifndef CONFIG_CMDLINE_EDITING
1053 static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1054 {
1055 	char *s;
1056 
1057 	if (*np == 0) {
1058 		return (p);
1059 	}
1060 
1061 	if (*(--p) == '\t') {			/* will retype the whole line	*/
1062 		while (*colp > plen) {
1063 			puts (erase_seq);
1064 			(*colp)--;
1065 		}
1066 		for (s=buffer; s<p; ++s) {
1067 			if (*s == '\t') {
1068 				puts (tab_seq+((*colp) & 07));
1069 				*colp += 8 - ((*colp) & 07);
1070 			} else {
1071 				++(*colp);
1072 				putc (*s);
1073 			}
1074 		}
1075 	} else {
1076 		puts (erase_seq);
1077 		(*colp)--;
1078 	}
1079 	(*np)--;
1080 	return (p);
1081 }
1082 #endif /* CONFIG_CMDLINE_EDITING */
1083 
1084 /****************************************************************************/
1085 
1086 int parse_line (char *line, char *argv[])
1087 {
1088 	int nargs = 0;
1089 
1090 #ifdef DEBUG_PARSER
1091 	printf ("parse_line: \"%s\"\n", line);
1092 #endif
1093 	while (nargs < CFG_MAXARGS) {
1094 
1095 		/* skip any white space */
1096 		while ((*line == ' ') || (*line == '\t')) {
1097 			++line;
1098 		}
1099 
1100 		if (*line == '\0') {	/* end of line, no more args	*/
1101 			argv[nargs] = NULL;
1102 #ifdef DEBUG_PARSER
1103 		printf ("parse_line: nargs=%d\n", nargs);
1104 #endif
1105 			return (nargs);
1106 		}
1107 
1108 		argv[nargs++] = line;	/* begin of argument string	*/
1109 
1110 		/* find end of string */
1111 		while (*line && (*line != ' ') && (*line != '\t')) {
1112 			++line;
1113 		}
1114 
1115 		if (*line == '\0') {	/* end of line, no more args	*/
1116 			argv[nargs] = NULL;
1117 #ifdef DEBUG_PARSER
1118 		printf ("parse_line: nargs=%d\n", nargs);
1119 #endif
1120 			return (nargs);
1121 		}
1122 
1123 		*line++ = '\0';		/* terminate current arg	 */
1124 	}
1125 
1126 	printf ("** Too many args (max. %d) **\n", CFG_MAXARGS);
1127 
1128 #ifdef DEBUG_PARSER
1129 	printf ("parse_line: nargs=%d\n", nargs);
1130 #endif
1131 	return (nargs);
1132 }
1133 
1134 /****************************************************************************/
1135 
1136 static void process_macros (const char *input, char *output)
1137 {
1138 	char c, prev;
1139 	const char *varname_start = NULL;
1140 	int inputcnt  = strlen (input);
1141 	int outputcnt = CFG_CBSIZE;
1142 	int state = 0;	/* 0 = waiting for '$'	*/
1143 			/* 1 = waiting for '(' or '{' */
1144 			/* 2 = waiting for ')' or '}' */
1145 			/* 3 = waiting for '''  */
1146 #ifdef DEBUG_PARSER
1147 	char *output_start = output;
1148 
1149 	printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
1150 #endif
1151 
1152 	prev = '\0';			/* previous character	*/
1153 
1154 	while (inputcnt && outputcnt) {
1155 	    c = *input++;
1156 	    inputcnt--;
1157 
1158 	    if (state!=3) {
1159 	    /* remove one level of escape characters */
1160 	    if ((c == '\\') && (prev != '\\')) {
1161 		if (inputcnt-- == 0)
1162 			break;
1163 		prev = c;
1164 		c = *input++;
1165 	    }
1166 	    }
1167 
1168 	    switch (state) {
1169 	    case 0:			/* Waiting for (unescaped) $	*/
1170 		if ((c == '\'') && (prev != '\\')) {
1171 			state = 3;
1172 			break;
1173 		}
1174 		if ((c == '$') && (prev != '\\')) {
1175 			state++;
1176 		} else {
1177 			*(output++) = c;
1178 			outputcnt--;
1179 		}
1180 		break;
1181 	    case 1:			/* Waiting for (	*/
1182 		if (c == '(' || c == '{') {
1183 			state++;
1184 			varname_start = input;
1185 		} else {
1186 			state = 0;
1187 			*(output++) = '$';
1188 			outputcnt--;
1189 
1190 			if (outputcnt) {
1191 				*(output++) = c;
1192 				outputcnt--;
1193 			}
1194 		}
1195 		break;
1196 	    case 2:			/* Waiting for )	*/
1197 		if (c == ')' || c == '}') {
1198 			int i;
1199 			char envname[CFG_CBSIZE], *envval;
1200 			int envcnt = input-varname_start-1; /* Varname # of chars */
1201 
1202 			/* Get the varname */
1203 			for (i = 0; i < envcnt; i++) {
1204 				envname[i] = varname_start[i];
1205 			}
1206 			envname[i] = 0;
1207 
1208 			/* Get its value */
1209 			envval = getenv (envname);
1210 
1211 			/* Copy into the line if it exists */
1212 			if (envval != NULL)
1213 				while ((*envval) && outputcnt) {
1214 					*(output++) = *(envval++);
1215 					outputcnt--;
1216 				}
1217 			/* Look for another '$' */
1218 			state = 0;
1219 		}
1220 		break;
1221 	    case 3:			/* Waiting for '	*/
1222 		if ((c == '\'') && (prev != '\\')) {
1223 			state = 0;
1224 		} else {
1225 			*(output++) = c;
1226 			outputcnt--;
1227 		}
1228 		break;
1229 	    }
1230 	    prev = c;
1231 	}
1232 
1233 	if (outputcnt)
1234 		*output = 0;
1235 
1236 #ifdef DEBUG_PARSER
1237 	printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
1238 		strlen(output_start), output_start);
1239 #endif
1240 }
1241 
1242 /****************************************************************************
1243  * returns:
1244  *	1  - command executed, repeatable
1245  *	0  - command executed but not repeatable, interrupted commands are
1246  *	     always considered not repeatable
1247  *	-1 - not executed (unrecognized, bootd recursion or too many args)
1248  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
1249  *           considered unrecognized)
1250  *
1251  * WARNING:
1252  *
1253  * We must create a temporary copy of the command since the command we get
1254  * may be the result from getenv(), which returns a pointer directly to
1255  * the environment data, which may change magicly when the command we run
1256  * creates or modifies environment variables (like "bootp" does).
1257  */
1258 
1259 int run_command (const char *cmd, int flag)
1260 {
1261 	cmd_tbl_t *cmdtp;
1262 	char cmdbuf[CFG_CBSIZE];	/* working copy of cmd		*/
1263 	char *token;			/* start of token in cmdbuf	*/
1264 	char *sep;			/* end of token (separator) in cmdbuf */
1265 	char finaltoken[CFG_CBSIZE];
1266 	char *str = cmdbuf;
1267 	char *argv[CFG_MAXARGS + 1];	/* NULL terminated	*/
1268 	int argc, inquotes;
1269 	int repeatable = 1;
1270 	int rc = 0;
1271 
1272 #ifdef DEBUG_PARSER
1273 	printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
1274 	puts (cmd ? cmd : "NULL");	/* use puts - string may be loooong */
1275 	puts ("\"\n");
1276 #endif
1277 
1278 	clear_ctrlc();		/* forget any previous Control C */
1279 
1280 	if (!cmd || !*cmd) {
1281 		return -1;	/* empty command */
1282 	}
1283 
1284 	if (strlen(cmd) >= CFG_CBSIZE) {
1285 		puts ("## Command too long!\n");
1286 		return -1;
1287 	}
1288 
1289 	strcpy (cmdbuf, cmd);
1290 
1291 	/* Process separators and check for invalid
1292 	 * repeatable commands
1293 	 */
1294 
1295 #ifdef DEBUG_PARSER
1296 	printf ("[PROCESS_SEPARATORS] %s\n", cmd);
1297 #endif
1298 	while (*str) {
1299 
1300 		/*
1301 		 * Find separator, or string end
1302 		 * Allow simple escape of ';' by writing "\;"
1303 		 */
1304 		for (inquotes = 0, sep = str; *sep; sep++) {
1305 			if ((*sep=='\'') &&
1306 			    (*(sep-1) != '\\'))
1307 				inquotes=!inquotes;
1308 
1309 			if (!inquotes &&
1310 			    (*sep == ';') &&	/* separator		*/
1311 			    ( sep != str) &&	/* past string start	*/
1312 			    (*(sep-1) != '\\'))	/* and NOT escaped	*/
1313 				break;
1314 		}
1315 
1316 		/*
1317 		 * Limit the token to data between separators
1318 		 */
1319 		token = str;
1320 		if (*sep) {
1321 			str = sep + 1;	/* start of command for next pass */
1322 			*sep = '\0';
1323 		}
1324 		else
1325 			str = sep;	/* no more commands for next pass */
1326 #ifdef DEBUG_PARSER
1327 		printf ("token: \"%s\"\n", token);
1328 #endif
1329 
1330 		/* find macros in this token and replace them */
1331 		process_macros (token, finaltoken);
1332 
1333 		/* Extract arguments */
1334 		if ((argc = parse_line (finaltoken, argv)) == 0) {
1335 			rc = -1;	/* no command at all */
1336 			continue;
1337 		}
1338 
1339 		/* Look up command in command table */
1340 		if ((cmdtp = find_cmd(argv[0])) == NULL) {
1341 			printf ("Unknown command '%s' - try 'help'\n", argv[0]);
1342 			rc = -1;	/* give up after bad command */
1343 			continue;
1344 		}
1345 
1346 		/* found - check max args */
1347 		if (argc > cmdtp->maxargs) {
1348 			printf ("Usage:\n%s\n", cmdtp->usage);
1349 			rc = -1;
1350 			continue;
1351 		}
1352 
1353 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
1354 		/* avoid "bootd" recursion */
1355 		if (cmdtp->cmd == do_bootd) {
1356 #ifdef DEBUG_PARSER
1357 			printf ("[%s]\n", finaltoken);
1358 #endif
1359 			if (flag & CMD_FLAG_BOOTD) {
1360 				puts ("'bootd' recursion detected\n");
1361 				rc = -1;
1362 				continue;
1363 			} else {
1364 				flag |= CMD_FLAG_BOOTD;
1365 			}
1366 		}
1367 #endif	/* CFG_CMD_BOOTD */
1368 
1369 		/* OK - call function to do the command */
1370 		if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
1371 			rc = -1;
1372 		}
1373 
1374 		repeatable &= cmdtp->repeatable;
1375 
1376 		/* Did the user stop this? */
1377 		if (had_ctrlc ())
1378 			return 0;	/* if stopped then not repeatable */
1379 	}
1380 
1381 	return rc ? rc : repeatable;
1382 }
1383 
1384 /****************************************************************************/
1385 
1386 #if (CONFIG_COMMANDS & CFG_CMD_RUN)
1387 int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
1388 {
1389 	int i;
1390 
1391 	if (argc < 2) {
1392 		printf ("Usage:\n%s\n", cmdtp->usage);
1393 		return 1;
1394 	}
1395 
1396 	for (i=1; i<argc; ++i) {
1397 		char *arg;
1398 
1399 		if ((arg = getenv (argv[i])) == NULL) {
1400 			printf ("## Error: \"%s\" not defined\n", argv[i]);
1401 			return 1;
1402 		}
1403 #ifndef CFG_HUSH_PARSER
1404 		if (run_command (arg, flag) == -1)
1405 			return 1;
1406 #else
1407 		if (parse_string_outer(arg,
1408 		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
1409 			return 1;
1410 #endif
1411 	}
1412 	return 0;
1413 }
1414 #endif	/* CFG_CMD_RUN */
1415