UBOOT之board.c分析(三)

/***************初始化输入输出***********************/
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");         //获取环境变量ip地址

stdio_init (); /* get the devices list going. */                 //标准输入输出的初始化

jumptable_init ();                                                                 //跳转表,在之后的控制台初始化时会用到,存放设备的各种操作等

stdio_init 在common/stdio.c中定义:
int stdio_init (void)
{
/* Initialize the list */
INIT_LIST_HEAD(&(devs.list));             //创建一个设备链表,变量devs就在common/stdio.c中定义。是一个 struct stdio_dev 
                                                                          //结构体的变量。这个结构体就是定义了一系列操作设备的函数指针,另外还包含了设                                                                             
                                                                         // 备名 称,标记和私有数据等等。这个链表中存放了所有用到的设备 ,也就是下面
                                                                        //所有被初始化过的设备

/*************下面是对各个用到的设备的初始化,并插入到devs链表中*********************/
#ifdef CONFIG_ARM_DCC_MULTI
drv_arm_dcc_init ();
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
drv_lcd_init ();                                 //对LCD初始化
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
serial_stdio_init ();                         //对串口初始化
#endif
#ifdef CONFIG_USB_TTY
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE
drv_jtag_console_init ();
#endif

return (0);
}

以上对各个设备做的初始化步骤大同小异,基本就是给每个设备的struct stdio_dev 结构体赋值,定义一系列的对这个设备的操作,包括输入输出等。设置名字等。最后都会调用 stdio_register 函数,复制一份结构体。然后插入到devs链表中。

下面只对串口标准输入输出的初始化简单注释:

serial_stdio_init 函数定义在common/serial.c中:
void serial_stdio_init (void)
{
struct stdio_dev dev;
struct serial_device *s = serial_devices;                 //将已经初始化好的串口设备结构体指针赋给s。

while (s) {                                                                     //循环将所有的串口设备初始化给标准输入输出
memset (&dev, 0, sizeof (dev));                    //清空dev结构体变量

strcpy (dev.name, s->name);                            //将串口设备的名字赋给dev结构体中的name项
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;    //设置标志位,表明该串口时标准输入输出

dev.start = s->init;                  //给该串口设备进行一系列的操作函数赋值
dev.putc = s->putc;
dev.puts = s->puts;
dev.getc = s->getc;
dev.tstc = s->tstc;

stdio_register (&dev);           //向标准输入输出注册设备

s = s->next;                             //指向下一个串口设备
}
}

stdio_register 函数在common/stdio.c中定义:
int stdio_register (struct stdio_dev * dev)
{
struct stdio_dev *_dev;

_dev = stdio_clone(dev);             //复制一份该设备的dev结构
if(!_dev)
return -1;
list_add_tail(&(_dev->list), &(devs.list));     //将复制后的dev结构插入到链表中,就是先前INIT_LIST_HEAD(&(devs.list));    
return 0;                                                          //创建的链表
}


/****************控制台初始化********************/

console_init_r ();

console_init_r有两种实现,一种是从环境变量中获取控制台信息,这个代码比较容易看懂,不做分析。第二个是从stdio_init中创建好的devs链表中获取控制台信息,下面的代码就是基于这种方式实现的控制台初始化。

console_init_r 函数定义在common/console.c中:
int console_init_r(void)
{
struct stdio_dev  *inputdev = NULL, *outputdev = NULL;
int i;
struct list_head *list = stdio_get_list();                 //获取devs链表的地址
struct list_head *pos;
struct stdio_dev *dev;

/* Scan devices looking for input and output devices */
list_for_each(pos, list) {                                     //list_for_each就是一个for循环的宏,用来便利devs链表
dev = list_entry(pos, struct stdio_dev, list);

if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {         //通过dev->flags判断该设备是否可以被作为标准输入
inputdev = dev;                                                    //如果可以,则将这个设备的struct stdio_dev结构指针赋给inputdev 。                                     
}
if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {  //通过dev->flags判断该设备是否可以被作为标准输出
outputdev = dev;                                                //如果可以,则将这个设备的struct stdio_dev结构指针赋给inputdev                                      
}
if(inputdev && outputdev)                         //当标准输入和标准输出都被设置后,便跳出循环
break;
}

/* Initializes output console first */
if (outputdev != NULL) {
console_setfile(stdout, outputdev);       //初始化标准输出,下面有详解
console_setfile(stderr, outputdev);       //初始化标准输入
#ifdef CONFIG_CONSOLE_MUX                         //是否定义了多个控制台
console_devices[stdout][0] = outputdev;    
console_devices[stderr][0] = outputdev;
#endif
}

/* Initializes input console */
if (inputdev != NULL) {                            
console_setfile(stdin, inputdev);                 //初始化标准输入
#ifdef CONFIG_CONSOLE_MUX
console_devices[stdin][0] = inputdev;
#endif
}

gd->flags |= GD_FLG_DEVINIT;                  //标记设备初始化已经完成

stdio_print_current_devices();           //打印输入输出信息,就是uboot刚上电时打印的那段信息,此函数很简单,不作分析
                                                                     //         In:    serial
                                                                     //        Out:   serial
                                                                     //        Err:   serial

/* Setting environment variables */
for (i = 0; i < 3; i++) {
setenv(stdio_names[i], stdio_devices[i]->name);     //设置环境变量
}

return 0;
}

console_setfile函数定义在common/console.c中:
static int console_setfile(int file, struct stdio_dev * dev)
{
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();                     //执行设备的初始化操作,并判断是否成功
/* 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;                 //将这个设备的struct stdio_dev结构体指针放到这个数组中,这个数组中存放了
                                                                           //标准输入输出以及出错的设备的  struct stdio_dev结构体指针    
/*
 * Update monitor functions
 * (to use the console stuff by other applications)
 */
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;
}

这两个数组在common/stdio.h中定义
struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };

















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值