分类: LINUX
2012-02-11 12:02:31
继续看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()