Linux字符设备驱动程序是Linux系统驱动中比较简单的了,当然我个人认为input子系统比字符设备驱动程序要简单,呵呵,不过你得熟悉了整个架构才能这么说。本文只是为了学习后免得忘记而留下的。本人记忆不是很好,经常选择性失忆,因此写出来总不会忘吧,希望这里的服务器不要给我选择性失忆。
废话就不多说了,Linux字符设备驱动基本架构如下:
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/version.h>
#include<linux/types.h>
#include<linux/errno.h>
#include<linux/init.h>
static int __init my_init(void) //字符设备驱动模块入口函数
{
printk("driver installed!\n");
return 0;
}static void __exit my_exit(void) //字符设备驱动模块出口函数
{
printk("driver uninstalled!\n");return;
}module_init(my_init); //一个宏,指定初始入口函数
module_exit(my_exit); //一个宏,指定出口函数
MODULE_AUTHOR("test@hotmail.com");
MODULE_LICENSE("GPL");这是最简单的字符设备驱动,几乎Linux所有的驱动程序都以此架构为基础,Linux内核为了减少内核的大小,在安装新设备更新驱动后不用重新编译内核,提出了这个模块化编程的思想。也就是可以把驱动程序做为一个新的功能加入内核,而不用重新编译内核,只需要将编译声成的模块使用命令插入内核即可。这样就大大方便了驱动程序的开发。下面来简单说说上面每一行的意义:
头文件我就不想说了,是下面这些函数的声明,下面这个函数什么实际的事情都不做,只是打印一条提示信息,这个将是此驱动模块的入口函数,那么什么是入口函数呢,其实说简单点,就是初始化函数,在使用insmod命令将模块插入内核的时候将调用此函数,驱动程序可以在这里对硬件进行初始化动作。
static int __init my_init(void) //字符设备驱动模块入口函数
{
printk("driver installed!\n");
return 0;
}下面这个函数是驱动程序的出口函数,就是在我们使用命令rmmod卸载一个模块的时候调用的函数,在这里可以对硬件做一些退出的动作,还做一些释放在入口函数申请的内存空间,irq等资源。当然在实际中,这2个函数当然不会这么简单,这里只是一个示例;看下面的出口函数中有__exit关键字,这表示当我们的驱动程序不做为模块编译的时候,那么这个模块将永远不会被调用,那么此函数也就没有用处,在这个时候,加了__exit关键字的函数将不做编译;
static void __exit my_exit(void) //字符设备驱动模块出口函数
{
printk("driver uninstalled!\n");return;
}下面这行其实是一个宏,它指定模块的入口函数:
module_init(my_init); //一个宏,指定初始入口函数
下面这行也是一个宏,它指定模块的出口函数:
module_exit(my_exit); //一个宏,指定出口函数
最后2行是一些辅助性的东西,将在后面说明,这里就不做说明了:
MODULE_AUTHOR("test@hotmail.com");
MODULE_LICENSE("GPL");在这里要说明的是,在2.4内核以前,是可以直接使用gcc命令直接编译模块的,不过在2.6内核中,必须使用makefile了,下面是编译模块的makefile,其实大多都差不多像下面这样了:
ifneq ($(KERNELRELEASE),)
obj-m :=demo.o //模块所依赖的.o文件这默认会编译demo.c文件,
else
KERNELDIR ?=/lib/modules/$(shell uname -r)/build //内核目录,请指定你将要把此模块插入的内核的目录
PWD :=$(shell pwd) //模块文件的目录
ALL:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules //按照这样写就行
endifclean: //不用解释
rm -fr *.o *.ko *~ core .depend .*.cmd *.mod.c .tmp_versions *symvers这个makefile比较简单,看右边的说明就行了,其它的不想多说!好累,好饿,心好冷,下回继续吧!