当前位置: 首页 > 科技观察

Linux终端初始化console_init和tty驱动框架

时间:2023-03-16 13:26:28 科技观察

之前分析了Linux入口地址和Linux系统启动过程。本文详细分析了Linux启动过程中的console_init终端初始化函数。上两篇文章如下:Linux内核入口分析,教大家如何分析Linux的启动过程。在解释终端初始化之前,我们先解释一个概念:tty在Linux系统中,终端是一种字符设备,它包括多种类型,通常用tty来表示各种类型的终端设备。我们一般分为三类:串口终端(/dev/ttyS*)串口终端是连接到电脑串口的终端设备。Linux将每个串行端口都视为一个字符设备。这些串口对应的设备名称为/dev/ttySAC0;/dev/ttySAC1...控制台终端(/dev/console)在Linux系统中,计算机的输出设备通常称为控制台终端(Console)。这里特指printk信息输出到的设备。/dev/console是一个虚拟设备,它需要映射到一个真实的tty(物理终端),比如console通过内核启动参数“console=ttySAC0”映射到串口0。虚拟终端(/dev/tty*)当用户登录时,使用虚拟终端。在使用Ctcl+Alt+[F1—F6]组合键时,我们可以切换到tty1、tty2、tty3等,tty1–tty6等称为虚拟终端,tty0是当前使用的虚拟终端的别名。console_init分析Linux启动函数start_kernel会调用console_init函数。linux4.14/kernel/printk/printk.clinux4.14/drivers/tty/n_tty.c我们可以看到console_init主要做了两件事:1.n_tty_init主要调用tty_register_ldisc(N_TTY,&n_tty_ops)注册tty线路规程。call=__con_initcall_start;while(call<__con_initcall_end){(*call)();call++;}这里主要是调用__con_initcall_start到__con_initcall_end之间的函数。__con_initcall_start和__con_initcall_end定义在:linux4.14/include/asm-generic/vmlinux.lds.h包含.con_initcall.init段:linux4.14/include/linux/init.h我们通过console_init来声明驱动模块,它将出现在该段中并被调用。一般我们声明的驱动模块使用module_init。如果我们写一个串口驱动,我们可以使用console_init声明。如果想看中间有哪些函数,可以查看Linux内核编译输出的System.map文件。这个文件记录了Linux从头到尾做了什么,具体地址存放了什么。System.map文件默认在编译好的Linux内核的根目录下,当然我们也可以修改到其他目录下。将有三列:地址、区域、功能名称。如果我们后面使用console_init(serial_5685_xxxx)来声明我们的驱动程序,那么这个serial_5685_xxxx就会出现在__con_initcall_start和__con_initcall_end之间,并且会被调用。initcall机制关注的是上述过程。下面来了解一下initcall机制:一般我们写程序,想让它被调用的时候,需要先在主进程中调用这个函数,然后才会调用。所以这个方法如果放到linux中,我们写的代码有多少地方要声明是不可想象的。而如果你使用initcall机制,就意味着你用一个字符串来声明你的驱动初始化函数,那么所有的驱动初始化函数都存储在内存中的一个连续段中。从每个函数开始,一个一个遍历,一个一个调用,这就是initcall机制。这就是为什么我们只需要使用module_init语句来写驱动,编译后就会自动调用!!!System.map编译后内核根目录下的system.map文件记录了所有的驱动加载顺序。如果您不确定驱动程序,您可以在此处检查加载顺序。每次编译Linux内核时,都会生成一个新的System.map。tty驱动我们不要将tty驱动与串口驱动混淆。tty驱动架构如下:tty驱动相当于我们平时写的驱动,我们可以自己写。换句话说,tty驱动框架主要分为三层:tty核心、tty行规程和tty驱动。顶层是用户空间,底层是硬件。tty核心称为tty核心,其主要作用是为用户提供统一的接口。tty线规程简称tty线规程,主要是接收上下层的数据,按照一定的协议进行转换,比如ppp或者蓝牙协议,让你的tty终端不仅可以使用普通的串口,也可以通过其他协议访问我们的系统。例如手机连接PCB板的WiFi进入系统控制终端,输入ls、cd等命令。这层不是必须的,直接用driver跟ttycore通信就可以了,不过一般都会有这一层。tty驱动就是我们常说的串口驱动。在console_init函数中,它做了两件事,即注册tty线路规程,注册tty驱动,将tty核心包含在内核中。可以有许多tty线路规程和tty驱动程序。有些人可能想知道为什么有tty驱动程序时会有tty线路纪律。得益于Linux模块化的思想,主要是分层和隔离。tty驱动只与硬件相关,只解析基本的硬件信息,将硬件信息转换成字符。所有对字符的进一步处理,包括添加蓝牙协议传输、监控数据等,都放在tty线规程中。这样就可以完美的复用和移植tty驱动了。分享一张彭老师的照片。在这篇文章中,我只谈了概念。彭老师解释了tty的源码:这里我们只需要注意一点。右下角,tty驱动没有读取功能。tty驱动层有一个缓冲区,输入的数据会存放在缓冲区中并读取。原因很简单。对于tty来说,输入设备和输出设备不是同一个设备。输入设备是键盘,输出设备是屏幕。这与普通IIC和SPI驱动的同一个设备不同。因此,tty驱动程序没有设计读取功能。本文转载自微信公众号《嵌入式Linux系统开发》