设备模型之终端设备(tty)驱动架构分析.pdf
《设备模型之终端设备(tty)驱动架构分析.pdf》由会员分享,可在线阅读,更多相关《设备模型之终端设备(tty)驱动架构分析.pdf(37页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Linux 设备模型之终端设备(tty)驱动架构分析*本文系本站原创,欢迎转载!转载请注明出处:http:/ 这里感谢:晓刚的分析和指点,及网上的所有串口资源*一:前言 一:前言 终端设备 在 Linux 系统中,终端是一种字符型设备,它有多种类型,通常使用 tty 来简称各种类型的终端设备。tty 是 Teletype 的缩写,Teletype 是最早出现的一种终端设备,很像电传打字机,是由 Teletype 公司生产的。Linux 中包含如下几类终端设备:1.串行端口终端(/dev/ttySn)串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。2.
2、伪终端(/dev/pty/)伪终端(Pseudo Terminal)是成对的逻辑终端设备 3.控制台终端(/dev/ttyn,/dev/console)二:终端设备驱动结构 二:终端设备驱动结构 1.Tty 架构如下所示Tty 架构如下所示:Tty_core:Tty_core:Tty 核心层 Line discipline:Line discipline:是线路规程的意思(链路层)。正如它的名字一样,它表示的是这条终端”线程”的输入与输出规范设置.主要用来进行输入/输出数据的预处理 Tty_driver:Tty_driver:Tty_driver就是终端对应的驱动了。它将字符转换成终端可以理解
3、的字串.将其传给终端设备。tty 设备发送数据的流程为:tty 设备发送数据的流程为:tty_core 从一个用户获得将要发送给一个 tty 设备的数据,tty_core 将数据传递给 Line discipline 处理,接着数据被传递到 tty_driver,tty 驱动将数据转换为可以发送给硬件的格式 tty 设备接受数据的流程为:tty 设备接受数据的流程为:从 tty 硬件接收到得数据向上交给 tty_driver,进入 Line discipline 处理,再进入tty_core,在这里它被一个用户获取 尽管大多数时候 tty_core 和 tty_driver 之间的数据传输会经
4、历 Line discipline 的转换,但是 tty_core 和 tty_driver 之间也可以直接传输数据 2.tty 主要源文件关系及数据流向:2.tty 主要源文件关系及数据流向:图二:tty 主要源文件关系及数据流向 上图显示了与 tty 相关的主要源文件及数据流向。tty_io.c:tty_io.c:tty_io.c 定义了 tty 设备通用的的 file_operation 结构体,并实现了接口函数 tty_register_driver()用于注册 tty 设备,它会利用 fs/char_dev.c 提供的接口函数注册字符设备。tty_io.c 也提供了 tty_regi
5、ster_ldisc()接口函数,用于注册线路规程。xxx_tty.cxxx_tty.c:与具体设备对应的 tty 驱动(xxx_tty.c)将实现 tty_driver 结构体中的成员函数。Ntty.cNtty.c:ntty.c 文件则实现了 tty_disc 结构体中的成员 特定 tty 设备的主体工作是填充 tty_driver 结构体中的成员,实现其中的成员函数,tty_driver 结构体的源码(linux/driver/char/tty_driver.h)如下:struct tty_driver int magic;/*magic number for this structure
6、*/struct cdev cdev;struct module*owner;const char*driver_name;const char*devfs_name;const char*name;int name_base;/*offset of printed name*/int major;/*major device number*/int minor_start;/*start of minor device number*/int minor_num;/*number of*possible*devices*/int num;/*number of devices allocat
7、ed*/short type;/*type of tty driver*/short subtype;/*subtype of tty driver*/struct termiostermios init_termios;/*Initial termios*/int flags;/*tty driver flags*/int refcount;/*for loadable tty drivers*/struct proc_dir_entry*proc_entry;/*/proc fs entry*/struct tty_driver*other;/*only used for the PTY
8、driver*/*Pointer to the tty data structures */struct tty_struct*ttys;struct termios*termios;struct termios*termios_locked;void*driver_state;/*only used for the PTY driver*/*Interface routines from the upper tty layer to the tty *driver.Will be replaced with struct tty_operations.*/int (*open)(struct
9、 tty_struct*tty,struct file*filp);void(*close)(struct tty_struct*tty,struct file*filp);int (*write)(struct tty_struct*tty,const unsigned char*buf,int count);void(*put_char)(struct tty_struct*tty,unsigned char ch);void(*flush_chars)(struct tty_struct*tty);int (*write_room)(struct tty_struct*tty);int
10、(*chars_in_buffer)(struct tty_struct*tty);int (*ioctl)(struct tty_struct*tty,struct file*file,unsigned int cmd,unsigned long arg);void(*set_termios)(struct tty_struct*tty,struct termios*old);void(*throttle)(struct tty_struct*tty);void(*unthrottle)(struct tty_struct*tty);void(*stop)(struct tty_struct
11、*tty);void(*start)(struct tty_struct*tty);void(*hangup)(struct tty_struct*tty);void(*break_ctl)(struct tty_struct*tty,int state);void(*flush_buffer)(struct tty_struct*tty);void(*set_ldisc)(struct tty_struct*tty);void(*wait_until_sent)(struct tty_struct*tty,int timeout);void(*send_xchar)(struct tty_s
12、truct*tty,char ch);int(*read_proc)(char*page,char*start,off_t off,int count,int*eof,void*data);int(*write_proc)(struct file*file,const char _user*buffer,unsigned long count,void*data);int(*tiocmget)(struct tty_struct*tty,struct file*file);int(*tiocmset)(struct tty_struct*tty,struct file*file,unsigne
13、d int set,unsigned int clear);struct list_head tty_drivers;三:tty 驱动接口分析 三:tty 驱动接口分析 1.分配 tty 驱动 1.分配 tty 驱动 tty driver 的所有操作都包含在tty_driver 中。内核即供了一个名叫alloc_tty_driver()来分配这个 tty_driver。当然我们也可以在自己的驱动中将它定义成一个静态的结构。对tty_driver 进行一些必要的初始化之后,调用 tty_register_driver()将其注册.alloc_tty_driver()接口代码(Linux/driv
14、er/char/tty_io.c)如下所示:struct tty_driver*alloc_tty_driver(int lines)struct tty_driver*driver;driver=kmalloc(sizeof(struct tty_driver),GFP_KERNEL);if(driver)memset(driver,0,sizeof(struct tty_driver);driver-magic=TTY_DRIVER_MAGIC;driver-num=lines;/*later well move allocation of tables here*/return driv
15、er;这个函数只有一个参数。这个参数的含义为 line 的个数。也即次设备号的个数。注意每个设备文件都会对应一个 line.在这个接口里为 tty_driver 分配内存,然后将 driver-magic 与 driver-num 初始化之后就 返 回 了.其 中 driver-magic 为 tty_driver 这 个 结 构 体 的“幻 数”,设 为TTY_DRIVER_MAGIC,在这里被初始化。2.注册 tty 驱动 2.注册 tty 驱动 在 这 里,tty_register_driver()用 来 注 册 一 个tty_driver,源 码 如 下(Linux/driver/ch
16、ar/tty_io.c):int tty_register_driver(struct tty_driver*driver)int error;int i;dev_t dev;void*p=NULL;if(driver-flags&TTY_DRIVER_INSTALLED)return 0;/TTY_DRIVER_DEVPTS_MEM:使用 devpts 进行动态内存映射 if(!(driver-flags&TTY_DRIVER_DEVPTS_MEM)p=kmalloc(driver-num*3*sizeof(void*),GFP_KERNEL);if(!p)return-ENOMEM;mem
17、set(p,0,driver-num*3*sizeof(void*);/如果没有指定 driver-major,注册字符设备号 if(!driver-major)error=alloc_chrdev_region(&dev,driver-minor_start,driver-num,(char*)driver-name);if(!error)driver-major=MAJOR(dev);driver-minor_start=MINOR(dev);else dev=MKDEV(driver-major,driver-minor_start);error=register_chrdev_regi
18、on(dev,driver-num,(char*)driver-name);if(error ttys=(struct tty_struct*)p;driver-termios=(struct termios*)(p+driver-num);driver-termios_locked=(struct termios*)(p+driver-num*2);else driver-ttys=NULL;driver-termios=NULL;driver-termios_locked=NULL;/注册字符设备 cdev_init(&driver-cdev,&tty_fops);driver-cdev.
19、owner=driver-owner;error=cdev_add(&driver-cdev,dev,driver-num);if(error)cdev_del(&driver-cdev);unregister_chrdev_region(dev,driver-num);driver-ttys=NULL;driver-termios=driver-termios_locked=NULL;kfree(p);return error;/指定默认的 put_char if(!driver-put_char)driver-put_char=tty_default_put_char;list_add(&
20、driver-tty_drivers,&tty_drivers);/如果没有指定 TTY_DRIVER_DYNAMIC_DEV.即动态设备管理 if(!(driver-flags&TTY_DRIVER_NO_DEVFS)for(i=0;i num;i+)tty_register_device(driver,i,NULL);proc_tty_register_driver(driver);return 0;注册 tty 驱动成功时返回 0;参数为由 alloc_tty_driver()分配的 tty_driver 结构体指针。这个函数操作比较简单。就是为 tty_driver 创建字符设备。然后
21、将字符设备的操作集指定为 tty_fops.并且将 tty_driver 挂载到 tty_drivers 链表中。以设备号为关键字找到对应的 driver.四:设备文件的打开操作 四:设备文件的打开操作 1.打开 tty 设备的操作 1.打开 tty 设备的操作 在下面得程序里,我们会遇到 tty_struct 结构体,tty_struct 结构体被 tty 核心用来保存当前 tty 端口的状态,它的大多数成员只被 tty 核心使用。从注册的过程可以看到,所有的操作都会对应到 tty_fops 中。Open 操作对应的操作接口是tty_open()。代码如下(linux/drivers/cha
22、r/tty_io.c):static int tty_open(struct inode*inode,struct file*filp)struct tty_struct*tty;int noctty,retval;struct tty_driver*driver;int index;dev_t device=inode-i_rdev;unsigned short saved_flags=filp-f_flags;nonseekable_open(inode,filp);retry_open:/*O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制端 noctty:需不需要更改当前
23、进程的控制终端*/noctty=filp-f_flags&O_NOCTTY;index =-1;retval=0;/*O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端*/down(&tty_sem);/设备号(5,0)即/dev/tty.表示当前进程的控制终端 if(device=MKDEV(TTYAUX_MAJOR,0)if(!current-signal-tty)/如果当前进程的控制终端不存在,退出 up(&tty_sem);return-ENXIO;/取得当前进程的 tty_driver driver=current-signal-tty-driver;index=c
24、urrent-signal-tty-index;filp-f_flags|=O_NONBLOCK;/*Dont let/dev/tty block*/*noctty=1;*/goto got_driver;#ifdef CONFIG_VT/打开的设备节点是否是当前的控制终断/dev/ttys0/(4,0)if(device=MKDEV(TTY_MAJOR,0)extern struct tty_driver*console_driver;driver=console_driver;/fg_console:表示当前的控制台 index=fg_console;noctty=0;goto got_d
25、river;#endif/设备号(5,1).即/dev/console.表示外接的控制台.通过 regesit_console()if(device=MKDEV(TTYAUX_MAJOR,1)driver=console_device(&index);if(driver)/*Dont let/dev/console block*/filp-f_flags|=O_NONBLOCK;noctty=0;goto got_driver;up(&tty_sem);return-ENODEV;/index 就是文件的设备号/以文件的设备号为关键字,到 tty_drivers 中搜索所注册的 driver
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 设备 模型 终端设备 tty 驱动 架构 分析
限制150内