/******************************************************************************/
首先贴出来下面要用到的4个操作函数集,
1.
struct tty_ldisc *ld;
struct tty_ldisc_ops *ops;
ld->ops->xx
2.
struct tty_struct *tty;
const struct tty_operations *ops;
tty->ops->xx
3.
struct uart_ops s3c24xx_serial_ops
/******************************************************************************/
参考了这篇文章:
http://blog.csdn.net/mbh_1991/article/details/9317653
串口的分析主要是分析两个文件:samsung.c s3c6400.c
从上面左图可以看出,用户对uart设备操作的调用关系非常简单,
file_operations => [tty_ldisc_ops] => tty_operations => uart ops,这几个调用关系会在后面函数流程分析中详细体现出来,其中tty_ldisc_ops线路规程并不是必要的,依赖于应用层设置是否使用ldisc处理数据
而上面右图,则表示uart驱动常用的数据结构,如下:
UART驱动程序结构: struct uart_driver
UART端口结构: struct uart_port
UART相关操作函数结构: struct uart_ops
UART状态结构: struct uart_ops
UART信息结构: struct uart_info
一个uart_driver就相当于一个串口驱动(1个驱动可以有多个串口)
一个uart_port就相当于一个串口
uart_ops 操作函数集
在Samsung.c中,找到其入口函数
module_init(s3c24xx_serial_modinit);
module_exit(s3c24xx_serial_modexit);
为s3c24xx_serial_modinit
完成了一个主要的功能,注册串口驱动
在s3c6400.c中,其入口函数
module_init(s3c6400_serial_init);
module_exit(s3c6400_serial_exit);
为s3c6400_serial_init,
在其入口函数中,调用s3c24xx_serial_init这个函数,
又调用了注册平台驱动,我们知道,在总线设备驱动模型中,当驱动和设备匹配上时,会调用probe函数进行初始化,因此分析其probe函数
跳转到s3c6400_serial_probe函数中去,可以看到又调用了s3c24xx_serial_probe这个函数,
跳转到s3c24xx_serial_probe这个函数中去,可以看到在这个匹配函数中,做了一系列的初始化,主要分为了4步。
1,s3c24xx_serial_ports这个函数是对串口的一些信息进行初始化,例如:中断,fifo的大小,操作函数集,如下图所示:
在s3c24xx_serial_ports中,需要着重注意的是s3c24xx_serial_ops这个操作函数集,在以后会有用处。
言归正传,在s3c24xx_serial_ports中有一个参数probe_index,,如果是probe_index是0,则取出s3c24xx_serial_ports中串口0的信息
2 调用s3c24xx_serial_init_port函数进行初始化,
2.1 在s3c24xx_serial_init_port函数中,首先做的是获取虚拟基地址,如下
由此可以知道,采用的是静态映射的方式获取到虚拟地址,即事先指定相应的规则。
2.3最后对fifo进行复位
继续回到s3c24xx_serial_probe函数进行分析。
3 建立 &s3c24xx_uart_drv, &ourport->port两者之间的关系,即建立串口与其驱动描述结构之间的关系,s3c24xx_uart_drv如下:
4 创建属性文件device_create_file,即将属性文件创建到/sys目录,通过属性文件我们可以看到串口的状态信息
5.s3c24xx_serial_cpufreq_register初始化动态频率调节
其流程图如下所示:
用户程序打开串口,会使用open系统调用,open系统调用会通过一系列的传递,然后传递到串口驱动,然后在串口驱动中会有一个相应open函数的函数,例如xx_open,然后通过这个函数打开串口,如下:
上面环节有两个重要点:
1open系统调用的时候,Linux内核是如何把这个调用关系传递到串口驱动???
2驱动程序如何实现打开操作,即xx_open???
1.open系统调用的时候,Linux内核是如何把这个调用关系传递到串口驱动???
我们知道。open函数是打开一个字符设备文件,字符设备文件里面对应操作函数集,即file_operation.
在Samsung.c中
在uart_register_driver函数中,有一个函数tty_register_driver
在tty_register_driver函数中,有字符文件设备相关的操作
tty_fops便是串口设备文件的操作函数集,在这个操作函数集在里面,首先看到的是tty_open函数,
因此可以知道tty_open是对open系统调用的响应,在tty_open函数中,又调用了函数指针
我们可以看到这个ops的类型为tty_operations,因此找到这个ops,
上图可以看到是调用了uart_open函数,在uart_open函数中,
打开uart_startup函数
因此我们需要知道uport 的ops函数集,
在s3c24xx_serial_ports里面,有一个操作函数集
这一个操作函数集便是我们的串口操作函数集,s3c24xx_serial_startup这个便是我们最终打开串口的函数。
根据上图,可以得知,在s3c24xx_serial_startup函数中,主要做的工作有:
1.使能串口接收功能
2.为数据接收注册中断
3.使能串口发送
4.为数据发送注册中断
也就是说,主要做的功能就是使能串口的接收和发送功能,并且对串口的接收和发送中断进行注册,当串口需要发送或者接收数据的时候,立马产生中断,到相应的中断处理函数中进行数据处理,这也是下一章节要说明的,后话,暂且不提。
通过以上流程可以知道,我们的open系统调用,传输到tty子系统中,串口驱动通过XX_OPEN函数对其响应,这个XX_OPEN便是我们的uart_open函数。
上面的分析如下所示:
下图,为响应open系统调用,经过一一系列的调用,最终的响应。
菜鸟一枚,如有错误,多多指教。。。