Chinaunix首页 | 论坛 | 博客
  • 博客访问: 866205
  • 博文数量: 190
  • 博客积分: 7021
  • 博客等级: 少将
  • 技术积分: 1752
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-17 19:26
文章分类

全部博文(190)

文章存档

2014年(9)

2011年(32)

2010年(149)

我的朋友

分类: LINUX

2010-05-21 17:18:24

到了这里,就是vivi启动的最后阶段了。

#define DEFAULT_BOOT_DELAY 0x3000
void boot_or_vivi(void)
{
    char c;
    int ret;
    ulong boot_delay;

    #if 0
        boot_delay = get_param_value("boot_delay", &ret);
        if (ret) boot_delay = DEFAULT_BOOT_DELAY;
    #else
        boot_delay = DEFAULT_BOOT_DELAY;
    #endif
    /* If a value of boot_delay is zero,
     * unconditionally call vivi shell */

    if (boot_delay == 0) vivi_shell();


    /*
     * wait for a keystroke (or a button press if you want.)
     */

    printk("Press Return to start the LINUX now, any other key for vivi\n");
    c = awaitkey(boot_delay, NULL);
    if (((c != '\r') && (c != '\n') && (c != '\0'))) {
        printk("type \"help\" for help.\n");
        vivi_shell();
    }
    run_autoboot();

    return;
}

boot_or_vivi()---->vivi_shell()
              ---->run_autoboot()
我们可以看到,在这个函数中,要不就是运行vivi命令模式(vivi_shell),或者是自动启动(run_autoboot)
因为我们是定义了延时:#define DEFAULT_BOOT_DELAY 0x3000
先来看看awaitkey(boot_delay, NULL);函数:

/*
 * Reads and returns a character from the serial port
 * - Times out after delay iterations checking for presence of character
 * - Sets *error_p to UART error bits or - on timeout
 * - On timeout, sets *error_p to -1 and returns 0
 */

char awaitkey(unsigned long delay, int* error_p)
{
    return (do_getc(NULL, delay, error_p));
}


__u8 do_getc(vfuncp idler, unsigned long timeout, int *statp)
{
    __u8 c, rxstat;
    int do_timeout = timeout != 0;

    getc_errno = 0; /* reste errno */

    while(!SERIAL_CHAR_READY()) {

        if (do_timeout) {
            if (!timeout)
                break;
            timeout--;
        }

        if (idler)
            idler();
    }

    if (do_timeout && timeout == 0) {
        c = 0;
        rxstat = -1;
    } else {
        c = SERIAL_READ_CHAR();
        rxstat = SERIAL_READ_STATUS();
    }
    

    //如果有错误则进入下面的if语句,而且将错误返回给*statp
    if (rxstat) {
        getc_errno = rxstat;
        /*printk("RXSTAT error. status = 0x%08lx", rxstat);*/
        if (statp)
            *statp = rxstat;
    }
    return (c);
}

其中他们的作用就是第一个函数的英文部分。
就是在一定的时间内输入一个信号,要是超时没有输入,则返回0,如果在时间内有输入,则获取输入的字符,且检查错误。
分析完上面的细节,我们来看看vivi_shell();
vivi_shell的流程就是:
1:用户输入命令;
2:调用get_cmd()函数将命令保存在一个数组中,并反输出到串口终端,是用户能够看到;
3:在获取了命令之后则是要解析获取的命令,通过调用parseargs(buf, &argc, argv, &resid)函数
4:解析完成之后则是按照用户输入的命令,指向相应的函数execcmd(argc, (const char **)argv)


void
vivi_shell(void)
{
#ifdef CONFIG_SERIAL_TERM
    serial_term();
#else
#error there is no terminal.
#endif
}

对于vivi而言,串口是必不可少的。几乎所有的信号都是通过串口来传送的

void serial_term(void)
{
    char cmd_buf[MAX_CMDBUF_SIZE];

    for (;;) {
        printk("%s> ", prompt);

        getcmd(cmd_buf, MAX_CMDBUF_SIZE);

        /* execute a user command */
        if (cmd_buf[0])
            exec_string(cmd_buf);
    } 
}



serial_term()--->getcmd();
下面这个函数正好帮我们复习ASCII码表,还有c语言中的转义符。
我在c语言文件夹中已经添加了ASCII表和转义符的含义:

void getcmd(char *cmd_buf, unsigned int len)
{
    char curpos = 0; /* current position - index into cmd_buf */
    char c;
    int cmd_echo = 1;

    /* Clear out the buffer */
    memset(cmd_buf, 0, MAX_CMDBUF_SIZE);
        
    for (;;) {
        c = getc();
        switch (c) {
        case 0x08:    //退一格
        case 0x06:    //ACK
        case 0x07:    //BELL
        case 0x7E:    //~
        case 0x7F: /* backspace or delete */
            /* we're not at the beginning of the line */
            if (curpos) {
                curpos--;
                putc(0x08); /* go backwards */
                putc(' '); /* overwrite the char */
                putc(0x08); /* go back again */
            }
            cmd_buf[curpos] = '\0';
            break;
        case '\r':      //回车
        case '\n':      //换行
        case '\0':      //NULL
            putc('\r');  //输出回车
            putc('\n');  //输出换行
            goto end_cmd;
        case CTL_CH('x'):
            curpos = 0;
            break;

        default:
            if (curpos < MAX_CMDBUF_SIZE) {
                cmd_buf[curpos] = c;
                /* echo it back out to the screen */
                if (cmd_echo)
                    putc(c);
                curpos++;
            }
            break;
        }
    }
end_cmd:
    DPRINTK("COMMAND: %s\n", cmd_buf);
}

这个函数的作用就是获取用户键入的命令,并且保存在cmd_buf数组中,而且把这个命令通过终端显示出来
serial_term()--->exec_string();(vivi/lib/command.c)

/* parse and execute a string */
void exec_string(char *buf)
{
    int argc;
    char *argv[128];
    char *resid;

    while (*buf) {
        memset(argv, 0, sizeof(argv));
        parseargs(buf, &argc, argv, &resid);
        if (argc > 0)
            execcmd(argc, (const char **)argv);
        buf = resid;
    }
}

serial_term()--->exec_string()--->parseargs()
                              --->execcmd()

void parseargs(char *argstr, int *argc_p, char **argv, char** resid)
{
    int argc = 0;
    char c;
    enum ParseState lastState = PS_WHITESPACE;

    /* tokenize the argstr */
    while ((c = *argstr) != 0) {
        enum ParseState newState;

        if (c == ';' && lastState != PS_STRING && lastState != PS_ESCAPE)
            break;

        if (lastState == PS_ESCAPE) {
            newState = stackedState;
        } else if (lastState == PS_STRING) {
            if (c == '"') {
                newState = PS_WHITESPACE;
                *argstr = 0;
            } else {
                newState = PS_STRING;
            }
        } else if ((c == ' ') || (c == '\t')) {
            /* whitespace character */
            *argstr = 0;
            newState = PS_WHITESPACE;
        } else if (c == '"') {
            newState = PS_STRING;
            *argstr++ = 0;
            argv[argc++] = argstr;
        } else if (c == '\\') {
            stackedState = lastState;
            newState = PS_ESCAPE;
        } else {
            /* token */
            if (lastState == PS_WHITESPACE) {
                argv[argc++] = argstr;
            }
            newState = PS_TOKEN;
        }

        lastState = newState;
        argstr++;
    }

    argv[argc] = NULL;
    if (argc_p != NULL)
        *argc_p = argc;

    if (*argstr == ';') {
        *argstr++ = '\0';
    }
    *resid = argstr;
}

在解析完命令以后则是执行:exec_cmd(argc, const char ** argv)

/* execute a function */
void execcmd(int argc, const char **argv)
{
    user_command_t *cmd = find_cmd(argv[0]);

    if (cmd == NULL) {
        printk("Could not found '%s' command\n", argv[0]);
        printk("If you want to konw available commands, type 'help'\n");
        return;
    }
    /*printk("execcmd: cmd=%s, argc=%d\n", argv[0], argc);*/

    cmd->cmdfunc(argc, argv);
}

上面的执行函数需要调用find_cmd(const char *cmdname)来遍历整个命令结构数组,找到我们需要的命令结构

/* find command */
user_command_t *find_cmd(const char *cmdname)
{
    user_command_t *curr;

    /* do da string compare for the first offset character of cmdstr
      against each number of the cmdlist */

    curr = head_cmd;
    while(curr != NULL) {
        if (strncmp(curr->name, cmdname, strlen(cmdname)) == 0)
            return curr;
        curr = curr->next_cmd;
    }
    return NULL;
}

再来看vivi_or_boot的第二个部分
run_autoboot():

void run_autoboot(void)
{
    while (1) {
        exec_string("boot");
        printk("Failed 'boot' command. reentering vivi shell\n");
        /* if default boot fails, drop into the shell */
        vivi_shell();
    }
}

其实就是执行boot命令。类似于利用vivi_shell的方式,用户输入boot命令!
到这里整个vivi启动的部分已经完成,很多细节的东西还没讲到,比如vivi向内核传递参数还有就是每个命令函数的具体实现,这些都要具体去看,不仅可以增加C语言的水平,而且对启动也有一个更整体和清晰的认识!!!在后面我会陆续补上。
阅读(1172) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~