如何编写Linux设备驱动程序( 三 )


如果登记成功,返回设备的主设备号,不成功,返回一个负值 。
void cleanup_module(void)
{
unregister_chrdev(test_major,"test");
};
在用rmmod卸载模块时,cleanup_module函数被调用,它释放字符设备test在系统字符设备表中占有的表项 。
一个极其简单的字符设备可以说写好了,文件名就叫test.c吧 。
下面编译
$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c
得到文件test.o就是一个设备驱动程序 。
如果设备驱动程序有多个文件,把每个文件按上面的命令行编译,然后
ld -r file1.o file2.o -o modulename.
驱动程序已经编译好了,现在把它安装到系统中去 。
$ insmod -f test.o
如果安装成功,在/proc/devices文件中就可以看到设备test,并可以看到它的主设备号 。
要卸载的话,运行
$ rmmod test
下一步要创建设备文件 。
mknod /dev/test c major minor
c 是指字符设备,major是主设备号,就是在/proc/devices里看到的 。
用shell命令
$ cat /proc/devices | awk "$2=="test" {print $1}"
就可以获得主设备号,可以把上面的命令行加入你的shell script中去 。
minor是从设备号,设置成0就可以了 。
我们现在可以通过设备文件来访问我们的驱动程序 。写一个小小的测试程序 。
#include
#include
#include
#include
main()
{
int testdev;
int i;
char buf[10];
testdev = open("/dev/test",O_RDWR);
if ( testdev == -1 )
{
printf("Cann"t open file n");
exit(0);
}
read(testdev,buf,10);
for (i = 0; i < 10;i)
printf("%dn",buf[i]);
close(testdev);
}

编译运行,看看是不是打印出全1 ?
以上只是一个简单的演示 。真正实用的驱动程序要复杂的多,要处理如中断,DMA,I/O port等问题 。这些才是真正的难点 。请看下节,实际情况的处理 。
如何编写Linux操作系统下的设备驱动程序
三、设备驱动程序中的一些具体问题
1. I/O Port.
和硬件打交道离不开I/O Port,老的ISA设备经常是占用实际的I/O端口,在linux下,操作系统没有对I/O口屏蔽,也就是说,任何驱动程序都可对任意的I/O口操作,这样就很容易引起混乱 。每个驱动程序应该自己避免误用端口 。
有两个重要的kernel函数可以保证驱动程序做到这一点 。
1)check_region(int io_port,int off_set)
这个函数察看系统的I/O表,看是否有别的驱动程序占用某一段I/O口 。
参数1:io端口的基地址,
参数2:io端口占用的范围 。
返回值:0 没有占用,非0,已经被占用 。
2)request_region(int io_port,int off_set,char *devname)
如果这段I/O端口没有被占用,在我们的驱动程序中就可以使用它 。在使用之前,必须向系统登记,以防止被其他程序占用 。登记后,在/proc/ioports文件中可以看到你登记的io口 。
参数1:io端口的基地址 。
参数2:io端口占用的范围 。
参数3:使用这段io地址的设备名 。
在对I/O口登记后,就可以放心地用inb(),outb()之类的函来访问了 。
在一些pci设备中,I/O端口被映射到一段内存中去,要访问这些端口就相当于访问一段内存 。经常性的,我们要获得一块内存的物理地址 。在dos环境下,(之所以不说是dos操作系统是因为我认为DOS根本就不是一个操作系统,它实在是太简单,太不安全了)只要用段:偏移就可以了 。在window95中,95ddk提供了一个vmm 调用 _MapLinearToPhys,用以把线性地址转化为物理地址 。但在Linux中是怎样做的呢?
2.内存操作
在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页 。释放内存用的是kfree,或free_pages. 请注意,kmalloc等函数返回的是物理地址!而malloc等返回的是线性地址!关于kmalloc返回的是物理地址这一点本人有点不太明白:既然从线性地址到物理地址的转换是由386cpu硬件完成的,那样汇编指令的操作数应该是线性地址,驱动程序同样也不能直接使用物理地址而是线性地址 。但是事实上kmalloc返回的确实是物理地址,而且也可以直接通过它访问实际的RAM,我想这样可以由两种解释,一种是在核心态禁止分页,但是这好像不太现实;另一种是linux的页目录和页表项设计得正好使得物理地址等同于线性地址 。我的想法不知对不对,还请高手指教 。

推荐阅读