Merge branch 'support_for_ar9341'
[oweals/u-boot_mod.git] / u-boot / common / main.c
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /* #define      DEBUG   */
25
26 #include <common.h>
27 #include <command.h>
28
29 #ifdef CONFIG_SILENT_CONSOLE
30 DECLARE_GLOBAL_DATA_PTR;
31 #endif
32
33 extern int reset_button_status(void);
34 extern void all_led_on(void);
35 extern void all_led_off(void);
36 extern int NetLoopHttpd(void);
37
38 #define MAX_DELAY_STOP_STR 32
39
40 static char *delete_char(char *buffer, char *p, int *colp, int *np, int plen);
41 static int parse_line(char *, char *[]);
42 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
43 static int abortboot(int);
44 #endif
45
46 char console_buffer[CFG_CBSIZE]; /* console I/O buffer  */
47 static char erase_seq[] = "\b \b"; /* erase sequence    */
48 static char tab_seq[] = "        "; /* used to expand TABs      */
49
50 /***************************************************************************
51  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
52  * returns: 0 -  no key string, allow autoboot
53  *          1 - got key string, abort
54  */
55 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
56 static __inline__ int abortboot(int bootdelay){
57         int abort = 0;
58
59 #ifdef CONFIG_SILENT_CONSOLE
60         if(gd->flags & GD_FLG_SILENT){
61                 /* Restore serial console */
62                 console_assign(stdout, "serial");
63                 console_assign(stderr, "serial");
64         }
65 #endif
66
67 #ifdef CONFIG_MENUPROMPT
68         printf(CONFIG_MENUPROMPT, bootdelay);
69 #else
70         printf("Hit any key to stop autoboot: %d ", bootdelay);
71 #endif
72
73         while((bootdelay > 0) && (!abort)){
74                 int i;
75
76                 --bootdelay;
77
78                 /* delay 100 * 10ms */
79                 for(i = 0; !abort && i < 100; ++i){
80
81                         /* we got a key press   */
82                         if(tstc()){
83                                 /* don't auto boot      */
84                                 abort = 1;
85                                 /* no more delay        */
86                                 bootdelay = 0;
87                                 /* consume input        */
88                                 (void) getc();
89                                 break;
90                         }
91                         udelay(10000);
92                 }
93
94                 printf("\b\b%d ", bootdelay);
95         }
96
97         printf("\n\n");
98
99 #ifdef CONFIG_SILENT_CONSOLE
100         if(abort){
101                 /* permanently enable normal console output */
102                 gd->flags &= ~(GD_FLG_SILENT);
103         } else if(gd->flags & GD_FLG_SILENT){
104                 /* Restore silent console */
105                 console_assign(stdout, "nulldev");
106                 console_assign(stderr, "nulldev");
107         }
108 #endif
109
110         return(abort);
111 }
112 #endif  /* CONFIG_BOOTDELAY >= 0  */
113
114 /****************************************************************************/
115
116 void main_loop(void){
117         static char lastcommand[CFG_CBSIZE] = { 0, };
118         int len;
119         int rc = 1;
120         int flag;
121         int counter = 0;
122
123 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
124         char *s;
125         int bootdelay;
126
127         // get boot delay (seconds)
128         s = getenv("bootdelay");
129         bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
130
131         // get boot command
132         s = getenv("bootcmd");
133
134 #if !defined(CONFIG_BOOTCOMMAND)
135 #error "CONFIG_BOOTCOMMAND not defined!"
136 #endif
137
138         if(!s){
139                 setenv("bootcmd", CONFIG_BOOTCOMMAND);
140         }
141
142         s = getenv("bootcmd");
143
144         // are we going to run web failsafe mode, U-Boot console, U-Boot netconsole or just boot command?
145         if(reset_button_status()){
146
147                 // wait 0,5s
148                 milisecdelay(500);
149
150                 printf("Press reset button for at least:\n- %d sec. to run web failsafe mode\n- %d sec. to run U-Boot console\n- %d sec. to run U-Boot netconsole\n\n",
151                                 CONFIG_DELAY_TO_AUTORUN_HTTPD,
152                                 CONFIG_DELAY_TO_AUTORUN_CONSOLE,
153                                 CONFIG_DELAY_TO_AUTORUN_NETCONSOLE);
154
155                 printf("Reset button is pressed for: %2d ", counter);
156
157                 while(reset_button_status()){
158
159                         // LED ON and wait 0,15s
160                         all_led_on();
161                         milisecdelay(150);
162
163                         // LED OFF and wait 0,85s
164                         all_led_off();
165                         milisecdelay(850);
166
167                         counter++;
168
169                         // how long the button is pressed?
170                         printf("\b\b\b%2d ", counter);
171
172                         if(!reset_button_status()){
173                                 break;
174                         }
175
176                         if(counter >= CONFIG_MAX_BUTTON_PRESSING){
177                                 break;
178                         }
179                 }
180
181                 all_led_off();
182
183                 if(counter > 0){
184
185                         // run web failsafe mode
186                         if(counter >= CONFIG_DELAY_TO_AUTORUN_HTTPD && counter < CONFIG_DELAY_TO_AUTORUN_CONSOLE){
187                                 printf("\n\nButton was pressed for %d sec...\nHTTP server is starting for firmware update...\n\n", counter);
188                                 NetLoopHttpd();
189                                 bootdelay = -1;
190                         } else if(counter >= CONFIG_DELAY_TO_AUTORUN_CONSOLE && counter < CONFIG_DELAY_TO_AUTORUN_NETCONSOLE){
191                                 printf("\n\nButton was pressed for %d sec...\nStarting U-Boot console...\n\n", counter);
192                                 bootdelay = -1;
193                         } else if(counter >= CONFIG_DELAY_TO_AUTORUN_NETCONSOLE){
194                                 printf("\n\nButton was pressed for %d sec...\nStarting U-Boot netconsole...\n\n", counter);
195                                 bootdelay = -1;
196                                 run_command("startnc", 0);
197                         } else {
198                                 printf("\n\n## Error: button wasn't pressed long enough!\nContinuing normal boot...\n\n");
199                         }
200
201                 } else {
202                         printf("\n\n## Error: button wasn't pressed long enough!\nContinuing normal boot...\n\n");
203                 }
204
205         }
206
207         if(bootdelay >= 0 && s && !abortboot(bootdelay)){
208
209                 // try to boot
210                 run_command(s, 0);
211
212                 // something goes wrong!
213                 printf("\n## Error: failed to execute 'bootcmd'!\nHTTP server is starting for firmware update...\n\n");
214                 NetLoopHttpd();
215         }
216 #endif  /* CONFIG_BOOTDELAY */
217
218         /*
219          * Main Loop for Monitor Command Processing
220          */
221         for(;;){
222                 len = readline(CFG_PROMPT);
223
224                 flag = 0; /* assume no special flags for now */
225                 if(len > 0){
226                         strcpy(lastcommand, console_buffer);
227                 } else if(len == 0){
228                         flag |= CMD_FLAG_REPEAT;
229                 }
230
231                 if(len == -1){
232                         puts("<INTERRUPT>\n");
233                 } else {
234                         rc = run_command(lastcommand, flag);
235                 }
236
237                 if(rc <= 0){
238                         /* invalid command or not repeatable, forget it */
239                         lastcommand[0] = 0;
240                 }
241         }
242 }
243
244 /****************************************************************************/
245
246 /*
247  * Prompt for input and read a line.
248  * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
249  * time out when time goes past endtime (timebase time in ticks).
250  * Return:      number of read characters
251  *              -1 if break
252  *              -2 if timed out
253  */
254 int readline(const char * const prompt){
255         char *p = console_buffer;
256         int n = 0; /* buffer index              */
257         int plen = 0; /* prompt length  */
258         int col; /* output column cnt   */
259         char c;
260
261         /* print prompt */
262         if(prompt){
263                 plen = strlen(prompt);
264                 puts(prompt);
265         }
266         col = plen;
267
268         for(;;){
269                 c = getc();
270
271                 /*
272                  * Special character handling
273                  */
274                 switch(c){
275                         case '\r': /* Enter             */
276                         case '\n':
277                                 *p = '\0';
278                                 puts("\r\n");
279                                 return(p - console_buffer);
280
281                         case '\0': /* nul                       */
282                                 continue;
283
284                         case 0x03: /* ^C - break                */
285                                 console_buffer[0] = '\0'; /* discard input */
286                                 return(-1);
287
288                         case 0x15: /* ^U - erase line   */
289                                 while(col > plen){
290                                         puts(erase_seq);
291                                         --col;
292                                 }
293                                 p = console_buffer;
294                                 n = 0;
295                                 continue;
296
297                         case 0x17: /* ^W - erase word   */
298                                 p = delete_char(console_buffer, p, &col, &n, plen);
299                                 while((n > 0) && (*p != ' ')){
300                                         p = delete_char(console_buffer, p, &col, &n, plen);
301                                 }
302                                 continue;
303
304                         case 0x08: /* ^H  - backspace   */
305                         case 0x7F: /* DEL - backspace   */
306                                 p = delete_char(console_buffer, p, &col, &n, plen);
307                                 continue;
308
309                         default:
310                                 /*
311                                  * Must be a normal character then
312                                  */
313                                 if(n < CFG_CBSIZE - 2){
314                                         if(c == '\t'){ /* expand TABs           */
315                                                 puts(tab_seq + (col & 07));
316                                                 col += 8 - (col & 07);
317                                         } else {
318                                                 ++col; /* echo input            */
319                                                 putc(c);
320                                         }
321                                         *p++ = c;
322                                         ++n;
323                                 } else { /* Buffer full         */
324                                         putc('\a');
325                                 }
326                 }
327         }
328 }
329
330 /****************************************************************************/
331
332 static char * delete_char(char *buffer, char *p, int *colp, int *np, int plen){
333         char *s;
334
335         if(*np == 0){
336                 return(p);
337         }
338
339         if(*(--p) == '\t'){ /* will retype the whole line       */
340                 while(*colp > plen){
341                         puts(erase_seq);
342                         (*colp)--;
343                 }
344                 for(s = buffer; s < p; ++s){
345                         if(*s == '\t'){
346                                 puts(tab_seq + ((*colp) & 07));
347                                 *colp += 8 - ((*colp) & 07);
348                         } else {
349                                 ++(*colp);
350                                 putc(*s);
351                         }
352                 }
353         } else {
354                 puts(erase_seq);
355                 (*colp)--;
356         }
357         (*np)--;
358         return(p);
359 }
360
361 /****************************************************************************/
362
363 int parse_line(char *line, char *argv[]){
364         int nargs = 0;
365
366         while(nargs < CFG_MAXARGS){
367
368                 /* skip any white space */
369                 while((*line == ' ') || (*line == '\t')){
370                         ++line;
371                 }
372
373                 if(*line == '\0'){ /* end of line, no more args */
374                         argv[nargs] = NULL;
375                         return(nargs);
376                 }
377
378                 argv[nargs++] = line; /* begin of argument string       */
379
380                 /* find end of string */
381                 while(*line && (*line != ' ') && (*line != '\t')){
382                         ++line;
383                 }
384
385                 if(*line == '\0'){ /* end of line, no more args */
386                         argv[nargs] = NULL;
387                         return(nargs);
388                 }
389
390                 *line++ = '\0'; /* terminate current arg         */
391         }
392
393         printf("## Error: too many args (max. %d)\n", CFG_MAXARGS);
394
395         return(nargs);
396 }
397
398 /****************************************************************************/
399
400 static void process_macros(const char *input, char *output){
401         char c, prev;
402         const char *varname_start = NULL;
403         int inputcnt = strlen(input);
404         int outputcnt = CFG_CBSIZE;
405         int state = 0; /* 0 = waiting for '$'   */
406         /* 1 = waiting for '(' or '{' */
407         /* 2 = waiting for ')' or '}' */
408         /* 3 = waiting for '''  */
409
410         prev = '\0'; /* previous character      */
411
412         while(inputcnt && outputcnt){
413                 c = *input++;
414                 inputcnt--;
415
416                 if(state != 3){
417                         /* remove one level of escape characters */
418                         if((c == '\\') && (prev != '\\')){
419                                 if(inputcnt-- == 0){
420                                         break;
421                                 }
422
423                                 prev = c;
424                                 c = *input++;
425                         }
426                 }
427
428                 switch(state){
429                         case 0: /* Waiting for (unescaped) $    */
430                                 if((c == '\'') && (prev != '\\')){
431                                         state = 3;
432                                         break;
433                                 }
434                                 if((c == '$') && (prev != '\\')){
435                                         state++;
436                                 } else {
437                                         *(output++) = c;
438                                         outputcnt--;
439                                 }
440                                 break;
441                         case 1: /* Waiting for (        */
442                                 if(c == '(' || c == '{'){
443                                         state++;
444                                         varname_start = input;
445                                 } else {
446                                         state = 0;
447                                         *(output++) = '$';
448                                         outputcnt--;
449
450                                         if(outputcnt){
451                                                 *(output++) = c;
452                                                 outputcnt--;
453                                         }
454                                 }
455                                 break;
456                         case 2: /* Waiting for )        */
457                                 if(c == ')' || c == '}'){
458                                         int i;
459                                         char envname[CFG_CBSIZE], *envval;
460                                         int envcnt = input - varname_start - 1; /* Varname # of chars */
461
462                                         /* Get the varname */
463                                         for(i = 0; i < envcnt; i++){
464                                                 envname[i] = varname_start[i];
465                                         }
466                                         envname[i] = 0;
467
468                                         /* Get its value */
469                                         envval = getenv(envname);
470
471                                         /* Copy into the line if it exists */
472                                         if(envval != NULL){
473                                                 while((*envval) && outputcnt){
474                                                         *(output++) = *(envval++);
475                                                         outputcnt--;
476                                                 }
477                                         }
478                                         /* Look for another '$' */
479                                         state = 0;
480                                 }
481                                 break;
482                         case 3: /* Waiting for '        */
483                                 if((c == '\'') && (prev != '\\')){
484                                         state = 0;
485                                 } else {
486                                         *(output++) = c;
487                                         outputcnt--;
488                                 }
489                                 break;
490                 }
491                 prev = c;
492         }
493
494         if(outputcnt){
495                 *output = 0;
496         }
497 }
498
499 /****************************************************************************
500  * returns:
501  *      1  - command executed, repeatable
502  *      0  - command executed but not repeatable, interrupted commands are
503  *           always considered not repeatable
504  *      -1 - not executed (unrecognized, bootd recursion or too many args)
505  *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
506  *           considered unrecognized)
507  *
508  * WARNING:
509  *
510  * We must create a temporary copy of the command since the command we get
511  * may be the result from getenv(), which returns a pointer directly to
512  * the environment data, which may change magicly when the command we run
513  * creates or modifies environment variables (like "bootp" does).
514  */
515
516 int run_command(const char *cmd, int flag){
517         cmd_tbl_t *cmdtp;
518         char cmdbuf[CFG_CBSIZE]; /* working copy of cmd         */
519         char *token; /* start of token in cmdbuf        */
520         char *sep; /* end of token (separator) in cmdbuf */
521         char finaltoken[CFG_CBSIZE];
522         char *str = cmdbuf;
523         char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
524         int argc, inquotes;
525         int repeatable = 1;
526         int rc = 0;
527
528         clear_ctrlc(); /* forget any previous Control C */
529
530         if(!cmd || !*cmd){
531                 return(-1); /* empty command */
532         }
533
534         if(strlen(cmd) >= CFG_CBSIZE){
535                 puts("## Error: command too long!\n");
536                 return(-1);
537         }
538
539         strcpy(cmdbuf, cmd);
540
541         /* Process separators and check for invalid
542          * repeatable commands
543          */
544         while(*str){
545
546                 /*
547                  * Find separator, or string end
548                  * Allow simple escape of ';' by writing "\;"
549                  */
550                 for(inquotes = 0, sep = str; *sep; sep++){
551                         if((*sep == '\'') && (*(sep - 1) != '\\')){
552                                 inquotes = !inquotes;
553                         }
554
555                         if(!inquotes && (*sep == ';') && (sep != str) && (*(sep - 1) != '\\')){
556                                 break;
557                         }
558                 }
559
560                 /*
561                  * Limit the token to data between separators
562                  */
563                 token = str;
564                 if(*sep){
565                         str = sep + 1; /* start of command for next pass */
566                         *sep = '\0';
567                 } else {
568                         str = sep; /* no more commands for next pass */
569                 }
570
571                 /* find macros in this token and replace them */
572                 process_macros(token, finaltoken);
573
574                 /* Extract arguments */
575                 if((argc = parse_line(finaltoken, argv)) == 0){
576                         rc = -1; /* no command at all */
577                         continue;
578                 }
579
580                 /* Look up command in command table */
581                 if((cmdtp = find_cmd(argv[0])) == NULL){
582                         printf("## Error: unknown command '%s' - try 'help'\n\n", argv[0]);
583                         rc = -1; /* give up after bad command */
584                         continue;
585                 }
586
587                 /* found - check max args */
588                 if(argc > cmdtp->maxargs){
589 #ifdef CFG_LONGHELP
590                         if(cmdtp->help != NULL){
591                                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
592                         } else {
593                                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
594                         }
595 #else
596                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
597 #endif
598                         rc = -1;
599                         continue;
600                 }
601
602                 /* OK - call function to do the command */
603                 if((cmdtp->cmd)(cmdtp, flag, argc, argv) != 0){
604                         rc = -1;
605                 }
606
607                 repeatable &= cmdtp->repeatable;
608
609                 /* Did the user stop this? */
610                 if(had_ctrlc()){ /* if stopped then not repeatable */
611                         return(0);
612                 }
613         }
614
615         return(rc ? rc : repeatable);
616 }
617
618 /****************************************************************************/
619
620 #if (CONFIG_COMMANDS & CFG_CMD_RUN)
621 int do_run(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
622         int i;
623
624         if(argc < 2){
625 #ifdef CFG_LONGHELP
626                 if(cmdtp->help != NULL){
627                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
628                 } else {
629                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
630                 }
631 #else
632                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
633 #endif
634                 return(1);
635         }
636
637         for(i=1; i<argc; ++i){
638                 char *arg;
639
640                 if((arg = getenv(argv[i])) == NULL){
641                         printf("## Error: \"%s\" not defined\n", argv[i]);
642                         return(1);
643                 }
644
645                 if(run_command(arg, flag) == -1){
646                         return(1);
647                 }
648         }
649
650         return(0);
651 }
652 #endif  /* CFG_CMD_RUN */