前言
内核版本4.4
平台 瑞芯微RK3399 8250串口
一、驱动整体框架
二、驱动结构体对象
1. struct uart_driver 串口驱动主要结构体,记录各个层对象,(tty层,和uart层)
2. |---struct tty_driver tty层结构体
3. |---struct uart_state uart层结构体
4. |---struct tty_port
5. |---struct uart_port 每个结构体对应硬件上每个uart
关系如下图所示
三、驱动代码流程
驱动加载由以下入口
8250_core.c-----> static int __init serial8250_init(void)这部分创建uart_driver结构体对象,结合上图,该结构体维系tty层与core层关系。
8250_dw.c-----> static int dw8250_probe(struct platform_device *pdev)这部分创建platform_driver,注册设备树中的uart口,生成uart_port对象,记录于uart_state中
1.8250_core.c的serial8250_init
个人理解代码里有三套串口设备注册代码,
方式一,嵌入式常用的方式,驱动通过与dts硬件信息匹配注册uart_port
方式二,PC机常用方式,注册PNP驱动,扫描PNP设备完成注册,
(PNP理解应该是pc板卡的superIO,比如PNP0501转换芯片可实现较少的GPIO转出多个GPIO和5个串口)
方式三,内核提供的初始化uart_port硬件信息的方式,目前看一般不用到。
参考链接: 内核实现的注册uart_port方式
注册对象:
struct uart_driver serial8250_reg
serial8250_init函数中主要代码:
ret = uart_register_driver(&serial8250_reg);
该函数主要完成以下动作:
(1)申请uart_state内存空间,uart_driver->uart_state[nr]
(2)申请tty_driver内存空间,并初始化成员
(3)初始化tty_port
(4)注册tty_driver驱动
2.8250_dw.c-----> static int dw8250_probe
static struct platform_driver dw8250_platform_driver = {.driver = {.name = "dw-apb-uart",.pm = &dw8250_pm_ops,.of_match_table = dw8250_of_match,.acpi_match_table = ACPI_PTR(dw8250_acpi_match),},.probe = dw8250_probe,.remove = dw8250_remove,
};module_platform_driver(dw8250_platform_driver);
static int dw8250_probe(struct platform_device *pdev)
这个驱动入口通过platform总线,.of_match_table = dw8250_of_match,通过名字table与设备树信息匹配。调用probe函数(.probe = dw8250_probe)
dw8250_probe函数主要完成以下动作
(1)声明临时变量struct uart_8250_port uart,初始化uart成员uart_port的参数,
(2)获取串口编号(硬件上uart0,uart1的序号0,1),赋值给临时变量uart_port中
(3)data->line = serial8250_register_8250_port(&uart);
uart = serial8250_find_match_or_unused(&up->port);
根据(2)的串口编号,从前面初始化的static struct uart_8250_port serial8250_ports[UART_NR]数组中获取相应的uart_port,再将临时变量uart_port的初始值传给获取到的uart_port
(4)ret = uart_add_one_port(&serial8250_reg, &uart->port);
四、串口读写流程
五、代码文件
driver/tty/serial/8250/8250_core.c
8250_dw.c