第14章 Linux终端设备驱动之终端设备驱动初始化与释放

14.3 终端设备驱动初始化与释放

14.3.1 模块加载与卸载函数

    tty 驱动的模块加载函数中通常需要分配、初始化 tty_driver 结构体并申请必要的硬件资源,如代码清单 14.4。tty 驱动的模块卸载函数完成与模块加载函数相反的工作

代码清单 14.4 终端设备驱动模块加载函数

/* tty 驱动模块加载函数 */

static int __init tty3270_init(void)
{
struct tty_driver *driver;
int ret;

driver = alloc_tty_driver(RAW3270_MAXDEVS);/* 分配 tty_driver 结构体 */
if (!driver)
return -ENOMEM;
        /* 初始化 tty_driver 结构体 */
driver->owner = THIS_MODULE;
driver->driver_name = "ttyTUB";
driver->name = "ttyTUB";
driver->major = IBM_TTY3270_MAJOR;
driver->minor_start = RAW3270_FIRSTMINOR;
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
printk(KERN_ERR "tty3270 registration failed with %d\n", ret);
put_tty_driver(driver);
return ret;
}
tty3270_driver = driver;
ret = raw3270_register_notifier(tty3270_notifier);
if (ret) {
printk(KERN_ERR "tty3270 notifier registration failed " "with %d\n", ret);
put_tty_driver(driver);
return ret;

}

        .....................................................

        ret = request_irq(...); /* 硬件资源申请 */

        .....................................................

return 0;
}

14.3.2 打开与关闭函数

    当用户对 tty 驱动所分配的设备节点进行 open()系统调用时,tty_driver 所拥有的 tty_operations中的 open()成员函数将被 tty 核心调用。tty 驱动必须设置 open()成员,否则,-ENODEV 将被返回给调用 open()的用户。

    open()成员函数的第 1 个参数为一个指向分配给这个设备的 tty_struct 结构体的指针,第 2 个参数为文件指针。

    tty_struct 结构体被 tty 核心用来保存当前 tty 端口的状态,大多数成员只被 tty 核心使用。 tty_struct 结构体的定义如下:

include/linux/tty.h

struct tty_struct {
        int     magic;
        struct tty_driver *driver;
        int index;
        struct tty_ldisc ldisc;
        struct mutex termios_mutex;
        struct ktermios *termios, *termios_locked;
        char name[64];
        struct pid *pgrp;
        struct pid *session;
        unsigned long flags;
        int count;
        struct winsize winsize;
        unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
        unsigned char low_latency:1, warned:1;
        unsigned char ctrl_status;
        unsigned int receive_room;      /* Bytes free for queue */

        struct tty_struct *link;
        struct fasync_struct *fasync;
        struct tty_bufhead buf;
        int alt_speed;          /* For magic substitution of 38400 bps */
        wait_queue_head_t write_wait;
        wait_queue_head_t read_wait;
        struct work_struct hangup_work;
        void *disc_data;
        void *driver_data;
        struct list_head tty_files;

#define N_TTY_BUF_SIZE 4096

        /*
         * The following is data for the N_TTY line discipline.  For
         * historical reasons, this is included in the tty structure.
         */
        unsigned int column;
        unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
        unsigned char closing:1;
        unsigned short minimum_to_wake;
        unsigned long overrun_time;
        int num_overrun;
        unsigned long process_char_map[256/(8*sizeof(unsigned long))];
        char *read_buf;
        int read_head;
        int read_tail;
        int read_cnt;
        unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
        int canon_data;
        unsigned long canon_head;
        unsigned int canon_column;
        struct mutex atomic_read_lock;
        struct mutex atomic_write_lock;
        unsigned char *write_buf;
        int write_cnt;
        spinlock_t read_lock;
        /* If the tty has a pending do_SAK, queue it here - akpm */
        struct work_struct SAK_work;
};

分析:

(1)flags 标示tty 设备的当前状态

(2)ldisc 为给 tty 设备的线路规程

(3)write_wait、read_wait 为给 tty 写/读函数的等待队列,tty 驱动应在合适的时机唤醒对应的等待队列。

(4)termios 为指向 tty 设备的当前 termios 设置的指针

(5)stopped:1 指示是否停止 tty 设备,tty 驱动可以设置这个值;hw_stopped:1 指示是否 tty设备已经被停止,tty 驱动可以设置这个值;flow_stopped:1 指示是否 tty 设备数据流停止。

(6)driver_data、disc_data 为数据指针,用于存储 tty 驱动和线路规程的“私有”数据。

    驱动中可以定义一个设备相关的结构体,并在open()函数中将其赋值给tty_struct的driver_data成员,如代码清单 14.5。

代码清单 14.5 在 tty 驱动打开函数中赋值tty_struct 的 driver_data 成员

    /* 设备“私有”数据结构体 */
 struct xxx_tty {
         struct tty_struct *tty; /* tty_struct 指针 */
         int open_count; /* 打开次数 */
         struct semaphore sem; /* 结构体锁定信号量 */
         intxmit_buf; /* 传输缓冲区 */
         ...

 }

/* 打开函数 */
 static int xxx_open(struct tty_struct *tty, struct file *file)
 {
         struct xxx_tty *xxx;

         /* 分配 xxx_tty 内存*/
        xxx = kmalloc(sizeof(*xxx), GFP_KERNEL);
         if (!xxx)
                 return - ENOMEM;
         /* 初始化 xxx_tty 中的成员 */
         init_MUTEX(&xxx->sem);
         xxx->open_count = 0;
          ...
         /* 让 tty_struct  中的 driver_data 指向 xxx_tty */
         tty->driver_data = xxx;
         xxx->tty = tty;
         ...
         return 0;
 }

    在用户对前面使用 open()系统调用而创建的文件句柄进行 close()系统调用时,tty_driver 所拥有的 tty_operations 中的 close()成员函数将被 tty 核心调用。


猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/80689983