ttys和tty_ttyS、tty,console和pty

从图14.2可以看出,特定tty设备驱动的主体工作是填充tty_driver结构体中的成员,实现其中的成员函数,tty_driver结构体的定义如代码清单14.1。代码清单14.1 tty_driver结构体1struct tty_driver

2  {

3    int magic;

4    struct cdev cdev; /*对应的字符设备cdev */

5    struct module *owner;   /*这个驱动的模块拥有者*/

6    const char *driver_name;

7    const char *devfs_name;

8    const char *name;   /*设备名*/

9    int name_base; /* offset of printed name */

10   int major; /*主设备号*/

11   int minor_start; /*开始次设备号*/

12   int minor_num; /*设备数量*/

13   int num; /*被分配的设备数量*/

14   short type; /* tty驱动的类型*/

15   short subtype; /* tty驱动的子类型*/

16   struct termios init_termios; /*初始线路设置*/

17   int flags; /* tty驱动标志*/

18   int refcount; /*引用计数(针对可加载的tty驱动)*/

19   struct proc_dir_entry *proc_entry; /* /proc文件系统入口*/

20   struct tty_driver *other; /*仅对PTY驱动有意义*/

21   ...

22   /*接口函数*/

23   int(*open)(struct tty_struct *tty, struct file *filp);

24   void(*close)(struct tty_struct *tty, struct file *filp);

25   int(*write)(struct tty_struct *tty, const unsigned char *buf, int count);

26   void(*put_char)(struct tty_struct *tty, unsigned char ch);

27   void(*flush_chars)(struct tty_struct *tty);

28   int(*write_room)(struct tty_struct *tty);

29   int(*chars_in_buffer)(struct tty_struct *tty);

30   int(*ioctl)(struct tty_struct *tty, struct file *file, unsigned int cmd,

31     unsigned long arg);

32   void(*set_termios)(struct tty_struct *tty, struct termios *old);

33   void(*throttle)(struct tty_struct *tty);

34   void(*unthrottle)(struct tty_struct *tty);

35   void(*stop)(struct tty_struct *tty);

36   void(*start)(struct tty_struct *tty);

37   void(*hangup)(struct tty_struct *tty);

38   void(*break_ctl)(struct tty_struct *tty, int state);

39   void(*flush_buffer)(struct tty_struct *tty);

40   void(*set_ldisc)(struct tty_struct *tty);

41   void(*wait_until_sent)(struct tty_struct *tty, int timeout);

42   void(*send_xchar)(struct tty_struct *tty, char ch);

43   int(*read_proc)(char *page, char **start, off_t off, int count, int *eof,

44     void *data);

45   int(*write_proc)(struct file *file, const char __user *buffer, unsigned long

46     count, void *data);

47   int(*tiocmget)(struct tty_struct *tty, struct file *file);

48   int(*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set,

49     unsigned int clear);

50

51   struct list_head tty_drivers;

52 };

tty_driver结构体中的magic表示给这个结构体的“幻数”,设为TTY_DRIVER_MAGIC,在 alloc_tty_driver()函数中被初始化。name与driver_name的不同在于后者表示驱动的名字,用在/proc/tty和sysfs中,而前者表示驱动的设备节点名。type与subtype描述tty驱动的类型和子类型,subtype的值依赖于type,type成员的可能值为TTY_DRIVER_TYPE_SYSTEM(由tty子系统内部使用,subtype应当设为SYSTEM_TYPE_TTY、SYSTEM_TYEP_CONSOLE、SYSTEM_TYPE_SYSCONS或SYSTEM_TYPE_SYSPTMX,这个类型不应当被任何常规tty驱动使用)、TTY_DRIVER_TYPE_CONSOLE(仅被控制台驱动使用)、TTY_DRIVER_TYPE_SERIAL(被任何串行类型驱动使用,subtype应当设为SERIAL_TYPE_NORMAL或SERIAL_TYPE_CALLOUT)、TTY_DRIVER_TYPE_PTY(被伪控制台接口pty使用,此时subtype需要被设置为PTY_TYPE_MASTER或PTY_TYPE_SLAVE)。init_termios为初始线路设置,为一个termios结构体,这个成员被用来提供一个线路设置集合。termios用于保存当前的线路设置,这些线路设置控制当前波特率、数据大小、数据流控设置等,这个结构体包含tcflag_t c_iflag(输入模式标志)、tcflag_t c_oflag(输出模式标志)、tcflag_t c_cflag(控制模式标志)、tcflag_t c_lflag(本地模式标志)、cc_t c_line(线路规程类型)、cc_t c_cc[NCCS](一个控制字符数组)等成员。驱动会使用一个标准的数值集初始化这个成员,它拷贝自tty_std_termios变量,tty_std_termos在tty核心中的定义如代码清单14.2。代码清单14.2 tty_std_termios变量1  struct termios tty_std_termios =

2  {

3   .c_iflag = ICRNL | IXON, /*输入模式*/

4   .c_oflag = OPOST | ONLCR, /*输出模式*/

5   .c_cflag = B38400 | CS8 | CREAD | HUPCL, /*控制模式*/

6   .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |

7   ECHOCTL | ECHOKE | IEXTEN,  /*本地模式*/

8   .c_cc = INIT_C_CC  /*控制字符,用来修改终端的特殊字符映射*/

9  };

tty_driver结构体中的major、minor_start、minor_num表示主设备号、次设备号及可能的次设备数,name表示设备名(如ttyS),第23~49行的函数指针实际和tty_operations结构体等同,它们通常需在特定设备tty驱动模块初始化函数中被赋值。put_char()为单字节写函数,当单个字节被写入设备时这个函数被tty核心调用,如果一个tty驱动没有定义这个函数,将使用count参数为1的write()函数。flush_chars()与wait_until_sent()函数都用于刷新数据到硬件。write_room()指示有多少缓冲区空闲,chars_in_buffer()指示缓冲区中包含的数据数。当ioctl(2)在设备节点上被调用时,ioctl()函数将被tty核心调用。当设备的termios设置被改变时,set_termios()函数将被tty核心调用。throttle ()、unthrottle()、stop()和start()为数据抑制函数,这些函数用来帮助控制tty核心的输入缓存。当tty核心的输入缓冲满时,throttle()函数将被调用,tty驱动试图通知设备不应当发送字符给它。当tty核心的输入缓冲已被清空时,unthrottle()函数将被调用暗示设备可以接收数据。stop()和start()函数非常像throttle()和unthrottle()函数,但它们表示tty驱动应当停止发送数据给设备以及恢复发送数据。当tty驱动挂起tty设备时,hangup()函数被调用,在此函数中进行相关的硬件操作。当tty驱动要在RS-232端口上打开或关闭线路的BREAK状态时,break_ctl()线路中断控制函数被调用。如果state状态设为-1,BREAK状态打开,如果状态设为0,BREAK状态关闭。如果这个函数由tty驱动实现,而tty核心将处理TCSBRK、TCSBRKP、TIOCSBRK和TIOCCBRK这些ioctl命令。flush_buffer()函数用于刷新缓冲区并丢弃任何剩下的数据。set_ldisc()函数用于设置线路规程,当tty核心改变tty驱动的线路规程时这个函数被调用,这个函数通常不需要被驱动定义。send_xchar()为X-类型字符发送函数,这个函数用来发送一个高优先级XON或者XOFF字符给tty设备,要被发送的字符在第2个参数ch中指定。read_proc()和write_proc()为/proc读和写函数。tiocmget()函数用于获得tty设备的线路设置,对应的tiocmset()用于设置tty设备的线路设置,参数set和clear包含了要设置或者清除的线路设置。Linux内核提供了一组函数用于操作tty_driver结构体及tty设备,包括:•分配tty驱动struct tty_driver *alloc_tty_driver(int lines);这个函数返回tty_driver指针,其参数为要分配的设备数量,line会被赋值给tty_driver的num成员,例如:xxx_tty_driver = alloc_tty_driver(XXX_TTY_MINORS);

if (!xxx_tty_driver) //分配失败return -ENOMEM;

•注册tty驱动inttty_register_driver(struct tty_driver *driver);注册tty驱动成功时返回0,参数为由alloc_tty_driver ()分配的tty_driver结构体指针,例如:retval = tty_register_driver(xxx_tty_driver);

if (retval) //注册失败{

printk(KERN_ERR "failed to register tiny tty driver");

put_tty_driver(xxx_tty_driver);

return retval;

}

•注销tty驱动inttty_unregister_driver(struct tty_driver *driver);这个函数与tty_register_driver ()对应,tty驱动最终会调用上述函数注销tty_driver。•注册tty设备void tty_register_device(struct tty_driver *driver, unsigned index,

struct device *device);仅有tty_driver是不够的,驱动必须依附于设备,tty_register_device()函数用于注册关联于tty_driver的设备,index为设备的索引(范围是0~driver->num),如:for (i = 0; i < XXX_TTY_MINORS; ++i)

tty_register_device(xxx_tty_driver, i, NULL);

•注销tty设备void tty_unregister_device(struct tty_driver *driver, unsigned index);上述函数与tty_register_device()对应,用于注销tty设备,其使用方法如:for (i = 0; i < XXX_TTY_MINORS; ++i)

tty_unregister_device(xxx_tty_driver, i);

•设置tty驱动操作void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);上述函数会将tty_operations结构体中的函数指针拷贝给tty_driver对应的函数指针,在具体的tty驱动中,通常会定义1个设备特定的tty_operations,tty_operations的定义如代码清单14.3。tty_operations中的成员函数与tty_driver中的同名成员函数意义完全一致,因此,这里不再赘述。代码清单14.3 tty_operations结构体1  struct tty_operations

2  {

3     int  (*open)(struct tty_struct * tty, struct file * filp);

4     void (*close)(struct tty_struct * tty, struct file * filp);

5     int  (*write)(struct tty_struct * tty,

6                   const unsigned char *buf, int count);

7     void (*put_char)(struct tty_struct *tty, unsigned char ch);

8     void (*flush_chars)(struct tty_struct *tty);

9     int  (*write_room)(struct tty_struct *tty);

10    int  (*chars_in_buffer)(struct tty_struct *tty);

11    int  (*ioctl)(struct tty_struct *tty, struct file * file,

12                unsigned int cmd, unsigned long arg);

13    void (*set_termios)(struct tty_struct *tty, struct termios * old);

14    void (*throttle)(struct tty_struct * tty);

15    void (*unthrottle)(struct tty_struct * tty);

16    void (*stop)(struct tty_struct *tty);

17    void (*start)(struct tty_struct *tty);

18    void (*hangup)(struct tty_struct *tty);

19    void (*break_ctl)(struct tty_struct *tty, int state);

20    void (*flush_buffer)(struct tty_struct *tty);

21    void (*set_ldisc)(struct tty_struct *tty);

22    void (*wait_until_sent)(struct tty_struct *tty, int timeout);

23    void (*send_xchar)(struct tty_struct *tty, char ch);

24    int (*read_proc)(char *page, char **start, off_t off,

25                      int count, int *eof, void *data);

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()等函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值