u-boot源码分析 --- 启动第二阶段004

来源:互联网 发布:淘宝店卖话费充值 编辑:程序博客网 时间:2024/04/28 10:30

继续看console_init_r()函数

common/console.c:

/* Called after the relocation - use desired console functions */

int console_init_r (void)

{

    DECLARE_GLOBAL_DATA_PTR;

 

    /*1. 首先获取由device_init里注册的input,output设备*/

    device_t *inputdev = NULL, *outputdev = NULL;

    int i, items = ListNumItems (devlist);

 

#ifdef CONFIG_SPLASH_SCREEN

    /* suppress all output if splash screen is enabled and we have

       a bmp to display                                            */

    if (getenv("splashimage") != NULL)

        outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");

#endif

 

#ifdef CONFIG_SILENT_CONSOLE

    /* Suppress all output if "silent" mode requested     */

    if (gd->flags & GD_FLG_SILENT)

        outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");

#endif

 

    /* Scan devices looking for input and output devices */

    /*寻找系统上存在的输入,输出设备,别忘了上面注册的串口设备就是输入,输出设备*/

    for (i = 1;

         (i <= items) && ((inputdev == NULL) || (outputdev == NULL));

         i++

        ) {

        device_t *dev = ListGetPtrToItem (devlist, i);

 

        if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {

            inputdev = dev; /*找到输入设备,参考drv_system_init */

        }

        if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {

            outputdev = dev; /*找到输出设备, 参考drv_system_init */

        }

    }

 

    /* Initializes output console first */

    /*由drv_system_init可知,我们可以找到输入,输出设备,而且都是同一个serial设备*/

    if (outputdev != NULL) {

        console_setfile (stdout, outputdev); /*设置标准输出设备*/

        console_setfile (stderr, outputdev); /*设置标准的错误输出设备*/

    }

 

    /* Initializes input console */

    if (inputdev != NULL) {

        console_setfile (stdin, inputdev); /*设置标准输入设备*/

    }

   

    /*设置初始化完成标记*/

    gd->flags |= GD_FLG_DEVINIT;   /* device initialization completed */

 

#ifndef CFG_CONSOLE_INFO_QUIET

    /* Print information */

    /*打印相关设备信息*/

    puts ("In:    ");

    if (stdio_devices[stdin] == NULL) {

        puts ("No input devices available!/n");

    } else {

        printf ("%s/n", stdio_devices[stdin]->name);

    }

 

    puts ("Out:   ");

    if (stdio_devices[stdout] == NULL) {

        puts ("No output devices available!/n");

    } else {

        printf ("%s/n", stdio_devices[stdout]->name);

    }

 

    puts ("Err:   ");

    if (stdio_devices[stderr] == NULL) {

        puts ("No error devices available!/n");

    } else {

        printf ("%s/n", stdio_devices[stderr]->name);

    }

#endif /* CFG_CONSOLE_INFO_QUIET */

 

    /* Setting environment variables */

    for (i = 0; i < 3; i++) {

        setenv (stdio_names[i], stdio_devices[i]->name);

    }

 

#if 0

    /* If nothing usable installed, use only the initial console */

    if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))

        return (0);

#endif

 

    return (0);

}

该函数主要是设置好了标准输入,标准输出,标准错误输出设备,并定义好相关输入,输出函数,以使后面的如puts(),printf()等函数可以运行,这个应该不陌生的。 为了一解疑惑我们可以继续分析下去:

common/console.c:

static int console_setfile (int file, device_t * dev)

{

    DECLARE_GLOBAL_DATA_PTR;

    int error = 0;

 

    if (dev == NULL)

        return -1;

 

    switch (file) {

    case stdin:

    case stdout:

    case stderr:

        /* Start new device */

        if (dev->start) {

            error = dev->start ();  /*在drv_system_init下没定义这个函数*/

            /* If it's not started dont use it */

            if (error < 0)

                break;

        }

 

        /* Assign the new device (leaving the existing one started) */

        /*保存标准输入,标准输出,标准错误输出设备*/

        stdio_devices[file] = dev; 

 

        /*

         * Update monitor functions

         * (to use the console stuff by other applications)

         */

        /*

* 设置好标准输入,标准输出,标准错误输出设备的输入,输出函数,可以从

* drv_system_init下查到

*/

        switch (file) {

        case stdin:

            gd->jt[XF_getc] = dev->getc;

            gd->jt[XF_tstc] = dev->tstc;

            break;

        case stdout:

            gd->jt[XF_putc] = dev->putc;

            gd->jt[XF_puts] = dev->puts;

            gd->jt[XF_printf] = printf;

            break;

        }

        break;

 

    default:        /* Invalid file ID */

        error = -1;

    }

    return error;

}

这个函数就是初始化好标准输入,标准输出,标准错误输出设备,这以后就可以调用如puts,printf等函数了. 我们以puts为例继续分析:

common/console.c:

void puts (const char *s)

{

    DECLARE_GLOBAL_DATA_PTR;

 

#ifdef CONFIG_SILENT_CONSOLE

    if (gd->flags & GD_FLG_SILENT)

        return;

#endif

 

    if (gd->flags & GD_FLG_DEVINIT) {  //这个标记前面设置过了

        /* Send to the standard output */

        fputs (stdout, s);   /*就是调用这个函数*/

    } else {

        /* Send directly to the handler */

        serial_puts (s);

    }

}

void fputs (int file, const char *s)

{

/*

* 这里就是调用我们初始化时设置的了即serial_puts()函数,可以在drv_system_init查到

*/

    if (file < MAX_FILES)

        stdio_devices[file]->puts (s); 

 }

 

serial_puts函数就是和具体设备相关了,对于smdk2410的代码如下

cu/arm920t/s3c24x0/serial.c:

void serial_puts (const char *s)

{

    while (*s) {

        serial_putc (*s++);

    }

}

/*

 * Output a single byte to the serial port.

 */

void serial_putc (const char c)

{

    S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);

#ifdef CONFIG_MODEM_SUPPORT

    if (be_quiet)

        return;

#endif

 

    /* wait for room in the tx FIFO */

    while (!(uart->UTRSTAT & 0x2));

 

#ifdef CONFIG_HWFLOW

    /* Wait for CTS up */

    while(hwflow && !(uart->UMSTAT & 0x1))

        ;

#endif

 

    uart->UTXH = c;

 

    /* If /n, also do /r */

    if (c == '/n')

        serial_putc ('/r');

}

这些函数对照着datasheet就很好理解了。

 

printf函数最终也是调用puts函数。

至此我们对打印的来龙去脉了解了。

 

接下来继续分析初始化过程

 

lib_arm/board.c:

void start_armboot (void)

{

   ………

#if defined(CONFIG_MISC_INIT_R)   /*smdk2410没定义*/

    /* miscellaneous platform dependent initialisations */

    misc_init_r ();

#endif

 

    /* enable exceptions */

    enable_interrupts ();   /*smdk2410是个空函数*/

 

    /* Perform network card initialisation if necessary */

#ifdef CONFIG_DRIVER_CS8900  /*smdk2410没定义*/

    cs8900_get_enetaddr (gd->bd->bi_enetaddr);

#endif

 

/*smdk2410没定义*/

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)

    if (getenv ("ethaddr")) {

        smc_set_mac_addr(gd->bd->bi_enetaddr);

    }

#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

 

    /* Initialize from environment */

    if ((s = getenv ("loadaddr")) != NULL) {  /*从环境变量中获取加载地址*/

        load_addr = simple_strtoul (s, NULL, 16);

    }

#if (CONFIG_COMMANDS & CFG_CMD_NET) /*smdk2410没定义*/

    if ((s = getenv ("bootfile")) != NULL) {

        copy_filename (BootFile, s, sizeof (BootFile));

    }

#endif  /* CFG_CMD_NET */

 

#ifdef BOARD_LATE_INIT   /*smdk2410没定义*/

    board_late_init ();

#endif

#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) /*smdk2410没定义*/

    puts ("Net:   ");

    eth_initialize(gd->bd);

#endif

    /* main_loop() can return to retry autoboot, if so just run it again. */

    /* 经过千山万水,终于来到这里了*/

    for (;;) {

        main_loop ();  /*主循环*/

    }

}

 这里很多的功能在smdk2410下都没定义(默认的代码),当然如果我们的板子上要加上这些功能我们可以在smdk2410.h下打开他们。

接下来我们主要分析main_loop()

0 0
原创粉丝点击