LPC2294的uclinux启动过程分析--串口初始化过程

LPC2294的uclinux启动过程分析--串口初始化过程

 
 
 
在/init/main.c中,start_kernel调用了console_init( ) ,该函数完成了串口的初始化、将串口向console注册等功能.

在linux/drivers/char/tty_io.c里,有console_init的函数定义.我开始一直在kernel或者linux的文件夹里面找,但是没找到,很奇怪地在char的驱动部分找到了这个函数的定义.虽然觉得可以解释的通,但是串口tty_io必须在char的设备里面吗?在block和net里面却没有同类的问题,恕我孤陋寡闻啊......继续说,里面有两个函数,一个是tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); ,一个是call.对于call的定义很奇怪:
#ifdef CONFIG_SERIAL_68360
/* This is not a console initcall. I know not what it's doing here.
   So I haven't moved it. dwmw2 */
        rs_360_init();
#endif
call = &__con_initcall_start;
while (call < &__con_initcall_end) {
(*call)();
call++;

在/arch/armnommu/kernel/vmlinux.lds.S中连接脚本汇编中有这段代码
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
__initcall_end = .;

在/include/linux/init.h里面,将上述两者联系起来:
#define console_initcall(fn) /
static initcall_t __initcall_##fn /
__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn
那最终是如何把具体的对串口的函数和console_init关联起来的,在/drivers/serial/8250.c里面有这么一句话:
console_initcall(serial8250_console_init);
这就让初始化文件调用的是serial8250_console_init.



接下来进入8250的部分.为什么是8250呢,因为在make config的时候,我们选了8250和16550的兼容设备,前者是个很通用的串口芯片,后者是接口芯片规范.

在8250.c里面定义了串口的个数和串口的结构:
static struct uart_8250_port serial8250_ports[UART_NR];
struct uart_8250_port {
struct uart_portport;
struct timer_listtimer;/* "no irq" timer */
struct list_headlist;/* ports on this IRQ */
unsigned intcapabilities;/* port capabilities */
unsigned shortrev;
unsigned characr;
unsigned charier;
unsigned charlcr;
unsigned charmcr_mask;/* mask of user bits */
unsigned charmcr_force;/* mask of forced bits */
unsigned charlsr_break_flag;

/*
* We provide a per-port pm hook.
*/
void(*pm)(struct uart_port *port,
      unsigned int state, unsigned int old);
};

在初始化函数中,将各个端口的各项属性赋值,这里指的属性是硬件地址等属性,当只有一个端口的时候循环只执行一次.然后是注册串口,在/kernel/printk.c里面,我本以为printk只是在上层输出的,原来它这个文件里面包含了如此之多的底层操作的函数.

在console这个结构里面,有一个setup的成员是一个函数,该函数在8250.c里面被调用,是设置串口的属性,这里指的属性是数据帧格式的属性.最终的一些寄存器的设置还是不在这里,在/drivers/char/serial_core.c里面,这里有很多uart的函数,包括串口速率和时钟的换算.速率和时钟在lpc22xx.h和time.h里面有过定义,在serial_core里面的前面还定义了set_termios=uart_set_termios,这个其实就是在8250.c里面的set_termios=serial8250_set_termios,最终又调用到serial_core里面的uart_get_divisor函数中去.

看起来很复杂,其实它这个抽象工作做的非常好,把串口抽象成uart,把uart具体成8250,上层和下次分的很清楚,各自负责各自的工作.把tty抽象成console,通过对结构和地址的引用来实现其控制台,不失通用性也不失具体性.

你可能感兴趣的:(linux,timer,工作,struct,汇编,脚本)