您的位置:首页 > 其它

第一个驱动之helloworld

2013-01-22 16:59 465 查看
第一个驱动——helloworld

运行环境:TQ2440开发板,内核版本2.6.30.4

开发环境:Window下的Source Insight以及PC机上的红帽企版5虚拟机

实验环境前提条件:拥有一个制作好的NFS文件系统

/**********************************hello.c*************************************/

#include<linux/init.h> //此头文件指定初始化和清除函数

#include<linux/module.h> //此头文件包含有可装载模块需要的大量符号和函数的定义

static int __init hello_init(void) //第一个运行的函数,注册,告诉内核要从这里开始执行

{

/* 执行insmod hello.ko 时就会打印hello,world */

printk(KERN_WARNING "hello,world.\n");

return 0;

}

static void __exit hello_exit(void) //清除函数

{

/* 执行rmmod hello 时就会打印goodbye world */

printk(KERN_WARNING "goodbye world\n");

}

module_init(hello_init); //宏调用,后面详细分析

module_exit(hello_exit); //宏调用,后面详细分析

MODULE_LICENSE("GPL"); //遵守GPL许可证

MODULE_AUTHOR("lwj"); //模块编写的作者

MODULE_DESCRIPTION("Just a simple module for hello world"); //模块的简单描述

程序深入分析:

一、static int __init hello_init(void),看到这个函数,有几点是需要注意的。

1、初始化函数应该被声明为static,因为这种函数除了在本文件内有意义,其他文件是没有意义的,因为一个模块函数如果要对内核其他部分可见,则必须被显式导出。如:EXPORT_SYMBOL(name)或者EXPORT_SYMBOL_GPL(name),这二个宏均用于符号导出到模块外部。后者表示导出的模块只能被GPL许可证下的模块方可使用。

2、函数返回值应为int型,主要是出错时,返回值有助于查找错误。

3、__init,双下划线__init的意思是,该函数仅仅在初始化期间内有效,在模块被装载之后,即insmod之后,模块装器就会将初始化函数丢弃,之后任何函数也没有办法调用初始化函数,因为该函数已经从内存中释放出来。

二、printk(KERN_WARNING "hello,world.\n"); 看到这个函数。

1、printk的功能和标准C库中的printf函数是类似的,不同是printk首先是输入一些所谓的等级。如下所示:

#define KERN_EMERG "<0>" /* system is unusable */

#define KERN_ALERT "<1>" /* action must be taken immediately */

#define KERN_CRIT "<2>" /* critical conditions */

#define KERN_ERR "<3>" /* error conditions */

#define KERN_WARNING "<4>" /* warning conditions */

#define KERN_NOTICE "<5>" /* normal but significant */

#define KERN_INFO "<6>" /* informational */

#define KERN_DEBUG "<7>" /* debug-level messages */

默认的级别是KERN_WARNING 即4,这个比较简单,随便一搜索就可以了解到,这里不详细分析。

三、static void __exit hello_exit(void) 看到这个函数

1、同样前面要加上static

2、清除函数没有返回值,因此被声明为void

3、__exit,双下划线__exit表示该函数仅仅用于模块被卸载的时候或者系统关闭时被调用

四、module_init(hello_init);

module_exit(hello_exit); 看到这条语句

1、module_init的使用是强制性的,这个宏会在模块的目标代码中增加一个特殊的段,用于说明内核初始化函数所在的位置,也就是说,没有这个定义,内核用于也找不到这个初始化函数在哪里,即用于得不到调用。

2、参数hello_init就相当于一个函数指针,从而使得内核能够找到初始化函数到底是谁。

3、module_exit同理,上面对于帮助内核找到模块的清除函数是必须的。

4、如果一个模块没有定义清除函数,则内核决不允许卸载该模块。

——————————————————————————————————

除了要有上面hello.c文件之外,我们还需要编写Makefile来编译产生.ko文件。

/**********************************万能的Makafile*************************************/

ifneq ($(KERNELRELEASE),)

obj-m :=hello.o

else

KERNELDIR :=/usr/src/linux-2.6.30.4

all:

make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-

clean:

rm -f *.o *.ko *.mod.o *.mod.c *.symvers

endif

Makfile简单分析:

1、模块的Makefile编写一般格式都很固定,只需编写一次,以后只需要小小修改一下即可使用

2、obj-m :=hello.o这句的意思是,hello.ko模块需要从目标文件hello.o中构造,-m的意思是编译成模块,而不编译进内核

3、KERNELDIR :=/usr/src/linux-2.6.30.4 这个路径是我开发板所使用的内核

4、ARCH=arm 代表架构为arm而不是X86,CROSS_COMPILE=arm-linux- 代表交叉编译工具为arm-linux-XXX,如:arm-linux-gcc、arm-linux-ld等等

5、clean:

rm -f *.o *.ko *.mod.o *.mod.c *.symvers

表示执行make clean的时候,删除所有符合上面格式的文件。

——————————————————————————————————

实验操作步骤:

一、虚拟机上的操作

1、建立一个单独的文件夹用于存放hello模块以及Makefile(方便开发)

2、编译模块,拷贝模块到制作好的NFS文件系统。

二、开发板上的操作

[\u@\h \W]# insmod hello.ko

hello,world.

[\u@\h \W]# lsmod

hello 1376 0 - Live 0xbf012000

[\u@\h \W]# rmmod hello

goodbye world

结束语:

期末考试终于结束了,我终于有时间将前几个月学习的驱动知识分享给大家了,基于能力有限,所写知识大多都是参考书籍所总结出来的,当然,代码是自己编写的,如有错误,希望多多包涵,也希望大家提出来,让我们一起共同进步,谢谢大家。如你之前所见,最后,祝大家学习愉快
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: