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