您的位置:首页 > 运维架构 > Linux

[Funkunux] Linux_2.6.22.6 内核start_kernel函数分析之console_init

2016-07-20 14:03 465 查看
在我的上一篇文章中,已经对start_kernel函数中的parse_init函数进行分析,该函数运行完后,可以得到如下三个变量:

saved_root_name="/dev/mtdblock3";

console_cmdline[0].name= "ttySAC";
console_cmdline[0].options= 0;
console_cmdline[0].idx= 0;

execute_command = "/linuxrc"

那么,这些参数都是在哪里被用到的呢?
我们先分析console_cmdline:

start_kernel 函数中调用了 console_init 函数:

void __init console_init(void)
{
initcall_t *call;

/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

/*
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
call++;
}
}在这里我们注意到:__con_initcall_start 和 __con_initcall_end 这个地址,我们可以在vmlinux.lds中找到它的定义:
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;显然,这两个地址之间存放的是 .con_initcall.init 段的内容,搜索得:
#define console_initcall(fn) \
static initcall_t __initcall_##fn \
__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn也就是说,通过 console_initcall(fn) 这个宏,将一个 initcall_t 类型的函数指针 fn 存进 .con_initcall.init 这个段中。然后console_init函数中就会去调用这个函数 fn 。

我们继续搜索console_initcall,看看这个fn函数指针具体是哪一个。由于博主使用的开发板是s3c2440,所以搜索结果中有这么一项:

S3c2410.c (linux-2.6.22.6\drivers\serial):console_initcall(s3c24xx_serial_initconsole);

static int s3c24xx_serial_initconsole(void)
{
struct s3c24xx_uart_info *info;
struct platform_device *dev = s3c24xx_uart_devs[0];

dbg("s3c24xx_serial_initconsole\n");

/* select driver based on the cpu */

if (dev == NULL) {
printk(KERN_ERR "s3c24xx: no devices for console init\n");
return 0;
}

if (strcmp(dev->name, "s3c2400-uart") == 0) {
info = s3c2400_uart_inf_at;
} else if (strcmp(dev->name, "s3c2410-uart") == 0) {
info = s3c2410_uart_inf_at;
} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
info = s3c2440_uart_inf_at;
} else if (strcmp(dev->name, "s3c2412-uart") == 0) {
info = s3c2412_uart_inf_at;
} else {
printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
return 0;
}

if (info == NULL) {
printk(KERN_ERR "s3c24xx: no driver for console\n");
return 0;
}

s3c24xx_serial_console.data = &s3c24xx_uart_drv;
s3c24xx_serial_init_ports(info);

register_console(&s3c24xx_serial_console);
return 0;
}

显然 fn-> s3c24xx_serial_initconsole(),函数中调用了register_console(&s3c24xx_serial_console),
static struct console s3c24xx_serial_console =
{
.name = S3C24XX_SERIAL_NAME,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
.write = s3c24xx_serial_console_write,
.setup = s3c24xx_serial_console_setup
};
<pre name="code" class="cpp">S3C24XX_SERIAL_NAME = "ttySAC" //和 <span style="font-family: Arial, Helvetica, sans-serif;">console_cmdline[0].name 一样</span>


而且register_console函数中有这么一段:

void register_console(struct console *console)
{
...
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) {
if (strcmp(console_cmdline[i].name, console->name) != 0)
continue;
if (console->index >= 0 &&
console->index != console_cmdline[i].index)
continue;
if (console->index < 0)
console->index = console_cmdline[i].index;
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
console->flags |= CON_ENABLED;
console->index = console_cmdline[i].index;
if (i == selected_console) {
console->flags |= CON_CONSDEV;
preferred_console = selected_console;
}
break;
}

...
}显然,当 console_cmdline[i].name 和 s3c24xx_serial_console.name相匹配,则 s3c24xx_serial_console.index = console_cmdline[i].index,且调用 s3c24xx_serial_console.setup(&s3c24xx_serial_console, console_cmdline[i].option),也即:
s3c24xx_serial_console_setup(&s3c24xx_serial_console, console_cmdline[0].option),在这里面对s3c24xx的设备串口进行初始化设置等。

console_cmdline分析到此。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息