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()
- u-boot源码分析 --- 启动第二阶段004
- u-boot源码分析 --- 启动第二阶段004
- u-boot源码分析 --- 启动第二阶段001
- u-boot源码分析 --- 启动第二阶段002
- u-boot源码分析 --- 启动第二阶段003
- u-boot源码分析 --- 启动第二阶段005
- u-boot源码分析 --- 启动第二阶段006
- u-boot源码分析 --- 启动第二阶段007
- u-boot源码分析 --- 启动第二阶段001
- u-boot源码分析 --- 启动第二阶段002
- u-boot源码分析 --- 启动第二阶段003
- u-boot源码分析 --- 启动第二阶段005
- u-boot源码分析 --- 启动第二阶段006
- u-boot源码分析 --- 启动第二阶段007
- u-boot第二阶段源码分析
- U-Boot 启动过程和源码分析(第二阶段)
- U-Boot启动过程源码分析(2)-第二阶段
- U-Boot启动第二阶段代码分析
- Android Studio更新后 Eclipse项目导入问题
- 不同时间入库的相同药品中,只获取最后一次入库的药品信息的方法
- 通过注册表屏蔽WIN+L、注销、切换用户等
- SyncTools--->备份数据工具类
- 比较两数大小(指针)
- u-boot源码分析 --- 启动第二阶段004
- 打造属于自己的前端开发神器 -- 给Sublime Text加上Eclipse的光环
- Java回顾之网络通信
- 用于开发移动应用的英特尔® HTML5 工具
- 程序猿也爱学英语(上),有图有真相
- 在注册表里设定ie首页的样例
- silverlight 2.0 外部参数传递到app中
- 对目前一些混淆器的总结
- C#中问号的用法(非表达式)---单问号,双问号