uart驱动分析
2014-06-19 21:50
190 查看
。
在这期间有一个问题困扰着我,那就是来自用户空间的针对uart设备的操作意图是如何通过tty框架逐层调用到uart层的core驱动,进而又是如何调用到真实对应于设备的设备驱动的,本文中的对应设备驱动就是8250驱动,最近我想将这方面的内容搞清楚。
在说明这一方面问题之前我们先要大致了解两个基本的框架结构,tty框架和uart框架。
首先看看tty框架:
在linux系统中,tty表示各种终端。终端通常都跟硬件相对应。比如对应于输入设备键盘鼠标,输出设备显示器的控制终端和串口终端。
下面这张图是一张很经典的图了,很清楚的展现了tty框架的层次结构,大家先看图,下面给大家解释。
最上面的用户空间会有很多对底层硬件(在本文中就是8250uart设备)的操作,像read,write等。用户空间主要是通过设备文件同tty_core交互,tty_core根据用空间操作的类型再选择跟line discipline和tty_driver也就是serial_core交互,例如设置硬件的ioctl指令就直接交给serial_core处理。Read和write操作就会交给line discipline处理。Line discipline是线路规程的意思。正如它的名字一样,它表示的是这条终端”线程”的输入与输出规范设置,主要用来进行输入/输出数据的预处理。处理之后,就会将数据交给serial_core,最后serial_core会调用8250.c的操作。
下图是同一样一副经典的uart框架图,将uart重要的结构封装的很清楚,大家且看。
一个uart_driver通常会注册一段设备号.即在用户空间会看到uart_driver对应有多个设备节点。例如:
/dev/ttyS0 /dev/ttyS1 每个设备节点是对应一个具体硬件的,这样就可做到对多个硬件设备的统一管理,而每个设备文件应该对应一个uart_port,也就是说:uart_device要和多个uart_port关系起来。并且每个uart_port对应一个circ_buf(用来接收数据),所以 uart_port必须要和这个缓存区关系起来。
1 自底向上
接下来我们就来看看对设备的操作是怎样进行起来的,不过在此之前我们有必要从底层的uart驱动注册时开始说起,这样到后面才能更清晰。
这里我们讨论的是8250驱动,在驱动起来的时候调用了uart_register_driver(&serial8250_reg);函数将参数serial8250_reg注册进了tty层。具体代码如下所示:
[cpp]view plaincopy
int uart_register_driver(struct uart_driver *drv)
[cpp]view plaincopy
{
struct tty_driver *normal = NULL;
int i, retval;
BUG_ON(drv->state);
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
drv->tty_driver = normal;
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv; // here is important for me, ref uart_open function in this file
tty_set_operations(normal, &uart_ops); //这里把操作函数赋值给了驱动ops
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
state->close_delay = 500;
state->closing_wait = 30000;
mutex_init(&state->mutex);
tty_port_init(&state->info.port);
init_waitqueue_head(&state->info.delta_msr_wait);
tasklet_init(&state->info.tlet, uart_tasklet_action,
(unsigned long)state);
在这期间有一个问题困扰着我,那就是来自用户空间的针对uart设备的操作意图是如何通过tty框架逐层调用到uart层的core驱动,进而又是如何调用到真实对应于设备的设备驱动的,本文中的对应设备驱动就是8250驱动,最近我想将这方面的内容搞清楚。
在说明这一方面问题之前我们先要大致了解两个基本的框架结构,tty框架和uart框架。
首先看看tty框架:
在linux系统中,tty表示各种终端。终端通常都跟硬件相对应。比如对应于输入设备键盘鼠标,输出设备显示器的控制终端和串口终端。
下面这张图是一张很经典的图了,很清楚的展现了tty框架的层次结构,大家先看图,下面给大家解释。
最上面的用户空间会有很多对底层硬件(在本文中就是8250uart设备)的操作,像read,write等。用户空间主要是通过设备文件同tty_core交互,tty_core根据用空间操作的类型再选择跟line discipline和tty_driver也就是serial_core交互,例如设置硬件的ioctl指令就直接交给serial_core处理。Read和write操作就会交给line discipline处理。Line discipline是线路规程的意思。正如它的名字一样,它表示的是这条终端”线程”的输入与输出规范设置,主要用来进行输入/输出数据的预处理。处理之后,就会将数据交给serial_core,最后serial_core会调用8250.c的操作。
下图是同一样一副经典的uart框架图,将uart重要的结构封装的很清楚,大家且看。
一个uart_driver通常会注册一段设备号.即在用户空间会看到uart_driver对应有多个设备节点。例如:
/dev/ttyS0 /dev/ttyS1 每个设备节点是对应一个具体硬件的,这样就可做到对多个硬件设备的统一管理,而每个设备文件应该对应一个uart_port,也就是说:uart_device要和多个uart_port关系起来。并且每个uart_port对应一个circ_buf(用来接收数据),所以 uart_port必须要和这个缓存区关系起来。
1 自底向上
接下来我们就来看看对设备的操作是怎样进行起来的,不过在此之前我们有必要从底层的uart驱动注册时开始说起,这样到后面才能更清晰。
这里我们讨论的是8250驱动,在驱动起来的时候调用了uart_register_driver(&serial8250_reg);函数将参数serial8250_reg注册进了tty层。具体代码如下所示:
[cpp]view plaincopy
int uart_register_driver(struct uart_driver *drv)
[cpp]view plaincopy
{
struct tty_driver *normal = NULL;
int i, retval;
BUG_ON(drv->state);
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
drv->tty_driver = normal;
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv; // here is important for me, ref uart_open function in this file
tty_set_operations(normal, &uart_ops); //这里把操作函数赋值给了驱动ops
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
state->close_delay = 500;
state->closing_wait = 30000;
mutex_init(&state->mutex);
tty_port_init(&state->info.port);
init_waitqueue_head(&state->info.delta_msr_wait);
tasklet_init(&state->info.tlet, uart_tasklet_action,
(unsigned long)state);
相关文章推荐
- UART设备驱动分析
- uart_tty驱动架构分析
- linux终端设备uart驱动分析
- tty初探—uart驱动框架分析(二)uart_add_one_port
- tty初探—uart驱动框架分析
- linux设备模型之uart驱动架构分析
- UART驱动分析
- linux设备模型之uart驱动架构分析
- linux设备模型之uart驱动架构分析
- 嵌入式学习-驱动开发-lesson6.2-UART驱动初始化和open流程分析
- linux设备模型之uart驱动架构分析
- linux设备模型之uart驱动架构分析
- linux设备模型之uart驱动架构分析
- 学习笔记 --- LINUX UART串口驱动框架分析
- (转)eCos驱动分析 之 device安装实例化以及lookup等操作 和 nios uart安装与lookup特别分析实践
- [转]linux设备模型之uart驱动架构分析(开始做驱动!!)
- linux设备模型之uart驱动架构分析
- Linux设备模型之tty&&uart驱动架构分析
- MTK平台 UART驱动代码分析
- 嵌入式学习-驱动开发-lesson6.3-UART驱动send和receive流程分析