tty设备驱动注册简述

注意 :因为 tty_driver核心层 和 uart_driver 设备层 的注册是绑在一起的, 
所以把 核心层和设备层一起分析

一:tty设备驱动关键步骤

   设备驱动层的注册其实一共只有三步骤:
    1 构造 uart设备相关驱动结构体
    2 uart_register_driver{tty_register_driver}//同时注册了tty_driver
    3 uart_add_one_port

/kenrel/drivers/tty/serial XXX_uart.c

1

struct XXX_port{
    struct uart_port port;
.....
}     

static struct uart_driver XXX_uart_driver{
owner:     THIS_MODULE,
major:     SERIAL_WK2XXX_MAJOR,
driver_name:   "ttySWK",
dev_name:      "ttysWK",
minor:    MINOR_START,
nr:       NR_PORTS,
cons:     NULL//WK2Xxx_CONSOLE,  
}

static struct uart_ops wk2xxx_pops = {
    tx_empty:       wk2xxx_tx_empty,
    set_mctrl:      wk2xxx_set_mctrl,
    get_mctrl:      wk2xxx_get_mctrl,
    stop_tx:        wk2xxx_stop_tx,
    start_tx:       wk2xxx_start_tx,
    stop_rx:        wk2xxx_stop_rx,
    enable_ms:      wk2xxx_enable_ms,
    break_ctl:      wk2xxx_break_ctl,
    startup:        wk2xxx_startup,
    shutdown:       wk2xxx_shutdown,
set_termios:    wk2xxx_termios,
    type:           wk2xxx_type,
    release_port:   wk2xxx_release_port,
    request_port:   wk2xxx_request_port,
    config_port:    wk2xxx_config_port,
    verify_port:    wk2xxx_verify_port,

};

2

//其实 tty_driver  就是 uart_driver 的另一个封装
int uart_register_driver(struct uart_driver *drv)  
{  
    struct tty_driver *normal = NULL;  
    int i, retval;  

//根据driver支持的最大设备数,申请n个 uart_state 空间,每一个 uart_state 都有一个uart_port
    drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);  

//tty层:分配一个 tty_driver ,并将drv->tty_driver 指向它 uart_driver->tty_driver
    normal  = alloc_tty_driver(drv->nr);  
    drv->tty_driver = normal;  

//对 tty_driver 进行设置
    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;  

//设置tty_driver 的操作函数集 为 uart_ops函数集
//  tty_driver->ops  =  tty_operations uart_ops
    tty_set_operations(normal, &uart_ops);  


//初始化 uart_state,此时并没用和具体的 uart_port 对应起来;
    for (i = 0; i < drv->nr; i++) {  
        struct uart_state *state = drv->state + i;  
        struct tty_port *port = &state->port;    /* driver->state->tty_port */  

        tty_port_init(port);  
        port->close_delay     = 500; /* .5 seconds */  
        port->closing_wait    = 30000;   /* 30 seconds */  
        /* 初始化 tasklet */  
        tasklet_init(&state->tlet, uart_tasklet_action,  
                 (unsigned long)state);  
    }  

//tty层:注册 driver->tty_driver */  
    retval = tty_register_driver(normal);  

}  
2.1
        //为 tty_driver 创建字符设备、挂载tty_driver到链表、创建proc下的节点、
        //此处注册了tty_driver驱动(添加链表)、但是还没有对接任何物理端口(uart_port)、
        //也没有创建 /dev/ 下的任何设备节点;
        int tty_register_driver(struct tty_driver *driver)
        {
            int error;
            int i;
            dev_t dev;
            struct device *d;

            //申请主设备号
            if (!driver->major) {
                error = alloc_chrdev_region(&dev, driver->minor_start,
                                driver->num, driver->name);
                if (!error) {
                    driver->major = MAJOR(dev);
                    driver->minor_start = MINOR(dev);
                }
            } else {
                dev = MKDEV(driver->major, driver->minor_start);
                error = register_chrdev_region(dev, driver->num, driver->name);
            }
            if (error < 0)
                goto err;

            //添加一个自字符设备,file_operations和设备号关联起来,
            if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
                error = tty_cdev_add(driver, dev, 0, driver->num);
                if (error)
                    goto err_unreg_char;
            }

            //将该driver->tty_drivers 添加到 全局tty_drivers链表 
            mutex_lock(&tty_mutex);
            list_add(&driver->tty_drivers, &tty_drivers);
            mutex_unlock(&tty_mutex);

            if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
                for (i = 0; i < driver->num; i++) {
                    d = tty_register_device(driver, i, NULL);
                    if (IS_ERR(d)) {
                        error = PTR_ERR(d);
                        goto err_unreg_devs;
                    }
                }
            }

            /* proc 文件系统注册driver */  
            proc_tty_register_driver(driver);
            driver->flags |= TTY_DRIVER_INSTALLED;
            return 0;
            .....
        }

3

//为 uart_driver(tty_driver) 添加端口、
//最终上层可以通过 ->tty_driver->uart_driver->uart_port->uart_ops 操作底层
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
    struct uart_state *state;
    struct tty_port *port;
    int ret = 0;
    struct device *tty_dev;
    int num_groups;

    ....

//将 uart_port 绑定到 uart_driver 的 state 
    state->uart_port = uport;
    uport->state = state;
    ....

//创建设备节点(有点特别)
    tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
            uport->line, uport->dev, port, uport->tty_groups);
            {
                tty_line_name(driver, index, name);
                 ....
                    dev->devt = devt;
                    dev->class = tty_class;
                    dev->parent = device;
                    dev->release = tty_device_create_release;
                    dev_set_name(dev, "%s", name);
                    dev->groups = attr_grp;
                    dev_set_drvdata(dev, drvdata);

                    retval = device_register(dev);
            }
    ....
}

二 :汇总:上述代码工作汇总如下:

2.1 :

uart_register_driver
{
    1 // 根据平台支持的串口数目 申请 N 个uart_state 空间
    2 // 分配一个tty_driver,并且绑定到 uart_driver->tty_driver
    3 // 对 tty_driver 进行设置,拷贝 uart_driver 的参数(tty_driver == uart_driver)
    4 // 设置 tty_driver 的操作函数为 struct tty_operations uart_ops
    5 // 初始化uart_state,但是此时并没有和具体 uart_port 物理端口对应起来
    6 // 注册 tty_driver  tty_register_driver
       tty_register_driver
        {   
            6.1 //申请设备号
            6.2 //添加一个字符设备,file_operations,但此时并没有设备节点的创建
            6.3 //将 tty_drivers 添加到 全局tty_drivers链表
            6.4 //向proc文件系统注册 tty_drivers
        }
}

2.2:

uart_add_one_port
{
    1 //将 uart_port 绑定到 uart_driver->uart_state
    2 //创建设备节点
}

三 :总结

疑问:通过研究代码发现 tty_driver 和 uart_driver 两个结构体的成员很相似,并且在
      注册 uart_driver 的时候,会将 uart_driver 的很多参数传递赋值给 tty_driver 
      的同名参数,这两个结构体至今有啥关系吗?

答案:前面说到,tty作为终端设备,按照LDD3的说法,tty类型的终端设备分为三种类型 
      串口终端、虚拟终端、控制台终端;tty_driver->type 参数就是终端驱动类型的标志
      type 由 uart_driver->type 传入。所以可以理解为 tty_driver代表的是 串口终端
      uart_driver 、虚拟终端uart_driver 、 控制台终端uart_driver 三种类型终端驱动
      的一个抽象,这个抽象是给上层用的,用来区分出底层的设备驱动是哪一种类型的驱动

小结:在注册设备驱动 uart_driver 的同时 向上注册由 uart_driver 抽象出来的 tty_driver 驱动
      向下 创建 uart_state 、 并且绑定 uart_port 到 uart_driver->uart_state;这样就将底层设备
      驱动和核心层联系起来了;

猜你喜欢

转载自blog.csdn.net/linuxarmbiggod/article/details/78879919