【转】linux2.6.28-tty设备驱动学习

来源:互联网 发布:windows svn 命令行 编辑:程序博客网 时间:2024/06/05 04:44

linux2.6.28-tty设备驱动学习

在Linux系统中,终端是一种字符设备,它有多种类型,通常使用tty来简称各种类型的终端设备。tty是Teletype的缩写,Teletype是最早出现的一种终端设备,很像电传打字机,是由Teletype公司产生的。Linux系统包含以下几类终端设备:

1、串行终端设备(/dev/ttySn).它是使用计算机串行端口连接的终端设备,也就是我们主板上的串口。
2、伪终端(/dev/pty/).它是成对的逻辑终端设备,并存在成对的设备文件。如/dev/pty3和/dev/ttyp3,它们和实际的物理设备并不直接相关。
3、控制台终端(/dev/ttyn, /dev/console).如果当前进程有控制终端,那么/dev/tty就是当前进程的控制终端的设备特殊文件。
通过查看/proc/tty/drivers文件可以获知什么类型的tty设备文件存在以及什么驱动被加载到内核。这个文件包括一个当前存在的不同tty驱动的列表,包括驱动名、默认的节点名、驱动的主编号、这个驱动使用的次编号范围以及tty驱动的类型。看下面一个例子:
学习tty设备驱动,我们要先会加载和卸载此设备。
tty设备驱动有一个很重要的结构体:tty_driver。它用来注册和注销一个 tty 驱动到 tty 内核。
linux2.6.28/include/linux/tty_driver.h:
这个函数返回tty_driver指针,其参数为要分配的设备数量,line会被赋值给tty_driver的num成员.
为创建一个 struct tty_driver, 函数 alloc_tty_driver 必须用这个驱动作为参数而支持的 tty 设备号来调用.

以下函数用来注册tty设备和驱动:
linux2.6.28/include/linux/tty.h:
 
下面一个例子来加载和卸载tty模块:
Makefile:
我们编译并加载此模块后,观察如下文件:
红色字体那一行就是我的tty设备。

我创建了5个设备。到/dev目录下看看吧:
OK,tty设备的创建已经完成。后面就要对tty设备文件进行操作了。
 
本次目标是要实现在用户态下对tty驱动程序的数据读写。
首先来看一下tty设备的数据流通图:
tty设备有三层:tty核心,tty线路规程,tty驱动。
我们写驱动还是只负责最底层的tty驱动。线路规程的设置也是在底层的tty驱动。
tty核心是封装好的。
来看一下tty设备的操作函数:
tty设备没有read函数,是因为大部分tty的输入设备和输出设备不一样。例如我们的虚拟终端设备,它的输入是键盘,输出是显示器。
由于这样的原因,tty的驱动层和tty的线路规程层都有一个缓冲区。
tty驱动层的缓冲区用来保存硬件发过来的数据。在驱动程序里使用  tty_insert_flip_string 函数可以实现将硬件的数据存入到驱动层的缓冲区。
其实一个缓冲区就够了,为什么线路规程层还是有一个缓冲区呢?
那是因为tty核心无法直接读取驱动层的缓冲区的数据。tty核心读不到数据,用户也就无法获取数据。用户的read函数只能从tty核心读取数据。而tty核心只能从tty线路规程层的缓冲区读取数据。
因为是层层读写的关系,所以tty线路规程也是需要一个缓冲区的。
在驱动程序里使用 tty_flip_buffer_push()  函数将tty驱动层缓冲区的数据推到tty线路规程层的缓冲区。这样就完成了数据的流通。
因为全是缓冲区操作,所以需要两个进程:写数据进程和读数据进程。
如果缓冲区内没有数据,运行读进程的话,tty核心就会把读进程加入到等待队列。

完整的代码如下:
将此模块编译后加入到内核,再运行以下两个程序:
receive.c : 读取tty设备缓冲区的数据。
send.c    : 将数据写入到tty设备驱动。
首先运行 receive
$ sudo ./receive
open /dev/ttty_lan0: Success
ready for receiving data...
The data received is:

等待数据状态。

再打开另一个终端,运行 send
$ sudo ./send
open /dev/ttty_lan0: Success
ready for sending data...
the number of char sent is 35
$

这个程序运行结束后,我们来看一下receive是否接受到了数据:
$sudo ./receive
open /dev/ttty_lan0: Success
ready for receiving data...
The data received is:
Hello,this is a Serial_Port test!
$

说明接受到了缓冲区的数据。

具体测试程序的代码如下:
send.c:
receive.c: