您的位置:首页 > 编程语言

MTK平台 UART驱动代码分析

2016-03-30 16:45 796 查看
文章出处:http://blog.csdn.net/dlijun/article/details/50617445

首先参考网上的一些资料,给出UART驱动的整体描述与框架,

在 linux 系统中,tty 表示各种终端。终端通常都跟硬件相对应。比如对应于输入设备键盘 鼠标,输出设备显示器的控制终端和串口终端。

最上面的用户空间会有很多对底层硬件的操作,像 read,write 等。用户空间主要是通过设 备文件同 tty_core 交互,tty_core 根据用空间操作的类型再选择跟 line discipline 和 tty_driver 也就是 serial_core 交互,例如设置硬件的 ioctl 指令就直接交给 serial_core 处理。 Read 和 write 操作就会交给 line discipline 处理。Line discipline 是线路规程 的意思。正如它的名字一样,它表示的是这条终端”线程”的输入与输出规范设置,主要用 来进行输入/输出数据的预处理。处理之后,就会将数据交给 serial_core。



一个 uart_driver 通常会注册一段设备号.即在用户空间会看到 uart_driver 对应有多个设 备节点。例如:/dev/ttyMT0 /dev/ttyMT1 每个设备节点是对应一个具体硬件的,这样就可 做到对多个硬件设备的统一管理,而每个设备文件应该对应一个 uart_port,也就是 说:uart_device 要和多个 uart_port 关系起来。并且每个 uart_port 对应一个 circ_buf(用来接收数据),所以 uart_port 必须要和这个缓存区关系起来。

MTK uart 驱动,源文件路径 Mediatek/kernel/drivers/uart/uart.c

[objc]
view plain
copy



第 2238 行,调用 mtk_uart_sysfs 函数,其定义如下:



该函数初始化 mtk_uart_sysobj 结构体,主要调用 kobject_init_and_add 函数完成对 kobject 的初始化,建立 kobject 的层次结构,并将 kobject 添加到 sysfs 文件系统中。具 体实现请参考 http://blog.csdn.net/liuhaoyutz/article/details/12993931。
回到 mtk_uart_init 函数,第 2241 行调用 uart_register_driver 函数注册 mtk_uart_drv。mtk_uart_drv 结构如下:



uart_register_driver 函数定义在 kernel/drivers/tty/serial/serial_core.c 文件中,





第 2244行,uart驱动与tty_driver关联起来。

第 2254 行,设置 uart 的初始波特率。

第 2257 行,将 tty_driver 的操作集统一设为了 uart_ops.这样就使得从用户空间下来的操作可以找到正确的 serial_core 的操作函数。Uart_ops 如下:



第 2267 行,uart_port_ops 结构体如下:



第 2272 行,调用 tty_register_driver 函数,其所在文件为 kernel/drivers/tty/tty_io.c。





第 3154 行,MKDEV 宏定义在 include/linux/kdev_t.h 头文件,#define MKDEV(ma,mi) (((ma)<< MINORBITS) | (mi)) 作用是将主设备号和次设备号转换成 dev_t 类型。

第 3155 行,register_chrdev_region 为一个字符驱动获取一个或多个设备编号。

第 3170行,cdev_init函数initialize a cdev structure,tty_fops结构体如下:



第 3172行,调用 cdev_add() 函数,将cdev添加到系统中去。

第 3185行至3193行,因normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 故没有调用tty_register_device来创建ttyMT0~ttyMT3设备。

第 3194行,调用proc_tty_register_driver创建/proc/tty/driver/mtk-uart文件。其driver->ops->proc_fops 为uart_ops结构体中的uart_proc_fops函数。

回到 uart_register_driver函数,第2276 行调用 put_tty_driver 函数,当注册失败时,判断引用计数注销驱动。

回到 mtk_uart_init 函数,第 2245 行调用 platform_driver_register 函数注册 mtk_uart_dev_drv。



第2223行,mtk_uart_probe函数如下:



第1959行,调用uart_add_one_port向串口驱动添加一个端口。其具体实现在Kernel/drivers/tty/serial/Serial_core.c





第2356行,调用uart_configure_port函数进行端口配置。

第2362行,调用tty_register_device创建ttyMT0~ttyMT3设备。

Mtk-uart平台设备:

Mediatek/platform/mt8127/kernel/core/include/mach/Devs.h



mediatek/platform/mt8127/kernel/core/Mt_devs.c





回到 mtk_uart_init 函数,第 2275 行调用 mtk_uart_init_ops 函数。



回到 mtk_uart_init 函数,第 2277 行调用 mtk_uart_init_debug_spinlock 函数。



整个驱动加载完成后,驱动数据之间的总体关系如下:



kernel/drivers/tty/tty_io.c

tty_open函数:







第1920行retval = tty_alloc_file(filp);//动态分配tty_file_private内存

第1931行tty_open_current_tty(device, filp);//获取当前进程的控制终端

详细查看http://blog.csdn.net/mirkerson/article/details/38107927

第1936行tty_lookup_driver(device, filp, &noctty, &index);//根据device名字,查找驱动并且返回device index。

第1943行tty_driver_lookup_tty(driver, inode, index);//查找tty指针,从uart驱动流程代码看,仅仅是分配指针空间,并没有赋值,即返回的tty为空指针。具体见tty_register_driver函数的3162行。

第1955行,调用tty_init_dev函数初始tty设备



第1409行,分配tty_struct。

第1414行,调用initialize_tty_struct函数对tty_struct进行初始化。



第2946行,调用tty_ldisc_init函数,



第977行调用tty_ldisc_get函数,获取tty_ldisc_N_TTY(n_tty.c).



具体流程如下 :kernel/init/main.c: start_kernel ----> tty_io.c: console_init ----> tty_ldisc.c: tty_ldisc_begin

回到tty_ldisc_init函数,第980行调用tty_ldisc_assign将ld赋值给tty->ldisc。

回到tty_init_dev函数,第1416行调用tty_driver_install_tty函数。



因driver->ops->install为空,即调用tty_standard_install函数。



第1289行将新创建的tty赋值给driver->ttys[tty->index]。

第1283行调用tty_init_termios,



第1267行将init_termios赋值给tp,

第1275、1276行,调用tty_termios_input_baud_rate及tty_termios_baud_rate函数赋值输入输出波特率。

回到tty_init_dev函数,第1425行,调用tty_ldisc_setup函数打开线路规程。具体会调用到tty_ldisc_N_TTY.open函数。

回到tty_open函数。第1966行调用tty_add_file将tty与file关联。

第1976行,调用tty->ops->open(tty, filp);即uart_ops.open

uart_port的初始化(uart.c):



对mtk_uarts结构体成员变量进行初始化。

执行tty_open后,结构图如下:



用户层操作入口为cdev->ops = tty_fops, 在执行tty_open后,会调用mtk_uart_startup函数建立中断机制,

request_irq(port->irq, (irq_handler_t)mtk_uart_irq, IRQF_LEVEL_TRIGGER_POLARITY, DRV_NAME, uart);

与硬件中直接打交道的接口为mtk_uart_ops.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: