<?xml version="1.0" encoding="gbk"?> <rss version="2.0"><channel> <title>定阅帖子更新</title> <link>http://www.broadkey.com.cn/XML.ASP</link><description>TEAM Board - 意得法电子</description> <copyright>TEAM 2.0.5 Release</copyright><generator>TEAM Board by TEAM5.Cn Studio</generator> <ttl>30</ttl><item><link>http://www.broadkey.com.cn/Thread.asp?tid=53 </link><title>Linux&amp;nbsp;串口终端初始化</title><author>alan</author><pubDate>2009-11-25 23:42:41</pubDate><description><![CDATA[1. 串口初始化过程<br />
<br />
&nbsp;&nbsp;&nbsp; start_kernel()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- setup_arch()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- build_all_zonelists()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- page_alloc_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- trap_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- <strong>console_init()</strong><br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- mem_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; `----- <strong>rest_init()&nbsp;&nbsp; </strong>---&gt; kernel_thread() --&gt; init() --&gt;do_basic_setup()<br />
<br />
<br />
<strong>1.1 </strong>console_init()<br />
<br />
[drivers/char/tty_io.c]<br />
<br />
/* 只作基本的初始化，详细的初始化在后面做 */<br />
void __init <strong>console_init</strong>(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; initcall_t *call;<br />
<br />
&nbsp;&nbsp;&nbsp; /* Setup the default TTY line discipline. */<br />
&nbsp;&nbsp;&nbsp; (void) tty_register_ldisc(N_TTY, &amp;tty_ldisc_N_TTY);<br />
<br />
&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp; * set up the console device so that later boot sequences can<br />
&nbsp;&nbsp;&nbsp;&nbsp; * inform about problems etc..<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
#ifdef CONFIG_EARLY_PRINTK<br />
&nbsp;&nbsp;&nbsp; disable_early_printk();<br />
#endif<br />
&nbsp;&nbsp;&nbsp; call = __con_initcall_start;<br />
&nbsp;&nbsp;&nbsp; while (call &lt; __con_initcall_end) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (*call)();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call++;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
然后执行依次执行 .con_initcall.init 节中的函数，该节的每项为一个函数指针，使用宏 console_initcall(FUNC_NAME) 将函数指针填入，该宏定义于 [include/linux/init.h]:<br />
<br />
#define console_initcall(fn) \<br />
&nbsp;&nbsp;&nbsp; static initcall_t __initcall_##fn \<br />
&nbsp;&nbsp;&nbsp; __attribute_used__ __attribute__((__section__(&quot;<font color="#ff6600"><strong>.con_initcall.init</strong></font>&quot;)))=fn<br />
<br />
initcall_t 为一函数指针： typedef int (*initcall_t)(void);<br />
<br />
如： console_initcall(serial8250_console_init) 则展开为：<br />
<br />
static initcall_t __initcall_serial8250_console_init = __attribute_used__ \<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; __attribute__((__section__(&quot;<font color="#ff6600"><strong>.con_initcall.init</strong></font>&quot;))) = serial8250_console_init;<br />
<br />
即定义一个函数指针，使其指向 serial8250_console_init，并使用gcc的 __attribute__ 扩展，将其链接入.con_initcall.init 节，方便管理。<br />
<br />
一个典型的 .con_initcall.init 节的内容为：<br />
...<br />
Disassembly of section .con_initcall.init:<br />
<br />
80234f90 &lt;__initcall_serial8250_console_init&gt;:<br />
80234f90:&nbsp;&nbsp; 802328e4&nbsp;&nbsp;&nbsp; lb v1,10468(at)&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; # 这是一个函数指针，指向serial8250_console_init<br />
80234f94 &lt;__initcall_early_uart_console_init&gt;:&nbsp;&nbsp; <br />
80234f94:&nbsp;&nbsp; 80232ce4&nbsp;&nbsp;&nbsp; lb v1,11492(at)<br />
...<br />
<br />
因此 console_init() 所做的，就是：<br />
<br />
&nbsp;&nbsp;&nbsp; console_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- tty_register_ldisc()&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; /* Install a line discipline, [drivers/char/tty_io.c] */<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- serial8250_console_init()&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; `----- early_uart_console_init()<br />
<br />
<br />
<strong>1.1.1 </strong>serial8250_console_init<br />
<br />
serial8250_console_init() 定义于 [drivers/serial/8250.c]<br />
<br />
static int __init <strong>serial8250_console_init</strong>(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; serial8250_isa_init_ports();<br />
&nbsp;&nbsp;&nbsp; register_console(&amp;serial8250_console);<br />
&nbsp;&nbsp;&nbsp; return 0;<br />
}<br />
console_initcall(serial8250_console_init);<br />
<br />
static struct uart_8250_port <strong>serial8250_ports</strong>[UART_NR];<br />
<br />
static void __init <font color="#ff6600"><strong>serial8250_isa_init_ports</strong></font>(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; struct uart_8250_port *up;<br />
&nbsp;&nbsp;&nbsp; static int first = 1;<br />
&nbsp;&nbsp;&nbsp; int i;<br />
<br />
&nbsp;&nbsp;&nbsp; if (!first)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br />
&nbsp;&nbsp;&nbsp; first = 0;<br />
<br />
&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; nr_uarts; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct uart_8250_port *up = &amp;serial8250_ports[i];<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.line = i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock_init(&amp;up-&gt;port.lock);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_timer(&amp;up-&gt;timer);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;timer.function = serial8250_timeout;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ALPHA_KLUDGE_MCR needs to be killed.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;mcr_mask = ~ALPHA_KLUDGE_MCR;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;mcr_force = ALPHA_KLUDGE_MCR;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.ops = &amp;serial8250_pops;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; for (i = 0, up = serial8250_ports;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i &lt; ARRAY_SIZE(old_serial_port) &amp;&amp; i &lt; nr_uarts;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i++, up++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.iobase&nbsp;&nbsp; = old_serial_port[i].port;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.irq&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = irq_canonicalize(old_serial_port[i].irq);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.uartclk = old_serial_port[i].baud_base * 16;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.flags&nbsp;&nbsp;&nbsp; = old_serial_port[i].flags;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.hub6&nbsp;&nbsp;&nbsp;&nbsp; = old_serial_port[i].hub6;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.membase = old_serial_port[i].iomem_base;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.iotype&nbsp;&nbsp; = old_serial_port[i].io_type;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.regshift = old_serial_port[i].iomem_reg_shift;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (share_irqs)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; up-&gt;port.flags |= UPF_SHARE_IRQ;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
<br />
serial8250_isa_init_ports() 所做的事即使用 old_serial_port 来初始化 struct uart_8250_port 结构数组 serial8250_ports. 这个 old_serial_port 定义为:<br />
<br />
static const struct old_serial_port old_serial_port[] = {<br />
&nbsp;&nbsp;&nbsp; SERIAL_PORT_DFNS &nbsp;&nbsp;&nbsp; /* defined in asm/serial.h */<br />
};<br />
<br />
[include/asm-mips/serial.h]<br />
#define SERIAL_PORT_DFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; DDB5477_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; EV64120_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; IP32_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; JAZZ_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; STD_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; MOMENCO_OCELOT_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; BCM947XX_SERIAL_PORT_DEFNS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; BCM56218_SERIAL_PORT_DEFNS<br />
<br />
这个根据具体的平台配置,使用相应的宏定义. 如当 CONFIG_HAVE_STD_PC_SERIAL_PORT 时:<br />
<br />
#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT<br />
#define <strong>STD_SERIAL_PORT_DEFNS </strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; /* UART CLK&nbsp;&nbsp; PORT IRQ&nbsp;&nbsp;&nbsp;&nbsp; FLAGS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />
&nbsp;&nbsp;&nbsp; { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \<br />
&nbsp;&nbsp;&nbsp; { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \<br />
&nbsp;&nbsp;&nbsp; { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \<br />
&nbsp;&nbsp;&nbsp; { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */<br />
<br />
#else /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */<br />
#define STD_SERIAL_PORT_DEFNS<br />
#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */<br />
<br />
否则为空宏<br />
<br />
serial8250_isa_init_ports() 后, serial8250_console_init() 调用 register_console(&amp;serial8250_console) 注册一个struct console 结构:<br />
<br />
static struct uart_driver serial8250_reg;<br />
static struct console serial8250_console = {<br />
&nbsp;&nbsp;&nbsp; .name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot;ttyS&quot;,<br />
&nbsp;&nbsp;&nbsp; .write&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = serial8250_console_write,<br />
&nbsp;&nbsp;&nbsp; .device&nbsp;&nbsp;&nbsp;&nbsp; = uart_console_device,<br />
&nbsp;&nbsp;&nbsp; .setup&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = serial8250_console_setup,<br />
&nbsp;&nbsp;&nbsp; .flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = CON_PRINTBUFFER,<br />
&nbsp;&nbsp;&nbsp; .index&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = -1,<br />
&nbsp;&nbsp;&nbsp; .data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &amp;serial8250_reg,<br />
};<br />
<br />
其用来描述一个 serial8250 的 console.<br />
这个register_console() 定义于 [kernel/printk.c]<br />
<br />
<strong>1.1.2</strong> early_uart_console_init()<br />
<br />
[drivers/serial/8250_early.c]<br />
<br />
static struct console early_uart_console __initdata = {<br />
&nbsp;&nbsp;&nbsp; .name&nbsp;&nbsp; = &quot;uart&quot;,<br />
&nbsp;&nbsp;&nbsp; .write = early_uart_write,<br />
&nbsp;&nbsp;&nbsp; .setup = early_uart_setup,<br />
&nbsp;&nbsp;&nbsp; .flags = CON_PRINTBUFFER,<br />
&nbsp;&nbsp;&nbsp; .index = -1,<br />
};<br />
<br />
static int __init early_uart_console_init(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; if (!early_uart_registered) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register_console(&amp;early_uart_console);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; early_uart_registered = 1;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; return 0;<br />
}<br />
console_initcall(early_uart_console_init);<br />
<br />
和 serial8250_console_init() 类似,也是注册一个 console 结构,表示一个 uart console<br />
<br />
<br />
<strong>1.2</strong> rest_init()<br />
<br />
&nbsp;&nbsp;&nbsp; rest_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- smp_prepare_cpus(max_cpus)<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- do_pre_smp_initcalls()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- smp_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- sched_init_smp()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- cpuset_init_smp()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- <strong>do_basic_setup()</strong><br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; `----- init_post()<br />
<br />
1.2.1 do_basic_setup()<br />
<br />
到 do_basic_setup() 时,与体系结构相关的部分已经初始化完了,现在开始初始化设备了:<br />
<br />
[init/main.c]<br />
<br />
static void __init do_basic_setup(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; /* drivers will send hotplug events */<br />
&nbsp;&nbsp;&nbsp; init_workqueues();<br />
&nbsp;&nbsp;&nbsp; usermodehelper_init();<br />
<br />
&nbsp;&nbsp;&nbsp;<strong> driver_init();&nbsp;&nbsp;</strong> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; /* initialize driver model */<br />
<br />
&nbsp;&nbsp;&nbsp; init_irq_proc();<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <strong>do_initcalls();&nbsp;&nbsp; </strong>&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; /* 顺序执行 .initcall.init 节中的所有函数 */<br />
<br />
}<br />
<br />
<br />
<strong>1.2.1</strong> driver_init()<br />
<br />
driver_init() 定义于 [drivers/base/init.c] 主要完成 driver subsystem 的初始化:<br />
<br />
void __init driver_init(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; /* These are the core pieces */<br />
&nbsp;&nbsp;&nbsp; devices_init();<br />
&nbsp;&nbsp;&nbsp; buses_init();<br />
&nbsp;&nbsp;&nbsp; classes_init();<br />
&nbsp;&nbsp;&nbsp; firmware_init();<br />
&nbsp;&nbsp;&nbsp; hypervisor_init();<br />
<br />
&nbsp;&nbsp;&nbsp; /* These are also core pieces, but must come after the<br />
&nbsp;&nbsp;&nbsp;&nbsp; * core core pieces.<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; platform_bus_init();<br />
&nbsp;&nbsp;&nbsp; system_bus_init();<br />
&nbsp;&nbsp;&nbsp; cpu_dev_init();<br />
&nbsp;&nbsp;&nbsp; memory_dev_init();<br />
&nbsp;&nbsp;&nbsp; attribute_container_init();<br />
}<br />
<br />
这些函数主要调用 subsystem_register() 注册一个struct subsystem 结构,进入kobjects.<br />
<br />
<strong><br />
1.2.2 </strong>do_initcall()<strong><br />
</strong><br />
这个于上面 console_init() 类似,其是顺序执行 .initcall.init 节中的所有函数:<br />
<br />
[init/main.c]<br />
<br />
extern initcall_t __initcall_start[], __initcall_end[];<br />
<br />
static void __init do_initcalls(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; initcall_t *call;<br />
&nbsp;&nbsp;&nbsp; int count = preempt_count();<br />
<br />
&nbsp;&nbsp;&nbsp; for (call = __initcall_start; call &lt; __initcall_end; call++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *msg = NULL;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char msgbuf[40];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (initcall_debug) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk(&quot;Calling initcall 0x%p&quot;, *call);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print_fn_descriptor_symbol(&quot;: %s()&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unsigned long) *call);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk(&quot;\n&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result = (*call)();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (result &amp;&amp; result != -ENODEV &amp;&amp; initcall_debug) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(msgbuf, &quot;error code %d&quot;, result);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg = msgbuf;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (preempt_count() != count) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg = &quot;preemption imbalance&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preempt_count() = count;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (irqs_disabled()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg = &quot;disabled interrupts&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local_irq_enable();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (msg) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk(KERN_WARNING &quot;initcall at 0x%p&quot;, *call);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print_fn_descriptor_symbol(&quot;: %s()&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unsigned long) *call);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk(&quot;: returned with %s\n&quot;, msg);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; /* Make sure there is no pending stuff from the initcall sequence */<br />
&nbsp;&nbsp;&nbsp; flush_scheduled_work();<br />
}<br />
<br />
关于符号地址 __initcall_start, __initcall_end 的来源,则是由编译系统写在 [arch/mips/kernel/vmlinux.lds]中:<br />
<br />
......<br />
__initcall_start = .;<br />
.initcall.init : {<br />
*(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)<br />
}<br />
__initcall_end = .;<br />
......<br />
<br />
链接时,会被替换为实际的地址矣.<br />
<br />
写入 .initcall.init 节的函数指针,有一组辅助的宏定义于[include/linux/init.h]:<br />
<br />
#define pure_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;0&quot;,fn,1)<br />
#define core_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;1&quot;,fn,1)<br />
#define core_initcall_sync(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;1s&quot;,fn,1s)<br />
#define postcore_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;2&quot;,fn,2)<br />
#define postcore_initcall_sync(fn) __define_initcall(&quot;2s&quot;,fn,2s)<br />
#define arch_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;3&quot;,fn,3)<br />
#define arch_initcall_sync(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;3s&quot;,fn,3s)<br />
#define subsys_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;4&quot;,fn,4)<br />
#define subsys_initcall_sync(fn)&nbsp;&nbsp;&nbsp; __define_initcall(&quot;4s&quot;,fn,4s)<br />
#define fs_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;5&quot;,fn,5)<br />
#define fs_initcall_sync(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;5s&quot;,fn,5s)<br />
#define rootfs_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;rootfs&quot;,fn,rootfs)<br />
#define device_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;6&quot;,fn,6)<br />
#define device_initcall_sync(fn)&nbsp;&nbsp;&nbsp; __define_initcall(&quot;6s&quot;,fn,6s)<br />
#define late_initcall(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;7&quot;,fn,7)<br />
#define late_initcall_sync(fn)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __define_initcall(&quot;7s&quot;,fn,7s)<br />
<br />
其优先级依次降低,优先级越高的,越靠前,则先被执行.<br />
<br />
在这个节的最后,可以看到调用串口相关的初始化函数:<br />
<br />
Disassembly of section .initcall.init:<br />
......<br />
......<br />
80234f80 &lt;__initcall_<font color="#339966"><strong>serial8250_init</strong></font>6&gt;:<br />
80234f80:&nbsp;&nbsp; 80232910&nbsp;&nbsp;&nbsp; lb v1,10512(at)<br />
80234f84 &lt;__initcall_random32_reseed7&gt;:<br />
80234f84:&nbsp;&nbsp; 802319c4&nbsp;&nbsp;&nbsp; lb v1,6596(at)<br />
80234f88 &lt;__initcall_seqgen_init7&gt;:<br />
80234f88:&nbsp;&nbsp; 80231ae8&nbsp;&nbsp;&nbsp; lb v1,6888(at)<br />
80234f8c &lt;__initcall_<font color="#339966"><strong>early_uart_console_switch</strong></font>7&gt;:<br />
80234f8c:&nbsp;&nbsp; 80233140&nbsp;&nbsp;&nbsp; lb v1,12608(at)<br />
<br />
因此:<br />
<br />
&nbsp;&nbsp;&nbsp; do_basic_setup()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- driver_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- init_irq_proc()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- do_initcalls()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; |----- <font color="#339966">serial8250_init()</font><br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; |----- seqgen_init()<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; `----- <font color="#339966">early_uart_console_switch()<strong><br />
</strong></font>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; |----- ...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; `----- ...<br />
<br />
<strong>1.2.2.1</strong> serial8250_init()<br />
<br />
[drivers/serial/8250.c]<br />
<br />
static int __init serial8250_init(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; int ret, i;<br />
<br />
&nbsp;&nbsp;&nbsp; if (nr_uarts &gt; UART_NR)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nr_uarts = UART_NR;<br />
<br />
&nbsp;&nbsp;&nbsp; printk(KERN_INFO &quot;Serial: 8250/16550 driver $Revision: 1.90 $ &quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;%d ports, IRQ sharing %sabled\n&quot;, nr_uarts,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; share_irqs ? &quot;en&quot; : &quot;dis&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; NR_IRQS; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock_init(&amp;irq_lists[i].lock);<br />
<br />
&nbsp;&nbsp;&nbsp; ret = uart_register_driver(&amp;serial8250_reg);<br />
&nbsp;&nbsp;&nbsp; if (ret)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto out;<br />
<br />
&nbsp;&nbsp;&nbsp; serial8250_isa_devs = platform_device_alloc(&quot;serial8250&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PLAT8250_DEV_LEGACY);<br />
&nbsp;&nbsp;&nbsp; if (!serial8250_isa_devs) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -ENOMEM;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto unreg_uart_drv;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; ret = platform_device_add(serial8250_isa_devs);<br />
&nbsp;&nbsp;&nbsp; if (ret)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto put_dev;<br />
<br />
&nbsp;&nbsp;&nbsp; serial8250_register_ports(&amp;serial8250_reg, &amp;serial8250_isa_devs-&gt;dev);<br />
<br />
&nbsp;&nbsp;&nbsp; ret = <strong>platform_driver_register</strong>(&amp;serial8250_isa_driver);&nbsp;&nbsp; ---&gt; 注册时调用 serial8250_probe()<br />
&nbsp;&nbsp;&nbsp; if (ret == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto out;<br />
<br />
&nbsp;&nbsp;&nbsp; platform_device_del(serial8250_isa_devs);<br />
put_dev:<br />
&nbsp;&nbsp;&nbsp; platform_device_put(serial8250_isa_devs);<br />
unreg_uart_drv:<br />
&nbsp;&nbsp;&nbsp; uart_unregister_driver(&amp;serial8250_reg);<br />
out:<br />
&nbsp;&nbsp;&nbsp; return ret;<br />
}<br />
<br />
注意 <strong>platform_driver_register</strong>() 中,注册时调用 serial8250_probe(), 从[arch/mips/emma3p/et10068/platform.c] 中设置的 struct platform_device 结构数组中获得板极相关的串口设备.<br />
<strong><br />
1.2.2.2 </strong>early_uart_console_switch()<br />
<br />
[drivers/serial/8250_early.c]<br />
<br />
static int __init early_uart_console_switch(void)<br />
{<br />
&nbsp;&nbsp;&nbsp; struct early_uart_device *device = &amp;early_device;<br />
&nbsp;&nbsp;&nbsp; struct uart_port *port = &amp;device-&gt;port;<br />
&nbsp;&nbsp;&nbsp; int mmio, line;<br />
<br />
&nbsp;&nbsp;&nbsp; if (!(early_uart_console.flags &amp; CON_ENABLED))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
<br />
&nbsp;&nbsp;&nbsp; /* Try to start the normal driver on a matching line. */<br />
&nbsp;&nbsp;&nbsp; mmio = (port-&gt;iotype == UPIO_MEM);<br />
&nbsp;&nbsp;&nbsp; line = serial8250_start_console(port, device-&gt;options);&nbsp;&nbsp; &nbsp;&nbsp; /* start console */<br />
&nbsp;&nbsp;&nbsp; if (line &lt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk(&quot;No ttyS device at %s 0x%lx for console\n&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmio ? &quot;MMIO&quot; : &quot;I/O port&quot;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmio ? port-&gt;mapbase :<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unsigned long) port-&gt;iobase);<br />
<br />
&nbsp;&nbsp;&nbsp; unregister_console(&amp;early_uart_console);<br />
&nbsp;&nbsp;&nbsp; if (mmio)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iounmap(port-&gt;membase);<br />
<br />
&nbsp;&nbsp;&nbsp; return 0;<br />
}<br />
late_initcall(early_uart_console_switch);<br />
<br />
到此串口终端正式可用矣~~~<br />
<br />
2. 兼容 8250 的串口控制器驱动位于:<br />
<br />
drivers/serial/8250_early.c<br />
drivers/serial/8250.c<br />
drivers/serial/serial_core.c]]></description></item></channel></rss>