- 浏览: 1486529 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (525)
- SEO (16)
- JAVA-EE-Hibernate (6)
- JAVA-EE-Struts (29)
- JAVA-EE-Spring (15)
- Linux (37)
- JAVA-SE (29)
- NetWork (1)
- CMS (14)
- Semantic Research (3)
- RIA-Flex (0)
- Ajax-Extjs (4)
- Ajax-Jquery (1)
- www.godaddy.com (0)
- SSH (34)
- JavaScript (6)
- SoftwareEngineer (9)
- CMMI (0)
- IDE-Myeclipse (3)
- PHP (1)
- Algorithm (3)
- C/C++ (18)
- Concept&Items (2)
- Useful WebSite (1)
- ApacheServer (2)
- CodeReading (1)
- Socket (2)
- UML (10)
- PowerDesigner (1)
- Repository (19)
- MySQL (3)
- SqlServer (0)
- Society (1)
- Tomcat (7)
- WebService (5)
- JBoss (1)
- FCKeditor (1)
- PS/DW/CD/FW (0)
- DesignPattern (11)
- WebSite_Security (1)
- WordPress (5)
- WebConstruction (3)
- XML|XSD (7)
- Android (0)
- Project-In-Action (9)
- DatabaseDesign (3)
- taglib (7)
- DIV+CSS (10)
- Silverlight (52)
- JSON (7)
- VC++ (8)
- C# (8)
- LINQ (1)
- WCF&SOA (5)
- .NET (20)
- SOA (1)
- Mashup (2)
- RegEx (6)
- Psychology (5)
- Stock (1)
- Google (2)
- Interview (4)
- HTML5 (1)
- Marketing (4)
- Vaadin (2)
- Agile (2)
- Apache-common (6)
- ANTLR (0)
- REST (1)
- HtmlAnalysis (18)
- csv-export (3)
- Nucth (3)
- Xpath (1)
- Velocity (6)
- ASP.NET (9)
- Product (2)
- CSS (1)
最新评论
-
lt26w:
理解成门面模式应该比较容易明白吧
FacadePattern-Java代码实例讲解 -
lt26w:
看下面的例子比较明白.
FacadePattern-Java代码实例讲解 -
javaloverkehui:
这也叫文档,别逗我行吗,也就自己看看。
HtmlCleaner API -
SE_XiaoFeng:
至少也应该写个注释吧。
HtmlCleaner API -
jfzshandong:
...
org.springframework.web.filter.CharacterEncodingFilter 配置
主题: linux内核模块的程序结构--模块加载函数(必须),模块卸载函数(必须),模块许可证声明(必须),模块参数(可选),模块导出符号(可选),模块作者的等信息声明(可选)
一个linux内核模块主要由以下几个部分组成。
1、模块加载函数"用module_init()来指定"(必须)
当通过insmod和modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。
linux模块加载函数一般以 __init表示声明。典型声明如下::
static int __init initialization_function(void)
{
/*初始化代码*/
}
module_init(initialization_function);
模块加载函数必须使用module_init(函数名)的形式被指定。它返回整型值,若初始化成功,应返回0,而初始化失败时,应返回错误编码。在linux内核中,错误编码是一个负值,在<linux/errno.h>中定义,包括-ENODEV、-ENOMEM之类的符号值。返回相应的错误编码是种非常好的习惯,只有这样,应用程序才能利用perror等方法把他们转换成有意义的错误信息字符串。
在2.6内核中,可以使用“request_module(const char *fmt,...)函数”加载内核模块(注意:前面加载模块都是通过insmod和modprobe来实现的),驱动开发人员可以通过调用::
request_module(module_name);
或
request_module("char-major-%d-%d",MAJOR(dev),MINOR(dev));
来加载其他内核模块。
在linux内核中,所有表示为__init的函数在连接的时候放在.init.text这个区段内,此外,所有的__init函数在段.initcall.init中还保存了一份函数指针,在初始化时,内核会通过这些指针调用这些__init函数,并在初始化完成后释放init区段(.init.text,.initcall.init等)。
////////////////////////////////////////////////////////////////////
2、模块卸载函数"用module_exit()来指定"(必须)
当通过rmmod和modprobe -r命令卸载内核模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。
linux内核模块于在函数一般以__exit表示说明,典型的模块卸载函数的形式如下::
static void __exit cleanup_function(void)
{
/*释放代码*/
}
module_exit(cleanup_function);
模块卸载函数在模块卸载的时候执行,不返回任何值,必须以"module_exit(函数名)"的形式来指定。
通常来说,模块卸载函数要完成与模块加载函数相反的功能,如下::
1>若模块加载函数注册了XXX,则模块卸载函数应该注销XXX;
2>若模块记载函数的动态申请了内存,则模块函数应该释放该该内存。
3>若模块加载函数申请了硬件资源(中断,DMA通道、I/O端口和I/O内存等)的占用,则模块卸载函数应该释放这些硬件资源。
4>模块加载函数一般用来开启硬件,模块卸载函数一般要关闭硬件。
和__init一样,__exit也可以使用对应函数在运行完成后自动回收内存。实际上,__init和__exit都是宏,
分别定义为::
#define __init __attribute__((__section__(".init.text")))
和
#ifdef MODULE
#define __exit __attribute__((__section__(".exit.text")))
#else
#define __exit \ __attribute__used____attribute((__section__(".exit.text")))
#endif
/////////////////////////////////////////////////////////////////////
3、模块许可证声明"MODULE_LICENSE("Daul BSD/GPL")"(必须)
模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告。
在linux2.6内核中,可接受的LICENSE包括"GPL"、"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"、"Dual MPL/GPL"和"Proprietary"
大多数情况下,内核模块应遵循GPL兼容许可权。linux2.6内核模块中最常见的是以MODULE_LICENSE("Dual BSD/GPL")语句声明模块采用BSD/GPL双LICENSE.
//////////////////////////////////////////////////////////////////////
4、模块参数(可选)
“模块参数”是“模块被加载的时候可以被传递给模块的值”,它本身对应模块内部的“全部变量”。
我们可以使用"module_param(参数名,参数类型,读/写权限)"为模块定义一个参数,例如::下列代码定义了一个整型参数和一个字符指针参数。
static char *book_name="深入浅出linux设备驱动";
static int num = 4000;
module_param(num,int,S_IRUGO);
module_param(book_name,charp,S_IRGUO);
在装载内核模块时,用户可以向内核模块传递参数,
形式为"sudo insmod/modprobe 模块名(例如linux.ko) 参数名=参数值",若果不传递,参数将使用模块内定义的默认值。
向内核模块传递参数时,参数的类型可以是byte(字节),short(短整型),ushort(无符号短整型),int,uint(无符号int),long,ulong(无符号long)、charp(字符指针)、bool或invbool(布尔的反),在模块被编译时会将module_param中声明的类型与变量定义的类型进行比较,判断是否一致。
模块被加载后,在/sys/module目录下将出现以此模块名命名的目录。当"参数读/写权限"为0时,表示此“参数不存在sysfs文件系统下对应的文件节点”,如果此模块存在"参数读/写权限"不为0的命令行参数,在此模块的目录下将出现parameters目录,包含一系列“以参数名命名的文件节点”。同时,这些文件的权限就是通过传入module_param()的"参数读/写权限",而文件的内容为参数的值。
除此之外,模块也可以拥有参数数组,形式为"module_param_array(数组名,数组类型,数组长,参数读/写权限)",在2.6.0~2.6.10版本,需将数组常变量名赋给"数组长",从2.6.10版本开始,需将数组长变量的指针赋给"数组长",当不需要保存实际输入的数组元数个数时,可以设置"数组长"为NULL。
运行insmod和modprobe命令时,应使用逗号分割输入的数组元素。
例如::
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static char *book_name="Dissecting Linux Device Driber";
static int num=4000;
static int __init book_init(void)
{
printk(KERN_INFO"book name :%s\n",book_name);
printk(KERN_INFO"book num :%s\n",num);
return 0;
}
static void __exit book_exit(void)
{
printk(KERN_INFO"Book module exit\n");
}
module_init(book_init);
module_exit(book_exit);
module_param(num,int,S_IRUGO);
module_param(book_name,charp,S_IRUGO);
MODULE_AUTHOR("chenbaihu");
MODULE_VERSION("v1.0");
MODULE_DESCRIPTION("A simple Module for testing module params");
编译该模块,Makefile为::
obj-m := module_param.o
kernel_path=/usr/src/kernels/2.6.29.6-217.2.16.fc11.i686.PAE
//内核路径
all:
make -C $(kernel_path) M=$(PWD) modules
clean:
make -C $(kernel_path) M=$(PWD) clean
然后,运行make命令,进行编译.生成module_param.ko文件.
加载该模块.
第一种方案::
“sudo insmod module_param.ko”命令时,运行结果为::
book name :Dissecting Linux Device Driber
book num :4000
第二种方案::
“sudo insmod module_param.ko num=5000”命令时,运行结果为::
book name :Dissecting Linux Device Driber
book num :5000 //参数传入了。
进入/sys/module/module_param/下,输入tree命令::
.
|-- holders
|-- initstate
|-- notes
|-- parameters
| |-- book_name //模块参数文件
| `-- num //模块参数文件
|-- refcnt
|-- sections
| `-- __param
|-- srcversion
`-- version
//////////////////////////////////////////////////////////////////////
5、模块导出符号(可选)
内核模块可以导出符号(symbol,对应与函数或变量),这样其他模块可以使用本模块中的变量和函数。
linux2.6的"/proc/kallsyms"文件对应这内核符号表,它记录了符号以及符号符号所在的内存地址。
模块可以使用如下宏导出符号到内核符号表::
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符合名); //只是用于GPL许可权模块。
导出的符合将可以被其他模块使用,使用前声明以下既可以。
内核模块中的符号导出(例子)::
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("Daul BSD/GPL");
int add_integar(int a,int b)
{
return a+b;
}
int sub_integer(int a,int b)
{
return a-b;
}
EXPORT_SYMBOL(add_integar); //导出函数
EXPORT_SYMBOL(sub_integer); //导出函数
编译后,sudo insmod export_symbol.ko将该模块加入内核。
从"/proc/kallsyms"中可以找到add_integae\sub_integer相关信息。
使用"cat /proc/kallsyms|grep integar"命令,就可以看到下面的结果::
f99f8048 r __ksymtab_add_integar [export_symbol]
f99f805c r __kstrtab_add_integar [export_symbol]
f99f8000 T add_integar [export_symbol]
6、模块作者等信息(可选)
MODULE_AUTOR("作者信息");
MODULE_DESCRIPTION("模块描述信息");
MODULE_VERSION("版本信息");
MODULE_ALIAS("别名信息");
MODULE_DEVICE_TABLE("设备表信息");
对于USB,PCI等设备驱动,通常会创建一个MODULE_DEVICE_TABLE,表示驱动所支持的设备列表。
1、模块加载函数"用module_init()来指定"(必须)
当通过insmod和modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。
linux模块加载函数一般以 __init表示声明。典型声明如下::
static int __init initialization_function(void)
{
/*初始化代码*/
}
module_init(initialization_function);
模块加载函数必须使用module_init(函数名)的形式被指定。它返回整型值,若初始化成功,应返回0,而初始化失败时,应返回错误编码。在linux内核中,错误编码是一个负值,在<linux/errno.h>中定义,包括-ENODEV、-ENOMEM之类的符号值。返回相应的错误编码是种非常好的习惯,只有这样,应用程序才能利用perror等方法把他们转换成有意义的错误信息字符串。
在2.6内核中,可以使用“request_module(const char *fmt,...)函数”加载内核模块(注意:前面加载模块都是通过insmod和modprobe来实现的),驱动开发人员可以通过调用::
request_module(module_name);
或
request_module("char-major-%d-%d",MAJOR(dev),MINOR(dev));
来加载其他内核模块。
在linux内核中,所有表示为__init的函数在连接的时候放在.init.text这个区段内,此外,所有的__init函数在段.initcall.init中还保存了一份函数指针,在初始化时,内核会通过这些指针调用这些__init函数,并在初始化完成后释放init区段(.init.text,.initcall.init等)。
////////////////////////////////////////////////////////////////////
2、模块卸载函数"用module_exit()来指定"(必须)
当通过rmmod和modprobe -r命令卸载内核模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。
linux内核模块于在函数一般以__exit表示说明,典型的模块卸载函数的形式如下::
static void __exit cleanup_function(void)
{
/*释放代码*/
}
module_exit(cleanup_function);
模块卸载函数在模块卸载的时候执行,不返回任何值,必须以"module_exit(函数名)"的形式来指定。
通常来说,模块卸载函数要完成与模块加载函数相反的功能,如下::
1>若模块加载函数注册了XXX,则模块卸载函数应该注销XXX;
2>若模块记载函数的动态申请了内存,则模块函数应该释放该该内存。
3>若模块加载函数申请了硬件资源(中断,DMA通道、I/O端口和I/O内存等)的占用,则模块卸载函数应该释放这些硬件资源。
4>模块加载函数一般用来开启硬件,模块卸载函数一般要关闭硬件。
和__init一样,__exit也可以使用对应函数在运行完成后自动回收内存。实际上,__init和__exit都是宏,
分别定义为::
#define __init __attribute__((__section__(".init.text")))
和
#ifdef MODULE
#define __exit __attribute__((__section__(".exit.text")))
#else
#define __exit \ __attribute__used____attribute((__section__(".exit.text")))
#endif
/////////////////////////////////////////////////////////////////////
3、模块许可证声明"MODULE_LICENSE("Daul BSD/GPL")"(必须)
模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告。
在linux2.6内核中,可接受的LICENSE包括"GPL"、"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"、"Dual MPL/GPL"和"Proprietary"
大多数情况下,内核模块应遵循GPL兼容许可权。linux2.6内核模块中最常见的是以MODULE_LICENSE("Dual BSD/GPL")语句声明模块采用BSD/GPL双LICENSE.
//////////////////////////////////////////////////////////////////////
4、模块参数(可选)
“模块参数”是“模块被加载的时候可以被传递给模块的值”,它本身对应模块内部的“全部变量”。
我们可以使用"module_param(参数名,参数类型,读/写权限)"为模块定义一个参数,例如::下列代码定义了一个整型参数和一个字符指针参数。
static char *book_name="深入浅出linux设备驱动";
static int num = 4000;
module_param(num,int,S_IRUGO);
module_param(book_name,charp,S_IRGUO);
在装载内核模块时,用户可以向内核模块传递参数,
形式为"sudo insmod/modprobe 模块名(例如linux.ko) 参数名=参数值",若果不传递,参数将使用模块内定义的默认值。
向内核模块传递参数时,参数的类型可以是byte(字节),short(短整型),ushort(无符号短整型),int,uint(无符号int),long,ulong(无符号long)、charp(字符指针)、bool或invbool(布尔的反),在模块被编译时会将module_param中声明的类型与变量定义的类型进行比较,判断是否一致。
模块被加载后,在/sys/module目录下将出现以此模块名命名的目录。当"参数读/写权限"为0时,表示此“参数不存在sysfs文件系统下对应的文件节点”,如果此模块存在"参数读/写权限"不为0的命令行参数,在此模块的目录下将出现parameters目录,包含一系列“以参数名命名的文件节点”。同时,这些文件的权限就是通过传入module_param()的"参数读/写权限",而文件的内容为参数的值。
除此之外,模块也可以拥有参数数组,形式为"module_param_array(数组名,数组类型,数组长,参数读/写权限)",在2.6.0~2.6.10版本,需将数组常变量名赋给"数组长",从2.6.10版本开始,需将数组长变量的指针赋给"数组长",当不需要保存实际输入的数组元数个数时,可以设置"数组长"为NULL。
运行insmod和modprobe命令时,应使用逗号分割输入的数组元素。
例如::
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static char *book_name="Dissecting Linux Device Driber";
static int num=4000;
static int __init book_init(void)
{
printk(KERN_INFO"book name :%s\n",book_name);
printk(KERN_INFO"book num :%s\n",num);
return 0;
}
static void __exit book_exit(void)
{
printk(KERN_INFO"Book module exit\n");
}
module_init(book_init);
module_exit(book_exit);
module_param(num,int,S_IRUGO);
module_param(book_name,charp,S_IRUGO);
MODULE_AUTHOR("chenbaihu");
MODULE_VERSION("v1.0");
MODULE_DESCRIPTION("A simple Module for testing module params");
编译该模块,Makefile为::
obj-m := module_param.o
kernel_path=/usr/src/kernels/2.6.29.6-217.2.16.fc11.i686.PAE
//内核路径
all:
make -C $(kernel_path) M=$(PWD) modules
clean:
make -C $(kernel_path) M=$(PWD) clean
然后,运行make命令,进行编译.生成module_param.ko文件.
加载该模块.
第一种方案::
“sudo insmod module_param.ko”命令时,运行结果为::
book name :Dissecting Linux Device Driber
book num :4000
第二种方案::
“sudo insmod module_param.ko num=5000”命令时,运行结果为::
book name :Dissecting Linux Device Driber
book num :5000 //参数传入了。
进入/sys/module/module_param/下,输入tree命令::
.
|-- holders
|-- initstate
|-- notes
|-- parameters
| |-- book_name //模块参数文件
| `-- num //模块参数文件
|-- refcnt
|-- sections
| `-- __param
|-- srcversion
`-- version
//////////////////////////////////////////////////////////////////////
5、模块导出符号(可选)
内核模块可以导出符号(symbol,对应与函数或变量),这样其他模块可以使用本模块中的变量和函数。
linux2.6的"/proc/kallsyms"文件对应这内核符号表,它记录了符号以及符号符号所在的内存地址。
模块可以使用如下宏导出符号到内核符号表::
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符合名); //只是用于GPL许可权模块。
导出的符合将可以被其他模块使用,使用前声明以下既可以。
内核模块中的符号导出(例子)::
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("Daul BSD/GPL");
int add_integar(int a,int b)
{
return a+b;
}
int sub_integer(int a,int b)
{
return a-b;
}
EXPORT_SYMBOL(add_integar); //导出函数
EXPORT_SYMBOL(sub_integer); //导出函数
编译后,sudo insmod export_symbol.ko将该模块加入内核。
从"/proc/kallsyms"中可以找到add_integae\sub_integer相关信息。
使用"cat /proc/kallsyms|grep integar"命令,就可以看到下面的结果::
f99f8048 r __ksymtab_add_integar [export_symbol]
f99f805c r __kstrtab_add_integar [export_symbol]
f99f8000 T add_integar [export_symbol]
6、模块作者等信息(可选)
MODULE_AUTOR("作者信息");
MODULE_DESCRIPTION("模块描述信息");
MODULE_VERSION("版本信息");
MODULE_ALIAS("别名信息");
MODULE_DEVICE_TABLE("设备表信息");
对于USB,PCI等设备驱动,通常会创建一个MODULE_DEVICE_TABLE,表示驱动所支持的设备列表。
发表评论
-
Linux内核源码包的安装及编译zz
2009-12-15 20:58 4262http://my.donews.com/ecco2005/2 ... -
Linux内核Makefile文件(二)
2009-12-15 19:34 2413=== 6 体系Makefile文 ... -
Linux内核Makefile文件(一)
2009-12-15 19:34 1832本文是/Documentation/kbuild/make ... -
Linux加载模块命令
2009-12-15 19:28 2674安装模块insmod *.ko卸载 ... -
编译linux内核~
2009-12-05 22:04 1391小菜鸟第一次编译linux内核。截图太多 。。不方便上传 = ... -
grub2 基础教程
2009-12-05 18:01 2737grub2基础教程-修订版 ... -
Ubuntu9.10版本没有了menu.lst文件!
2009-12-05 18:00 3111囧~现在都在grub下面配置了。 不过麦斯之前的men ... -
关于信号量与线程互斥锁的区别与实现
2009-11-30 14:37 2388之前一直没有怎么 ... -
Linux信号量线程控制
2009-11-30 14:31 3652线程中互斥锁的使用,达到对共享资源互斥使用。除了使用互斥锁, ... -
信号量和自旋锁
2009-11-29 21:56 1625内核同步措施 ... -
Linux信号量semaphore编程实例
2009-11-29 21:20 6537本例示范Linux信号量的基本用法。该范例使用了两个线程分别对 ... -
Linux获取当前时间
2009-11-29 21:16 3634Linux获取当前时间 ... -
pthread库学习(2): 线程的同步,使用信号量
2009-11-29 20:55 2451先看下面这段程序,主线程创建了三个线程,每个线程中均有一个打印 ... -
信号量的基本思想
2009-11-29 20:17 1454信号量是1965荷兰Dijkstra 为了解决并发进程问题 ... -
多进程通信方式一:管道(PIPE)
2009-11-27 18:29 9073进程通信(IPC)的几种方式及比较 撰文:黄显国08 ... -
进程的管道通信
2009-11-27 18:12 2977实验四 进程的管道通信 ... -
Linux下线程的挂起和恢复
2009-11-27 15:42 3698POSIX的Linux操作系统没有提供线程挂起和恢复的例程,在 ... -
Linux 编程之生成静态连接库
2009-11-27 15:41 1385静态库及动态库的建立 ... -
LInux高级编程 - 线程(Threads)
2009-11-27 15:40 1848LInux高级编程 - 线程(Threads) ... -
Linux下c开发 之 线程通信
2009-11-27 15:39 19281.Linux“线程” 进程与 ...
相关推荐
LINUX内核模块编程LINUX内核模块编程LINUX内核模块编程
linux内核模块编程,编写一个模块,实现文件的读取。
LINUX内核模块编程.pdf 粗略的讲解
Linux内核模块编程指南(经典)资料很好啊
linux 内核模块编程指南 中文版 很适合初学者 学习使用
很详细的linux内核开发指导, 比起中文翻译的一些资料详细多了,表达清晰,重点突出,是一本内核进阶和入门的好书
详细描述了内核模块的技术原理,了解linux技术内幕,迅速了解linux各个模块。
Linux内核模块编程指南 致谢 前言 第1章 Hello, World 145 1.1 内核模块的Makefiles文件 146 1.2 多重文件内核模块 147 第2章 字符设备文件 149 第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备...
The+Linux+Kernel+Module+Programming+Guide--2.6.4 注意版本不同可能导致编辑不成功,所以注意选择哈 很经典的linux内核模块编程指南
Linux内核模块编程指南
LINUX内核模块编程英文版,精典书籍,不下载会后悔的呢
一本Linux内核模块入门的比较好的资料。我全看完了,并且在上面做了标记。希望对想学习Linux内核的朋友们有所帮助
操作系统课程设计——Linux内核模块编程+源代码+文档说明 - 小白不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,...
基于Linux内核编程的实验报告(Linux内核分析实验报告)
linux内核模块 Linux内核分析 Linux内核编程
著名的The Linux Kernel ModuleProgramming的中文版,值得一看
2.1 Linux内核模块相关指令 (1) 插入模块:insmod hello.ko (2) 删除模块:rmmod hello (3) 列出已加载模块:lsmo