《【华清远见10年特献】《linux设备驱动开发详解》第14章、linux终端设备驱动》由会员分享,可在线阅读,更多相关《【华清远见10年特献】《linux设备驱动开发详解》第14章、linux终端设备驱动(41页珍藏版)》请在金锄头文库上搜索。
1、 LINUX 设备驱动开发详解 作者:华清远见 第第 14 章章 Linux 终端设备驱动终端设备驱动 本章简介 在 Linux 系统中,终端设备非常重要,没有终端设备,系统将无法向用户反馈 信息,Linux 系统中包含控制台、串口和伪终端 3 类终端设备。 14.1 节阐述了终端设备的概念及分类,14.2 节给出了 Linux 终端设备驱动的框 架结构,重点讲解 tty_driver 结构体及其成员。 14.314.5 节在 14.2 节的基础上,分别讲解 Linux 终端设备驱动的模块加载/ 卸载函数和 open()、close()函数,数据读写流程及 tty 设备线路设置的编程方法。 在
2、 Linux 系统中,串口驱动完全遵循 tty 驱动的框架结构,但是进行了底层操 作的再次封装,14.6 节讲解了 Linux 系统针对串口 tty 驱动的这一封装,14.7 节则 具体给出了串口 tty 驱动的实现方法。 14.8节基于14.6节和14.7节的讲解给出了串口tty驱动的设计实例, 即S3C2410 集成 UART 的驱动。 专业始于专注 卓识源于远见 2 终端设备终端设备 在 Linux 系统中,终端是一种字符型设备,它有多种类型,通常使用 tty 来简称各种类型的终端设备。 tty 是 Teletype 的缩写,Teletype 是最早出现的一种终端设备,很像电传打字机,是
3、由 Teletype 公司生产的。 Linux 系统中包含如下几类终端设备。 1串行端口终端(串行端口终端(/dev/ttySn) 串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口 都看作是一个字符设备。 这些串行端口所对应的设备名称是/dev/ttyS0 (或/dev/tts/0) 、 /dev/ttyS1 (或/dev/tts/1) 等,设备号分别是(4,0) 、 (4,1)等。 在命令行上把标准输出重定向到端口对应的设备文件名上就可以通过该端口发送数据,例如,在命 令行提示符下输入“echo test /dev/ttyS1”
4、会把单词“test”发送到连接在 ttyS1 端口的设备上。 2伪终端(伪终端(/dev/pty/) 伪终端(Pseudo Terminal)是成对的逻辑终端设备,并存在成对的设备文件,如/dev/ptyp3 和 /dev/ttyp3,它们与实际物理设备并不直接相关。如果一个程序把 ttyp3 看作是一个串行端口设备,则它对 该端口的读/写操作会反映在该逻辑终端设备对应的 ttyp3 上, 而 ttyp3 则是另一个程序用于读写操作的逻辑 设备。这样,两个程序就可以通过这种逻辑设备进行通信,使用 ttyp3 的程序会认为自己正在与一个串行 端口进行通信。 以 telnet 为例,如果某人在使用
5、 telnet 程序连接到 Linux 系统,则 telnet 程序就可能会开始连接到设备 ptyp2 上,而此时一个 getty 程序会运行在对应的 ttyp2 端口上。当 telnet 从远端获取了一个字符时,该字符 就会通过 ptyp2、ttyp2 传递给 getty 程序,而 getty 程序则会通过 ttyp2、ptyp2 和 telnet 程序返回“login:”字 符串信息。这样,登录程序与 telnet 程序就通过伪终端进行通信。通过使用适当的软件,可以把两个或多 个伪终端设备连接到同一个物理串行端口上。 3控制台终端(控制台终端(/dev/ttyn,/dev/console)
6、 如果当前进程有控制终端(Controlling Terminal) ,那么/dev/tty 就是当前进程的控制终端的设备特殊文 件。可以使用命令“psax”来查看进程与哪个控制终端相连,使用命令“tty”可以查看它具体对应哪个实 际终端设备。/dev/tty 有些类似于到实际所使用终端设备的一个连接。 在 UNIX 系统中,计算机显示器通常被称为控制台终端(Console) 。它仿真了类型为 Linux 的一种终 端(TERM = Linux) ,并且有一些设备特殊文件与之相关联:tty0、tty1、tty2 等。当用户在控制台上登录 时,使用的是 tty1。按Alt+F1Alt+F6组合键
7、时,我们就可以切换到 tty2、tty3 等。tty1tty6 等称为虚 拟终端,而 tty0 则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。因此不管当 前正在使用哪个虚拟终端,系统信息都会发送到控制台终端上。用户可以登录到不同的虚拟终端上去,因 而可以让系统同时有几个不同的会话期存在。只有系统或超级用户 root 可以向/dev/tty0 进行写操作。 在 Linux 系统中,可以在系统启动命令行里指定当前的输出终端,格式如下: console=device, options device 指代的是终端设备,可以是 tty0(前台的虚拟终端) 、ttyX(第 X 个虚拟
8、终端) 、ttySX(第 X 个 串口) 、lp0(第一个并口)等。 options 指代对 device 进行的设置,它取决于具体的设备驱动。对于串口设备,参数用来定义为如下。 专业始于专注 卓识源于远见 3 波特率、校验位、位数,格式为 BBBBPN,其中 BBBB 表示波特率,P 表示校验(n/o/e) ,N 表示位 数,默认 options 是 9600n8。 用户可以在内核命令行中同时设定多个终端, 这样输出将会在所有的终端上显示, 而当用户调用 open() 打开/dev/console 时,打开的将是设定的最后一个终端。例如: console=ttyS1, 9600 consol
9、e=tty0 定义了两个终端, 而调用 open()打开/dev/console 时, 将使用虚拟终端 tty0。 但是内核消息会在 tty0 VGA 虚拟终端和串口 ttyS1 上同时显示。 通过查看/proc/tty/drivers 文件可以获知什么类型的 tty 设备存在以及什么驱动被加载到内核,这个文 件包括一个当前存在的不同 tty 驱动的列表,包括驱动名、默认的节点名、驱动的主编号、这个驱动使 用的次编号范围以及 tty 驱动的类型。例如,下面所示为一个/proc/tty/drivers 文件的例子。 终端设备驱动结构终端设备驱动结构 Linux 内核中 tty 的层次结构如图 1
10、4.1 所示,包含 tty 核心、tty 线路规程和 tty 驱动,tty 线路规程的工 作是以特殊的方式格式化从一个用户或者硬件收到的数据,这种格式化常常采用一个协议转换的形式,例 如 PPP 和 Bluetooth。tty 设备发送数据的流程为:tty 核心从一 个用户获取将要发送给一个 tty 设备的数据,tty 核心将数据传递 给 tty 线路规程驱动,接着数据被传递到 tty 驱动,tty 驱动将数 据转换为可以发送给硬件的格式。 接收数据的流程为:从 tty 硬件接收到的数据向上交给 tty 驱 动,进入 tty 线路规程驱动,再进入 tty 核心,在这里它被一个用 户获取。 尽管
11、大多数时候 tty 核心和 tty 之间的数据传输会经历 tty 线路规程的转换, 但是 tty 驱动与 tty 核心之间也可以直接传输数 据。 图 14.2 显示了与 tty 相关的主要源文件及数据的流向。tty_io.c 定义了 tty 设备通用的 file_ operations 结构体并实现了接口函数 tty_register_driver()用于注册 tty 设备,它会利用 fs/char_dev.c 提供的接口函数注 册字符设备,与具体设备对应的 tty 驱动将实现 tty_driver 结构体中的成员函数。同时 tty_io.c 也提供了 tty_register_ldisc()
12、接口函数用于注册线路规程,n_tty.c 文件则实现了 tty_disc 结构体中的成员。 图 14.1 tty 分层结构 专业始于专注 卓识源于远见 4 图 14.2 tty 主要源文件关系及数据流向 从图 14.2 可以看出,特定 tty 设备驱动的主体工作是填充 tty_driver 结构体中的成员,实现其中的成员 函数,tty_driver 结构体的定义如代码清单 14.1 所示。 代码清单 14.1 tty_driver 结构体 1 struct tty_driver 2 3 int magic; 4 struct cdev cdev; /* 对应的字符设备 cdev */ 5 st
13、ruct 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 .