迷路庄的惨剧 电影:Linux终端设备驱动(理顺概念)(6)

来源:百度文库 编辑:中财网 时间:2024/05/04 13:10:50
26    int (*write_proc)(struct file *file, const char __user *buffer,
27                      unsigned long count, void *data);
28    int (*tiocmget)(struct tty_struct *tty, struct file *file);
29    int (*tiocmset)(struct tty_struct *tty, struct file *file,
30                         unsigned int set, unsigned int clear);
31 };
    终端设备驱动都围绕tty_driver结构体而展开,一般而言,终端设备驱动应包含如下组成:
?  终端设备驱动模块加载函数和卸载函数,完成注册和注销tty_driver,初始化和释放终端设备对应的tty_driver结构体成员及硬件资源。
?  实现tty_operations结构体中的一系列成员函数,主要是实现open()、close()、write()、tiocmget()、tiocmset()等函数。


14.3终端设备驱动初始化与释放
14.3.1模块加载与卸载函数
    tty驱动的模块加载函数中通常需要分配、初始化tty_driver结构体并申请必要的硬件资源,代码清单14.4。tty驱动的模块卸载函数完成与模块加载函数完成相反的工作。
代码清单14.4 终端设备驱动模块加载函数范例
1  /* tty驱动模块加载函数 */
2  static int __init xxx_init(void)
3  {
4    ...
5    /* 分配tty_driver结构体 */
6    xxx_tty_driver = alloc_tty_driver(XXX_PORTS);
7    /* 初始化tty_driver结构体 */
8    xxx_tty_driver->owner = THIS_MODULE;
9    xxx_tty_driver->devfs_name = "tts/";
10   xxx_tty_driver->name = "ttyS";
11   xxx_tty_driver->major = TTY_MAJOR;
12   xxx_tty_driver->minor_start = 64;
13   xxx_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
14   xxx_tty_driver->subtype = SERIAL_TYPE_NORMAL;
15   xxx_tty_driver->init_termios = tty_std_termios;
16   xxx_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
17   xxx_tty_driver->flags = TTY_DRIVER_REAL_RAW;
18   tty_set_operations(xxx_tty_driver, &xxx_ops);
19
20   ret = tty_register_driver(xxx_tty_driver);
21   if (ret)
22   {
23     printk(KERN_ERR "Couldn't register xxx serial driver\n");
24     put_tty_driver(xxx_tty_driver);
25     return ret;
26   }
27
28   ...
29   ret = request_irq(...); /* 硬件资源申请 */
30   ...
31 }
14.3.2打开与关闭函数
    当用户对tty驱动所分配的设备节点进行open()系统调用时,tty_driver中的open()成员函数将被tty核心调用。tty 驱动必须设置open()成员,否则,-ENODEV将被返回给调用open()的用户。open()成员函数的第1个参数为一个指向分配给这个设备的 tty_struct 结构体的指针,第2个参数为文件指针。
tty_struct结构体被 tty核心用来保存当前tty端口的状态,它的大多数成员只被 tty核心使用。tty_struct中的几个重要成员如下:
?  flags标示tty 设备的当前状态,包括TTY_THROTTLED、TTY_IO_ERROR、TTY_OTHER_CLOSED、TTY_EXCLUSIVE、 TTY_DEBUG、TTY_DO_WRITE_WAKEUP、TTY_PUSH、TTY_CLOSING、TTY_DONT_FLIP、 TTY_HW_COOK_OUT、TTY_HW_COOK_IN、TTY_PTY_LOCK、TTY_NO_WRITE_SPLIT等。
?  ldisc为给 tty 设备的线路规程。
?  write_wait、read_wait为给tty写/读函数的等待队列,tty驱动应当在合适的时机唤醒对应的等待队列。
?  termios为指向 tty 设备的当前 termios 设置的指针。
?  stopped:1指示是否停止tty设备,tty 驱动可以设置这个值;hw_stopped:1指示是否tty设备已经被停止,tty 驱动可以设置这个值;flow_stopped:1指示是否 tty 设备数据流停止。
?  driver_data、disc_data为数据指针,用于存储tty驱动和线路规程的“私有”数据。
驱动中可以定义1个设备相关的结构体,并在open()函数中将其赋值给tty_struct的driver_data成员,如代码清单14.5。
代码清单14.5 在tty驱动打开函数中赋值tty_struct的driver_data成员
1  /* 设备“私有”数据结构体 */
2  struct xxx_tty
3  {
4    struct tty_struct *tty; /* tty_struct指针 */
5    int open_count; /* 打开次数 */
6    struct semaphore sem; /* 结构体锁定信号量 */
7    int xmit_buf; /* 传输缓冲区 */
8    ...
9  }
10
11 /* 打开函数 */
12 static int xxx_open(struct tty_struct *tty, struct file *file)
13 {
14   struct xxx_tty *xxx;
15
16   /* 分配xxx_tty */
17   xxx = kmalloc(sizeof(*xxx), GFP_KERNEL);
18   if (!xxx)
19     return  - ENOMEM;