u-boot源碼分析 --- 啓動第二階段004

繼續看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()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章