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