第一个驱动之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
结束语:
期末考试终于结束了,我终于有时间将前几个月学习的驱动知识分享给大家了,基于能力有限,所写知识大多都是参考书籍所总结出来的,当然,代码是自己编写的,如有错误,希望多多包涵,也希望大家提出来,让我们一起共同进步,谢谢大家。如你之前所见,最后,祝大家学习愉快
运行环境: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
结束语:
期末考试终于结束了,我终于有时间将前几个月学习的驱动知识分享给大家了,基于能力有限,所写知识大多都是参考书籍所总结出来的,当然,代码是自己编写的,如有错误,希望多多包涵,也希望大家提出来,让我们一起共同进步,谢谢大家。如你之前所见,最后,祝大家学习愉快
相关文章推荐
- 第一个设备驱动--Hello,world
- 第一个驱动helloworld&nbsp;module加载i…
- 第一个驱动helloworld&nbsp;module加载i…
- Linux设备驱动程序学习(0) -设备驱动介绍& Hello, world!模块
- Eclipse + vs2013 编写第一个JNI HelloWorld
- 为什么学习众多编程语言的第一个程序都是 hello, world
- 第一个程序:"Hello World"
- Android测试教程(5):第一个测试项目HelloWorldTest
- 我的第一个汇编程序-Hello,World!
- 大白话解析Objective-C(一):入门 (Hello World + 第一个类)
- 模仿HelloWorldScene,写第一个Scene
- springboot开发 第一个案例之hello,world!
- NIOS2 uCLinux-mmu 驱动之hello_world
- SharePoint工作流开发点滴(2) - 开发第一个SharePiont工作流: HelloWorldSequential 的注意事项
- linux内核驱动---hello_world驱动加载
- [.NET MVC4 入门系列01]Helloworld MVC 4 第一个MVC4程序
- 我的第一个Qt程序:使用Qt creator和Qt designer完成"HelloWorld"和计算圆面积的程序设计
- 第一个Python小程序(Hello World!)
- Docker入门学习(2)----Docker安装和第一个hello-world
- Go语言开发第一个Hello,World