参考
https://blog.youkuaiyun.com/coding__madman/article/details/51457181
https://blog.youkuaiyun.com/coding__madman/article/details/51484155
http://www.wowotech.net/tty_framework/tty_concept.html
《UNIX环境高级编程》
《ARM Linux设备驱动开发详解》
首先由于板子的485口不通,所以尝试去了解一下Linux对整个串口驱动的安排。虽然花了一周的时间
但是对Linux串口整个的理解还是比较肤浅,由于内容比较多,所以做一个记录。
首先从应用层角度看,串口作为字符设备之一,也需要通过虚拟文件系统向应用层提供open、write、read等
系统调用。另外串口作为终端的一种,在应用层同样使用Linux提供的termios接口,这个接口由POSIX.1规定。
termios的配置过于复杂,无力完整探讨。只尝试对串口的初始化、打开、读和写作一分析。
在分析之前,首先介绍一下Linux串口的一些设计思路,串口驱动程序开发的前提是,TTY framework,
这个框架对上向应用层提供统一的接口;对下提供编写终端驱动程序的统一框架,从而简化驱动编写。系统调用
对应file_operation结构体。另外为了提高驱动软件的可重用性和跨平台特性,驱动设计又由总线、设备和驱动
三部分组成,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;在系统每注册一个
驱动的时候会寻找与之匹配的设备,匹配完成后调用probe函数。串口驱动将作为一个模块编译如内核。
下面的分析将参考上面文献中的博客,从四个方面分析串口驱动,即串口初始化、串口打开、读串口、写串口。
1、串口初始化。
串口驱动作为一个模块,就必须有模块初始化函数。
对于普通串口,这里面主要是三个事情,一个是注册串口驱动,一个是注册平台驱动,还有一个是端口初始化,其中端口
初始化主要是将uart_port的ops和串口驱动文件中的nuc970serial_ports绑定。
uart_register_driver的功能是1、分配一个tty_driver,normal; 2、从串口层获取串口的基本信息(包括设备号、设备名等);
3、分配一个state ;4、分配并初始化一个port;5、将tty_driver和uart_ops这个结构体关联起来;6、注册tty_driver,实际
上它最终注册了一个字符设备。7:put_tty_driver调用kref_put,将tty_driver中的信息保存起来供后面的程序使用。
platform_driver_register的功能是注册driver并诱发probe,这个probe会调用到串口中的probe函数。
这个probe函数的工作就是从platform_device pdev中获取到当前端口的信息,主要是io基址,内存基址、中断号
等,并赋给uart port,然后通过uart_add_one_port注册。uart_add_one_port用于建立uart_port和uart_driver之间的联系。
总的来说串口初始化工作就是将串口驱动文件nuc970_serial.c中的函数和其它层(tty层、串口核心层)建立联系,
为后面串口打开、串口读写打下基础。
2、串口打开
在注册串口驱动的时候,实际上注册了一个字符设备,在注册字符设备的时候需要为系统提供file_operations。
tty_open部分如下图,我们可以看到tty_open调用了tty->ops->open,最终调用uart_ops的uart_open;
因为tty从tty_open_current_tty得到,tty_open_current_tty是最终通过kref_get获得在串口初始化
的时候调用kref_put引入的tty_driver,从而建立和uart_ops的联系。(这里跳来跳去比较烦,在不知道tty详细的设计
思路的时候也只能这样了...)
而uart_open调用了uart_startup;uart_startup调用uart_port_startup,然后调用startup;这个ops的类型是
uart_ops,它的ops已经在上述串口初始化中和nuc970serial_ops绑定。因此实际上tty_open最终调用了
串口驱动文件中的nuc970serial_startup。值得注意的是tty_open中tty_init_dev还调用了初始化线路规程的程序。
nuc970serial_startup的代码如下
分别是重置FIFO、清除等待中断、注册中断处理程序、初始化UART控制器,
包括出发接收缓冲区阈值设置、数据位设置、超时设置、中断使能和波特率设置。