在uclinux初始化过程中,除非启用了early console,否则直到console_init调用之前是没有任何输出的,它们的输出都放在__log_buf这个缓冲内的,在console_init调用时再将这个缓冲区内的数据一次性输出。那么console_init又做了什么工作呢?这个函数体在drivers/char/tty_io.c中:/** Initialize the console device. This is called *early*, so* we can't necessarily depend on lots of kernel help here.* Just do some early initializations, and do the complex setup* later.*/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++;}}从这个函数大致可以猜出,console和串口的初始化操作应该是由__con_initcall_start到__con_initcall_end之间的函数调用来完成的。那么放到这段空间中的函数是怎么来的呢?又是什么函数可以放在这段空间中呢?让我们看看vmlinux.lds.s文件中对这两个符号的定义吧:.con_initcall.init :{___con_initcall_start = .;*(.con_initcall.init)___con_initcall_end = .;}原来,这段空间中存放的是.con_initcall.init这个段的内容,也就是说只要在数据代码中声明.con_initcall.init就可以了。
此函数的实现在kernel/printk.c中:/** The console driver calls this routine during kernel initialization* to register the console printing procedure with printk() and to* print any messages that were printed by the kernel before the* console driver was initialized.*/void register_console(struct console *console){int i;unsignedlong flags;struct console *bootconsole = NULL;if (preferred_console < 0 || bootconsole || !console_drivers)preferred_console = selected_console;/**See if we want to use this console driver. If we*didn't select a console we take the first one*that registers here.*/if (preferred_console < 0) {if (console->index < 0)console->index = 0;if (console->setup == NULL ||console->setup(console, NULL) == 0) {console->flags |= CON_ENABLED | CON_CONSDEV;preferred_console = 0;}}/**See if this console matches one we selected on*the command line.*/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;}if (!(console->flags & CON_ENABLED))return;/**Put this console in the list - keep the*preferred driver at the head of the list.*/acquire_console_sem();if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {console->next = console_drivers;console_drivers = console;if (console->next)console->next->flags &= ~CON_CONSDEV;} else {console->next = console_drivers->next;console_drivers->next = console;}if (console->flags & CON_PRINTBUFFER) {/** release_console_sem() will print out the buffered messages* for us.*/spin_lock_irqsave(&logbuf_lock, flags);