在前面几章,我们介绍了tty子系统的框架、数据结构、tty驱动的注册与注销等内容,本章我们借助
之前学习的内容开发一个虚拟的串口控制器驱动,以便我们理解开发串口驱动的步骤及驱动开发实践。
本次实现的虚拟串口主要是借助tty_register_driver、tty_port_register_device实现,而不是借助
uart_register_driver、uart_add_one_port,等我们后面介绍了uart子系统之后,再借助
uart_register_driver、uart_add_one_port实现一次虚拟串口。
本次虚拟串口实现的功能
虚拟串口的名称为vttyM(如串口0,则为/dev/vttyM0);应用程序可通过打开设备文件/dev/vttyM0,实现对串口vttyM0的读写操作;/dev/vttyM0支持loopback模式,即应用程序通过/dev/vttyM0打开串口后,向串口写入数据后,vttyM0则会将写入的数据作为接收数据,再刷新到串口中;可通过sysfs,通过设置/sys/class/tty/vttyM0/vtty_loopback属性,进行loopback模式的开启与关闭(默认开启loopback模式);可通过sysfs文件系统,通过向/sys/class/tty/vttyM0/vtty_receive_buff中写入数据,来模拟vttM0串口的数据接收,如echo "vtty test" >vtty_receive_buff,则表示串口接收到数据“vtty test”,此时若读取/dev/vttyM0,则可以获取到数据“vtty test”
本次虚拟串口实现涉及的知识点
借助platform device接口,实现虚拟串口端口对应platfomr的创建(如实现vttyM0、vttyM1两个串口,则创建对应的两个platform device);借助platform driver接口,实现platform device对应的driver,在platform driver的probe接口中,调用tty_port_register_device完成tty端口及其对应字符设备的注册借助sysfs_create_group,创建tty端口对应的sysfs属性文件,实现loopback的控制以及模拟串口接收数据的模拟;借助tty_register_driver,完成虚拟tty 控制器驱动的注册,并实现对应的接口
下面详细说明实现步骤
Platform device的实现
在本次代码实现中,主要实现了两个虚拟串口,因此创建了两个platform device,其中struct virtual_tty_port_platform_config定义了每一个端口的信息,此处主要定义了tty端口的index,而platform driver与platform dev匹配的条件即为plaform device的名称"virtual_tty_port_dev"
linux虚拟串口控制器实现---适用于无开发板学习tty driver-1.jpg (69.56 KB, 下载次数: 0)
2021-2-25 06:06 上传
Platform driver的实现
Platform driver的定义如下,该platform driver的名称为"virtual_tty_port_dev",基于名称匹配检测,即可完成platform driver与platform device的匹配。
当platform driver与platform device匹配后,则调用其probe接口进行探测操作,而在virtual_tty_port_platform_probe接口中,主要实现如下功能:
创建 struct virtual_tty_port *port变量,作为本驱动的tty_port相关数据结构类型变量,为该tty端口创建一个fifo,用于存储写入到虚拟串口中的数据;创建一个工作队列,并设置工作队列对应的callback为virtual_tty_flush_to_port,当线路规程的写接口调用tty_driver的write_buff接口后,在write_buff接口中,将数据刷到tty port的fifo中,然后唤醒该工作队列,由工作队列的回调函数进行写操作(因我们的虚拟串口不支持中断,此处由工作队列进行模拟)调用tty_port_register_device,注册该tty端口及其对应的字符设备;调用sysfs_create_group,为该tty端口对应的device创建属性文件,主要是/sys/class/tty/vttyM0/vtty_loopback、/sys/class/tty/vttyM0/vtty_receive_buff
linux虚拟串口控制器实现---适用于无开发板学习tty driver-2.jpg (89.73 KB, 下载次数: 0)
2021-2-25 06:06 上传
通过platform driver 的probe,即完成tty端口的注册,而tty端口的操作接口,主要定义了如下几个:
当打开tty端口时,将该端口的loopback模式设置为true,即打开其loopback模式,这样应用程序打开一个串口后,即可对该串口先进行写操作,再进行读操作了。而在关闭一个tty端口时,则关闭loopback模式,同时提供了tty端口内存的释放接口,这个主要是借助device的kref实现的。
linux虚拟串口控制器实现---适用于无开发板学习tty driver-3.jpg (67.74 KB, 下载次数: 0)
2021-2-25 06:06 上传
Tty driver的注册
Tty driver的代码如下,其中tty端口的名称前缀为vttyM,tty的类型为串口,该tty driver提供的操作接口包括open、close、write、hangup、write_room、install、remove、set_termios等。
具体功能说明如下:
open接口主要是打开一个tty端口,主要就是对tty_port_open,而在该接口中,会初始化该tty端口的接收缓存、tty_port与struct tty_struct的关联等等操作write接口用于向该tty端口写数据,在本驱动中,即将数据缓存到kfifo中,然后调用schedule_work,由我们注册工作队列进行写操作;hangup用于挂起一个tty端口,主要调用tty_port_hangup实现挂起操作;install主要建立tty_struct与tty_driver的关联,内部主要调用tty_standard_install实现,同时设置tty_struct->driver_data指向该tty端口对应的struct virtual_tty_port ,实现将tty_struct与我们的端口相关的私有数据变量的关联;remove用于移除tty_struct与tty_driver的关联,此处则主要设置driver->ttys[tty->index] = NULLcleanup主要进行资源的释放,此处主要是减少对struct virtual_tty_port 的引用计数;virtual_tty_set_termios则主要是设置字节宽度、波特率等信息,若是真实的串口,此处应该根据串口控制器的数据手册进行设置。
linux虚拟串口控制器实现---适用于无开发板学习tty driver-4.jpg (112.25 KB, 下载次数: 0)
2021-2-25 06:06 上传
设备属性文件的实现
主要是在sysfs文件系统下创建device相关的属性文件,此处主要是设置loopback模式以及模拟虚拟串口接收数据的功能,定义如下:
对于模拟接收数据的功能,主要是调用tty_insert_flip_char实现将数据写入到tty端口中,并调用
tty_flip_buffer_push实现将数据刷到对应线路规程的buffer中,关闭数据读写的流程,可参考我上一篇文章,此处不再细说。
linux虚拟串口控制器实现---适用于无开发板学习tty driver-5.jpg (91.88 KB, 下载次数: 0)
2021-2-25 06:06 上传
下面是测试截图:
通过sysfs下设备属性文件,模拟串口接收数据
linux虚拟串口控制器实现---适用于无开发板学习tty driver-6.jpg (8.11 KB, 下载次数: 0)
2021-2-25 06:06 上传
然后在应用程序读取串口接收的数据
linux虚拟串口控制器实现---适用于无开发板学习tty driver-7.jpg (9.09 KB, 下载次数: 0)
2021-2-25 06:06 上传
完成以上功能后,基本上完成了一个虚拟的串口控制器以及虚拟串口读写的实现,该代码可用来学习
串口驱动的使用,而在实际的串口中,主要是在写函数与读函数上有所不同,一般串口的读写均是通过中断实现的,而且也可以进行流控、串口波特率设置等内容,完整的代码后续会上传到csdn上,后面我会把链接贴上。本篇的内容主要是实现一个模拟的串口控制器及串口的实现,熟悉了tty_driver、tty_port的注册与注销后,下一章学习uart子系统也会有所帮助。