initcall机制
注意上述流程,我们来理解一下 initcall 机制:
普通我们写一个程序,想要它被调用,需要在主流程中调用这个函数,才算被调用。
那么这种方式如果放在 Linux 中,是难以想象的,我们自己写的代码要在多少个地方声明。
而你如果采用initcall机制,意思就是说,你使用一个字符串声明你的驱动初始化函数,那么所有的驱动初始化函数都存在内存中一个连续的段中,系统启动以后,会从这个段的第一个函数开始,一个一个遍历,进而一个一个调用,这就是initcall 机制。这就是为什么我们写驱动只需要使用 module_init 声明,编译进去即可自动被调用的原因!!!
System.map
编译后的内核根目录 System.map 文件记载了所有的驱动加载顺序,如果你不确定驱动的加载顺序,在这里查看就可以,每次编译 Linux 内核就会产生一个新的 System.map。
tty 驱动
我们不要把 tty 驱动和 串口驱动 弄混了,tty 驱动架构如下:
其中 tty driver 等价于我们普通写的驱动,可以自己写。
也就是说,在 tty 驱动框架主要有三层:tty core、tty line discipline、tty driver,另外最上层是用户空间,最下层是硬件。
tty core 称之为 tty 核心,主要作用是向用户提供统一的接口。
tty line discipline 称之为 tty 线路规程,主要从上下两层接收数据,并按照一定协议进行转换,比如 ppp 或者蓝牙协议,这样你的tty 终端就不止可以用普通的串口,还可以通过其他协议访问到我们的系统。比如手机链接 PCB 板子的 WiFi 接入系统控制终端,输入 ls、cd等命令。这一层并不是必须的,你可以直接使用驱动和 tty core 进行通信,但一般这一层都会有。
tty driver 就是我们常说的串口驱动。
在 console_init 函数中,它做的两件事,就是注册 tty 线路规程,注册 tty 驱动,tty 核心是包含在内核当中的。tty 线路规程和tty 驱动可以有很多个。
有的人会有疑问,为什么有了 tty 驱动了,还会有一个 tty 线路规程。得益于 Linux 模块化的思想,这里主要是为了分层与隔离。tty驱动只和硬件相关,只解析基本的硬件信息,把硬件信息转换成字符。所有的对字符的进一步处理包括加入蓝牙协议传输,监控数据等都放在 tty 线路规程当中。这样 tty
驱动是可以完美复用和移植的。
分享一张彭大佬的图,本文我只讲了概念,彭大佬讲解过 tty 源码:
这里只需要注意一点,在右下角,tty driver 是没有 read 函数的,tty driver 层有 buffer,输入的数据会存储在buffer 中,被读取。
原因很简单,对于 tty 来说,输入设备和输出设备不是同一个设备,输入设备是键盘,输出设备是屏幕,这和普通的 IIC、SPI驱动同一个设备不一样。因此在设计上 tty driver 没有 read 函数。
全部0条评论
快来发表一下你的评论吧 !