嵌入式与Linux那些事

电子技术应用专栏作家——嵌入式与Linux那些事。关注嵌入式与Linux的校招社招,本人整理了《嵌入式软件工程师笔试面试指南》PDF,平时发布嵌入式与Linux相关的实用技术文章

串口驱动分析(二)-tty core

0
阅读(1259)

  前言

  tty这个名称源于电传打字节的简称,在linux表示各种终端,终端通常都跟硬件相对应。比如对应于输入设备键盘鼠标,输出设备显示器的控制终端和串口终端。也有对应于不存在设备的pty驱动。在如此众多的终端模型之中,linux是怎么将它们统一建模的呢?这就是我们今天要讨论的问题。

  tty驱动概貌

  tty架构如下所示:

  image.png

  如上图所示,用户空间主要是通过系统调用与tty core交互。tty core根据用空间操作的类型再选择跟line discipline和tty driver交互。

  例如,设置硬件的ioctl指令就直接交给tty_driver处理。read和write操作就会交给 line discipline处理。

  Line discipline是线路规程的意思。正如它的名字一样,它表示的是这条终端”线程”的输入与输出规范设置。主要用来进行输入/输出数据的预处理。

  处理之后,就会将数据交给tty driver ,它将字符转换成终端可以理解的字串。将其传给终端设备。

  值得注意的是,这个架构没有为tty driver 提供read操作。也就是说tty core 和line discipline都没有办法从tty driver里直接读终端信息。这是因为tty driver对应的hardware并不一定是输入数据和输出 数据的共同负载者。

  例如控制终端,输出设备是显示器,输入设备是键盘。基于这样的原理。在line discipline中有一个输入缓存区,并提供了一个名叫receive_buf()的接口函数。对应的终端设备只要调用line discipine的receiver_buf函数,将数据写入到输入缓存区就可以了。如果一个设备同时是输入设备又是输出设备。那在设备的中断处理中调用receive_buf()将数据写入即可.

  tty驱动接口分析

 image.png

  tty_init主要做了以下工作:

  1. 初始化 tty 子系统的 sysctl 相关设置,包括注册 sysctl 参数、创建 sysctl 目录等。

  2. 初始化 tty 设备的字符设备对象,并将其与 tty 设备操作函数 tty_fops 绑定。同时,创建一个名为 "tty" 的 tty 设备节点,并将其设备号设置为 MKDEV(TTYAUX_MAJOR, 0)。

  3. 初始化控制台设备的字符设备对象,并将其添加到字符设备系统中。同时,创建一个名为 "console" 的控制台设备节点,并将其设备号设置为 MKDEV(TTYAUX_MAJOR, 1)。该控制台设备节点还将在 sysfs 中创建一个名为 "console" 的目录,并在该目录下创建多个属性文件,用于控制控制台的一些属性。

  4. 如果内核支持虚拟终端,则初始化虚拟终端。

  这里我们看到了熟悉的cdev_init(),device_create()之类的函数,这正是字符设备的创建流程。因此,我们说串口驱动也是一个字符设备驱动。

  而在serial8250_init()中,会调用platform_driver_register()去注册serial8250_isa_driver,在设备树节点和serial8250_isa_driver name匹配的时候,就会进入probe流程。因此,也可以说串口驱动是总线设备驱动模型。

  image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

  image.png  /**

image.png

image.png 

image.png

image.png

image.png

  

  函数所作工作如下:

  在打开 tty 设备时,该函数会检查文件的标志位,如果包含 O_NOCTTY 标志,则禁止将该 tty 设备设置为控制终端。这是因为如果一个进程打开一个 tty 设备并将其设置为控制终端,其他进程就无法再将该 tty 设备设置为控制终端,这可能会导致一些问题。

  如果打开当前的 tty 设备失败,则需要根据设备号来查找对应的 tty 驱动程序,并初始化该 tty 设备。在查找 tty 驱动程序时,需要调用 tty_lookup_driver 函数来查找对应的 tty 驱动程序,并将找到的 tty 驱动程序保存到 driver 变量中。如果找不到对应的 tty 驱动程序,则返回错误码。

  如果找到了对应的 tty 驱动程序,则调用 tty_driver_lookup_tty 函数来查找对应的 tty 设备,并将找到的 tty 设备结构体指针保存到 tty 变量中。如果找到了该 tty 设备,则需要重新打开该 tty 设备。否则,需要初始化该 tty 设备。在初始化 tty 设备时,需要调用 tty_init_dev 函数来为该 tty 设备分配一个 tty 结构体,并对其进行初始化。

  在打开 tty 设备之后,函数会调用 tty_add_file 函数将该 tty 设备与文件结构体相关联。此外,如果该 tty 设备是一个伪终端主设备,则需要将 noctty 标志设置为 1。

  最后,函数会调用 tty 设备的 open 函数,如果存在的话,来进行一些特定的操作。如果 open 函数返回错误码,则需要释放该 tty 设备并返回错误码。如果 open 函数返回 -ERESTARTSYS,则需要重新打开该 tty 设备。如果有中断发生,也需要重新打开该 tty 设备。

  tty_write

  tty_write()作用是将用户数据写入 tty 设备,并通过线路规则(line discipline)进行处理。

  线路规则是 tty 设备的一种机制,用于处理和转换从用户进程到内核和设备的数据流。在写入 tty 设备之前,需要获取该 tty 设备的线路规则,并调用其 write 方法进行处理。

  image.png

  tty_write()所作工作如下:

  首先从文件指针中获取 tty_struct 数据结构的指针,表示要写入的 tty 设备。

  检查传入的 tty_struct 指针是否有效,以及是否有其他进程正在访问该 tty 设备。如果出现问题,返回输入/输出错误码 -EIO。

  检查 tty_struct 指针是否有效、tty 设备是否支持写操作,以及是否已经出现了输入/输出错误。如果出现问题,返回输入/输出错误码 -EIO。

  检查 tty 设备是否实现了 write_room 方法,如果没有,则输出错误信息。

  获取 tty 设备的线路规则(line discipline),并等待获取成功。

  检查线路规则的 write 方法是否存在,如果不存在,返回输入/输出错误码 -EIO。否则,调用 do_tty_write 函数,将数据写入 tty 设备。

  释放线路规则引用计数器。

  返回写入操作的结果,如果写入成功,则返回写入的字节数;否则,返回相应的错误码。

  tty_read

 image.png

image.png

  tty_read()实现终端设备文件读操作的函数 。

  获取 tty_struct 结构体、inode 和 line discipline 对象的指针。

  调用 tty_paranoia_check() 函数检查 tty_struct 结构体是否可用。如果检查失败,返回 -EIO。

  检查 tty_struct 结构体是否为空或者 TTY_IO_ERROR 标志位已经设置。如果是,则返回 -EIO。

  获取 line discipline 对象的引用,确保它不会在 tty_read() 函数执行期间被卸载。

  检查 line discipline 的 read() 方法是否可用。如果可用,则调用该方法进行读取操作,并将返回的字节数保存在变量 i 中。如果不可用,返回 -EIO。

  释放 line discipline 的引用。

  如果读取操作成功,调用 tty_update_time() 函数更新 inode 的访问时间。

  返回读取的字节数。

  小结

  在这一节里,只对tty的构造做一个分析,具体的比如线路规程的内容我们了解知道就好,这里不做深入分析。

  本文参考

  https://blog.csdn.net/pan0755/article/details/51693178

  https://blog.csdn.net/qq_43286311/article/details/117824804

  https://www.jianshu.com/p/09e87a725ed4

  https://blog.csdn.net/weixin_40407893/article/details/117956968

  https://blog.csdn.net/pan0755/article/details/51693178


原文链接:https://mp.weixin.qq.com/s/dUKUd7HELFwx1-cfhC64Xg


微信图片_20220708145705.jpg

电子技术应用专栏作家 嵌入式与Linux那些事