本文共 4350 字,大约阅读时间需要 14 分钟。
# uname -r2.6.22.6-g8701f843-dirty# cat /proc/cmdline noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
✗ find . -name "*.o"./s3c2410.o // CONFIG_SERIAL_S3C2410./built-in.o./serial_core.o // CONFIG_SERIAL_CORE
linux的串口中有几个概念,一个就是文件 /dev/ttyXXX ,一个就是控制台 ,一个就是 early console
- 收s3c24xx_serial_rx_chars rd_regb(port, S3C2410_URXH);- 发static void s3c24xx_serial_console_putchar(struct uart_port *port, int ch) { unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); while (!s3c24xx_serial_console_txrdy(port, ufcon)) barrier(); wr_regb(cons_uart, S3C2410_UTXH, ch); }
1.各种串口设备形成的设备节点/dev/ttyXXX(例如 ttyAMA0,不指代所有的tty*文件) 是串口驱动 通过 uart_register_driver 和 uart_add_one_port 形成的,其中利用了tty子系统和serial子系统.
2.在 控制台概念中, bootargs 中 要传入 console=aaa console=bbb console=ccc ...(也可能只有console =aaa) , 那么如果 aaa bbb ccc 驱动中有对应的 console 被注册,就是将 printk 的内容打印到 aaa bbb ccc 上,对于上述例子,ccc(最后一个)为交互控制台,其他仅为打印控制台.在 驱动中,是 用的 console_initcall(s3c24xx_serial_initconsole); 这样子来注册控制台.注册的函数存在于 __con_initcall_start 和 __con_initcall_end 中.c0021890 T __con_initcall_start c0021890 t __initcall_kgdb_console_init // CONFIG_KGDB_CONSOLE c0021894 t __initcall_con_init // 一定会有的 c0021898 t __initcall_s3c24xx_serial_initconsole // CONFIG_SERIAL_S3C2410_CONSOLE c002189c T __con_initcall_end__con_initcall_start 和 __con_initcall_end 中 的函数 在console_init 的时候被调用. 这些函数都调用 register_console 来注册控制台(匹配到 console=xxx 的才能注册成功)
3.早期linux版本(例如linux-2.6.22.6)中 arm架构是没有 early console 的概念的.后来就有了.且发展为两个版本.early console 作为一种调试手段,在 early_console 注册之后,console_init之前可以利用printk打印到串口上进行调试early console 仅作为 console_init 之前使用, console_init 之后early console 就被 disabled.early console 仅实现了发送,没有实现初始化和接收,初始化已经在 bootloader做过.版本1: early printk early_param("earlyprintk", setup_early_printk);版本2: 版本1的升级版: earlycon early_param("earlycon", setup_of_earlycon); 3.1 early printk def_config CONFIG_EARLY_PRINTK CONFIG_DEBUG_LL // 平台相关 dts chosen{ bootargs ="earlyprintk"; }; code 1. 平台无关代码 arch/arm/kernel/early_printk.c early_param("earlyprintk", setup_early_printk); // 在 parse_args "early options" 解析 early_write printch // 平台相关 2. 平台相关代码 arch/arm/kernel/debug.S ENTRY(printch) addruart_current r3, r1, r2 mov r1, r0 mov r0, #0 b 1b ENDPROC(printch) 3.2 earlycon def_config CONFIG_SERIAL_EARLYCON CONFIG_OF_EARLY_FLATTREE CONFIG_SERIAL_SAMSUNG_CONSOLE // 平台相关 dts chosen{ bootargs = "earlycon"; linux,stdout-path = &uart0; }; uart0: serial@e2900000 { // 对于earlycon而言,只在乎compatible属性和reg属性,其他需要初始化的都要在uboot中完成。 compatible = "samsung,s5pv210-uart"; reg = <0xe2900000 0x400>; }; code 1. 平台无关 early_param("earlycon", setup_of_earlycon); // 在 parse_args "early options" 解析 // 根据 linux,stdout-path = &uart0; 中的 compatible 匹配 OF_EARLYCON_DECLARE 中 的 字符串,然后拿到 s5pv210_early_console_setup 函数 of_setup_earlycon register_console(early_console_dev.con); 2. 平台相关 OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); s5pv210_early_console_setup samsung_early_console_setup device->con->write = samsung_early_write;
如果一个串口设备要作为控制台的话,也就是启动信息输出到改串口的话,一定要在串口驱动中 添加 注册 register_console 的代码, 且在 bootargs 中一定要 添加 console=xxx0,xxx 为 register_console中的参数的name成员
内核的串口驱动比较简单,但是在串口驱动之上,封装了很多逻辑.但是从上层到 printch(操作寄存器的函数) ,这个过程中, 夹杂了很多其他杂七杂八的逻辑tty子系统vtptyhvcconsolegdb consoledmesgprintk也就是说 tty console 不只是为 串口驱动准备的,而是 tty console 做一个 生产者, 供给了很多消费者,而串口驱动只是其中一个.
转载地址:http://faigi.baihongyu.com/