2012-02-02

u-boot common/main.c

接下来我们主要分析main_loop()
common/main.c:
void main_loop (void)
{
#ifndef CFG_HUSH_PARSER
    static char lastcommand[CFG_CBSIZE] = { 0, };
    int len;
    int rc = 1;
    int flag;
#endif

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    char *s;
    int bootdelay;
#endif
#ifdef CONFIG_PREBOOT
    char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT
    unsigned long bootcount = 0;
    unsigned long bootlimit = 0;
    char *bcs;
    char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)   /*smdk2410没定义*/
    ulong bmp = 0;     /* default bitmap */
    extern int trab_vfd (ulong bitmap);

#ifdef CONFIG_MODEM_SUPPORT
    if (do_mdm_init)
        bmp = 1;    /* alternate bitmap */
#endif
    trab_vfd (bmp);
#endif  /* CONFIG_VFD && VFD_TEST_LOGO */

#ifdef CONFIG_BOOTCOUNT_LIMIT   /*smdk2410没定义*/
    bootcount = bootcount_load();
    bootcount++;
    bootcount_store (bootcount);
    sprintf (bcs_set, "%lu", bootcount);
    setenv ("bootcount", bcs_set);
    bcs = getenv ("bootlimit");
    bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_MODEM_SUPPORT /*smdk2410没定义*/
    debug ("DEBUG: main_loop:   do_mdm_init=%d/n", do_mdm_init);
    if (do_mdm_init) {
        uchar *str = strdup(getenv("mdm_cmd"));
        setenv ("preboot", str);  /* set or delete definition */
        if (str != NULL)
            free (str);
        mdm_init(); /* wait for modem connection */
    }
#endif  /* CONFIG_MODEM_SUPPORT */

#ifdef CONFIG_VERSION_VARIABLE /*smdk2410没定义*/
    {
        extern char version_string[];

        setenv ("ver", version_string);  /* set version variable */
    }
#endif /* CONFIG_VERSION_VARIABLE */

#ifdef CFG_HUSH_PARSER /*smdk2410没定义*/
    u_boot_hush_start ();
#endif

#ifdef CONFIG_AUTO_COMPLETE /*smdk2410没定义*/
    install_auto_complete();
#endif

#ifdef CONFIG_PREBOOT /*smdk2410没定义*/
    if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED /*smdk2410没定义*/
        int prev = disable_ctrlc(1);   /* disable Control C checking */
# endif

# ifndef CFG_HUSH_PARSER /*smdk2410没定义*/
        run_command (p, 0);
# else
        parse_string_outer(p, FLAG_PARSE_SEMICOLON |
                    FLAG_EXIT_FROM_LOOP);
# endif

# ifdef CONFIG_AUTOBOOT_KEYED /*smdk2410没定义*/
        disable_ctrlc(prev);   /* restore Control C checking */
# endif
    }
#endif /* CONFIG_PREBOOT */

/**/
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    s = getenv ("bootdelay");
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

    debug ("### main_loop entered: bootdelay=%d/n/n", bootdelay);

# ifdef CONFIG_BOOT_RETRY_TIME
    init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */

#ifdef CONFIG_BOOTCOUNT_LIMIT
    if (bootlimit && (bootcount > bootlimit)) {
        printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd./n",
                (unsigned)bootlimit);
        s = getenv ("altbootcmd");
    }
    else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
        s = getenv ("bootcmd");  /*smdk2410下这个环境变量是空的*/

    debug ("### main_loop: bootcmd=/"%s/"/n", s ? s : "<UNDEFINED>");

    if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
        int prev = disable_ctrlc(1);   /* disable Control C checking */
# endif

# ifndef CFG_HUSH_PARSER
        run_command (s, 0);
# else
        parse_string_outer(s, FLAG_PARSE_SEMICOLON |
                    FLAG_EXIT_FROM_LOOP);
# endif

# ifdef CONFIG_AUTOBOOT_KEYED
        disable_ctrlc(prev);   /* restore Control C checking */
# endif
    }

# ifdef CONFIG_MENUKEY
    if (menukey == CONFIG_MENUKEY) {
        s = getenv("menucmd");
        if (s) {
# ifndef CFG_HUSH_PARSER
        run_command (s, 0);
# else
        parse_string_outer(s, FLAG_PARSE_SEMICOLON |
                    FLAG_EXIT_FROM_LOOP);
# endif
        }
    }
#endif /* CONFIG_MENUKEY */
#endif  /* CONFIG_BOOTDELAY */

#ifdef CONFIG_AMIGAONEG3SE
    {
        extern void video_banner(void);
        video_banner();
    }
#endif

    /*
     * Main Loop for Monitor Command Processing
     */
     /*
      * 最核心的就是下面这个死循环了
      */
#ifdef CFG_HUSH_PARSER
    parse_file_outer();
    /* This point is never reached */
    for (;;);
#else
    for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
        if (rc >= 0) {
            /* Saw enough of a valid command to
             * restart the timeout.
             */
            reset_cmd_timeout();
        }
#endif
        len = readline (CFG_PROMPT);

        flag = 0;   /* assume no special flags for now */
        if (len > 0)
            strcpy (lastcommand, console_buffer);
        else if (len == 0)
            flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
        else if (len == -2) {
            /* -2 means timed out, retry autoboot
             */
            puts ("/nTimed out waiting for command/n");
# ifdef CONFIG_RESET_TO_RETRY
            /* Reinit board to run initialization code again */
            do_reset (NULL, 0, 0, NULL);
# else
            return;     /* retry autoboot */
# endif
        }
#endif

        if (len == -1)
            puts ("<INTERRUPT>/n");
        else
            rc = run_command (lastcommand, flag);

        if (rc <= 0) {
            /* invalid command or not repeatable, forget it */
            lastcommand[0] = 0;
        }
    }
#endif /*CFG_HUSH_PARSER*/
}
该函数比较长,但核心就是不停的从串口获取命令并解析执行此命令, 这个功能就在函数尾部的那个死循环里, 我们重点就是分析这个循环。

先看readline()
common/main.c:
/****************************************************************************/
/*
 * Prompt for input and read a line.
 * If  CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
 * time out when time goes past endtime (timebase time in ticks).
 * Return:  number of read characters
 *      -1 if break
 *      -2 if timed out
 * 上面的注释说的很清楚了,就是提示用户输入命令,并读取这个命令
*/
int readline (const char *const prompt)
{
    char   *p = console_buffer;   /* console_buffer 是个全局变量*/
    int n = 0;             /* buffer index    */
    int plen = 0;          /* prompt length   */
    int col;               /* output column cnt   */
    char    c;

    /* print prompt */
    if (prompt) { /*如果要输出提示符,则输出*/
        plen = strlen (prompt);
        puts (prompt);  //前面分析过了
    }
    col = plen;

    for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME  /*sdmk2410没定义*/
        while (!tstc()) {  /* while no incoming data */
            if (retry_time >= 0 && get_ticks() > endtime)
                return (-2);    /* timed out */
        }
#endif
        WATCHDOG_RESET();      /* Trigger watchdog, if needed */

#ifdef CONFIG_SHOW_ACTIVITY /*sdmk2410没定义*/
        while (!tstc()) {
            extern void show_activity(int arg);
            show_activity(0);
        }
#endif
        c = getc();  /*从串口获取用户输入的命令*/

        /*
         * Special character handling
         */
        /*下面这个switch就是处理不同的字符了*/
        switch (c) {
        case '/r':             /* Enter        */
        case '/n':
            *p = '/0';
            puts ("/r/n");
            return (p - console_buffer);  /*输入结束*/

        case '/0':             /* nul          */  /*忽略,继续*/
            continue;

        case 0x03:             /* ^C - break*//*呵呵,linux下的ctrl+c功能*/
            console_buffer[0] = '/0';  /* discard input */
            return (-1);

        case 0x15:             /* ^U - erase line */ /*删除*/
            while (col > plen) {
                puts (erase_seq);
                --col;
            }
            p = console_buffer;
            n = 0;
            continue;

        case 0x17:             /* ^W - erase word *//*删除*/
            p=delete_char(console_buffer, p, &col, &n, plen);
            while ((n > 0) && (*p != ' ')) {
                p=delete_char(console_buffer, p, &col, &n, plen);
            }
            continue;

        case 0x08:             /* ^H  - backspace */
        case 0x7F:             /* DEL - backspace */
            p=delete_char(console_buffer, p, &col, &n, plen);/*删除*/
            continue;

        default:   /*获取常规字符*/
            /*
             * Must be a normal character then
             */
            if (n < CFG_CBSIZE-2) {
                if (c == '/t') {   /* expand TABs     */
#ifdef CONFIG_AUTO_COMPLETE
                   /* if auto completion triggered just continue */
                    /*自动补全功能,熟悉linux的肯定知道*/
                   *p = '/0';
                   if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
                       p = console_buffer + n; /* reset */
                       continue;
                   }
#endif
                   puts (tab_seq+(col&07));
                   col += 8 - (col&07);
                } else {
                    ++col;      /* echo input      */
                   putc (c);
                }
                *p++ = c;/*把字符保存在buffer*/
                ++n;
            } else {           /* Buffer full     */
                putc ('/a');
            }
        }
    }
}
上面这个函数就是提示用户输入,然后一直等待用户输入,指到用户输入完成, 然后获取用户数据,并存入全局变量console_buffer中。

再来回顾下那个for循环
common/main.c:
void main_loop (void)
{
……
#ifdef CFG_HUSH_PARSER
    parse_file_outer();
    /* This point is never reached */
    for (;;);
#else
    for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
        if (rc >= 0) {
            /* Saw enough of a valid command to
             * restart the timeout.
             */
            reset_cmd_timeout();
        }
#endif
        len = readline (CFG_PROMPT); /*获取用户下的command*/

        flag = 0;   /* assume no special flags for now */
        if (len > 0)
            strcpy (lastcommand, console_buffer);  /*command存入lastcommand*/
        else if (len == 0)
            flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
        else if (len == -2) {
            /* -2 means timed out, retry autoboot
             */
            puts ("/nTimed out waiting for command/n");
# ifdef CONFIG_RESET_TO_RETRY
            /* Reinit board to run initialization code again */
            do_reset (NULL, 0, 0, NULL);
# else
            return;     /* retry autoboot */
# endif
        }
#endif

        if (len == -1)
            puts ("<INTERRUPT>/n");
        else
            rc = run_command (lastcommand, flag); /*执行command*/

        if (rc <= 0) {
            /* invalid command or not repeatable, forget it */
            lastcommand[0] = 0;
        }
    }
#endif /*CFG_HUSH_PARSER*/
}
OK!核心中的核心就是run_command函数了,一猜就知道是用户执行所有用户下达命令的函数。Let’s go