您的位置:首页 > 其它

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); 

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: