第一个驱动之helloworld


第一个驱动——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


 

结束语:

            期末考试终于结束了,我终于有时间将前几个月学习的驱动知识分享给大家了,基于能力有限,所写知识大多都是参考书籍所总结出来的,当然,代码是自己编写的,如有错误,希望多多包涵,也希望大家提出来,让我们一起共同进步,谢谢大家。如你之前所见,最后,祝大家学习愉快大笑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值