首页 > 代码库 > 3.2Linux的模块驱动

3.2Linux的模块驱动

Linux的模块驱动

?

技术分享

  1. 接下来写个最简单的驱动程序,就像程序语言的hello world程序。
  2. 首先是:hello.c的代码:

    技术分享

    这是个最简单的驱动程序。就是打印hello的信息。驱动程序和我们的程序语言结果有点不大一样。驱动模块的入口是倒数第二行的module_init()的函数。驱动模块的出口是module_exit()的函数。

3.接着是makfile文件:技术分享

这也是一个很简单的Makefile文件了。Obj-m后面跟的是我们的最终目标依赖的文件hello.o。第三行的KDIR是我们编译进的内核的路径。All是执行make得到的目标,$(KDIR)指定内核的路径,就是第三行的路径。M=$(PWD)是模块存放的路径。接着就是清除生成的文件的命令。

4.make的执行过程:

技术分享

从上面的执行的过程,我们可以看到makefile的执行的过程。

?

?

?

如果在一个工程里,当有两个.c文件的时候的编写:

Hello.c:

技术分享

Function.c:

技术分享

Makefile修改为:

技术分享

最后编译的结果如下图:

?

技术分享

?

?

?

?

内核模块的安装和卸载:

insmod hello.ko

卸载内核模块:

rmmod hello(卸载的时候不用加.ko)

查看模块:

lsmod

?

执行的结果:

技术分享

注意:内核模块只有当没有用户用时才可以卸载,如上图:我们的test是没有被使用,而fuse有两个用户在使用。我们试着卸载这两个内核模块的截图:

技术分享

?

?

?

内核模块的可选的信息:模块申明、模块参数、符号信息。

模块的申明:

????MODULE_LICENSE("遵守的协议")

申明该模块遵守的许可证协议,如:"GPL"、"GPL v2"等。

????MODULE_AUTHOR("作者")

????申明模块的作者

????MODULE_DESCRIPTION("该模块的功能描述")

????MODULE_VERSION("v1.0")

申明模块的版本

?

模块申明可以让读者知道该模块所遵守的协议,增加模块代码的可读性。

?

?

技术分享

只是一个提示,增加可读性的作用。

?

模块参数的传递:

在我们的应用程序中:int main(int argc,char** argv):argc表示命令行输入的参数个数,argv中保存输入端的参数。

那么我们的内核模块中是怎么传入参数的呢?:

?

模块参数跟我们程序语言的参数有点不大一样,除了用一般的数据类型来申明变量参数,我们还得用module_param()这个宏来指定它是模块参数:

Module_param(name,type,perm):

Name:变量的名称

Type:变量的类型,bool,int,charp。

Perm:访问权限。S_IRUGO:读权限。S_IWUSR:写权限。

例如:

Int a=33;

Char *st;

Module_param(a,int ,S_IRUGO);

Module_param(st,charp,S_IRUGO);

?

下面是执行的实例:

技术分享

我们定义了一个a=99;然后在14行打印出来。运行的结果:

技术分享

上面是执行的过程,我们也可以在执行的时候给它加参数:

技术分享

字符串也是一样:

技术分享

运行的结果:

?

技术分享

?

最后是符号导出:

符号导出的实例:

修改Makefile:

?

技术分享

修改function.c为:

技术分享

?

执行的过程:

技术分享

?

同时产生了两个.ko模块。

当我们去安装hello.ko的时候,出现了这个错误:未定义的符号:

技术分享

这是因为我们程序中的extern int function();现在的系统中不存在这个函数。那是不是得先insmod function.ko呢!?

技术分享

虽然系统已经出现了function函数,可是系统还是找不到。可以看出错误依然存在。

?

这就是模块导出的问题:当我们要去使用一个模块里面的变量,函数的时候,必须使用符号导出。也就是把变量和函数输出到我们的系统当中,使整个系统都可以使用。

技术分享

修改function.c为:

技术分享

用EXPORT_SYMBOL()来申明,我的function是可以被系统的其他模块使用的。不过,我们应该先编译function.ko,在编译hello.ko。结果:

技术分享

这就是符号输出的使用。

总结与应用程序的区别:

技术分享

内核的打印:

技术分享

Printf和printk都是打印信息的。但是printk还有级别打印:

技术分享

技术分享

Hello.c:

技术分享

?

输出结果:

技术分享

结果只有KERN_EMERG级别的才在屏幕打印出来。这样的打印级别,我们可以控制在那些地方可以打印什么。当然,我们也可以用输入来代替级别。例如上面的"<0>",就是KERN_EMER。

?

技术分享

?

?

?

?

?

?

?

?

?

3.2Linux的模块驱动