linux驱动开发笔记2
来源:互联网 发布:js cookie时间 编辑:程序博客网 时间:2024/05/29 18:48
建立和运行模块
2.1模块基本构成
最简单的helloworld模块示例代码如下:
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("DualBSD/GPL");
staticint hello_init(void)
{
printk(KERN_ALERT"Hello, world\n");
return0;
}
staticvoid hello_exit(void)
{
printk(KERN_ALERT"Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
该模块定义了两个函数,hello_init在模块被加载时调用,hello_exit在模块被删除时调用。module_init和module_exit两行代码使用linux宏指明以上两个函数角色。另一个宏MODULE_LICENSE告诉内核模块有一个自由许可证。如果没有这样的声明,内核加载模块时就会抱怨。
2.2编译和加载
内核是一个大的、独立的程序,对于它的各个部分如何组合在一起有详细的明确的要求。在有足够新的编译器、模块工具、其他必要工具和内核源码树前提下,为你的模块创建一个makefile就是直接了当的。对于上面的helloworld例子,单行就够了obj-m:hello.o.这种写法利用了GNU-make提供的扩展语法,编译出的模块名为hello.ko。反之,如果如果有个模块名为module.ko,来自2个原文件,正确书写:
obj-m:=module.o
moduleobjs:= file1.o file2.o
假设上面的内核源码位于~/kernel-2.6,用来建立你的模块的make命令(模块源码目录)
make-C ~/kernel-2.6 M=‘pwd’ modules
这个命令开始是改变它的目录到用-C选项提供的目录下(就是说,你的内核源码目录).它在那里会发现内核的顶层makefile.这个M=选项使makefile在试图建立模块目标前,回到你的模块源码目录.这个目标,依次地,是指在obj-m变量中发现的模块列表,在我们的例子里设成了module.o.
上面的方法仍然麻烦,可以采用下面更简单的方法,这充分类用了makefile的扩展特性。
#If KERNELRELEASE is defined, we've been invoked from the
#kernel build system and can use its language.
ifneq($(KERNELRELEASE),)
obj-m:= hello.o
#Otherwise we were called directly from the command
#line; invoke the kernel build system.
else
KERNELDIR?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE)-C $(KERNELDIR) M=$(PWD) modules
endif
再一次,我们看到了扩展的GNUmake语法在起作用.这个makefile在一次典型的建立中要被读2次.当从命令行中调用这个makefile,它注意到KERNELRELEASE变量没有设置.它利用这样一个事实来定位内核源码目录,即已安装模块目录中的符号连接指回内核建立树.如果你实际上没有运行你在为其而建立的内核,你可以在命令行提供一个KERNELDIR=选项,设置KERNELDIR环境变量,或者重写makefile中设置KERNELDIR的那一行.一旦发现内核源码树,makefile调用default:目标,来运行第2个make命令(在makefile里参数化成$(MAKE))象前面描述过的一样来调用内核建立系统.在第2次读,makefile设置obj-m,并且内核的makefile文件完成实际的建立模块工作。
模块编译完成,一般使用insmod加载(rmsmod卸载),这个程序加载模块的代码段和数据段到内核,然后执行符号链接。另一个工具modprobe,如同insmod,他能够检测依赖关系,将依赖模块装载,比insmod强大。
2.3初始化和关停
staticint __init initialization_function(void)
{
/*Initialization code here */
}
module_init(initialization_function);
staticvoid __exit cleanup_function(void)
{
/*Cleanup code here */
}
module_exit(cleanup_function);
特别指出在注册时,存在模块加载竞争,如果注册了某特性,可能还没有执行完注册函数,内核其他模块就有可能调用已经注册的模块,请确保要注册的特性内部初始化已经完成再进行注册。另外就是不能完全注册成功时,最好保留部分注册成功的功能,而不要让注册失败。
- linux驱动开发笔记2
- Linux驱动开发-字符设备驱动笔记 2
- Linux驱动开发学习笔记
- Linux驱动开发学习笔记
- Linux设备驱动开发笔记
- Linux驱动开发学习笔记
- linux设备驱动开发学习笔记一
- linux设备驱动开发学习笔记二
- Linux驱动开发学习笔记1
- "Linux设备驱动开发详解" 笔记
- Linux驱动开发笔记总结(一)
- Linux驱动开发盲点笔记1
- Linux设备驱动开发详解--笔记2--驱动设计的硬件基础
- linux 下块设备驱动开发学习笔记 2(sbull驱动分析)
- linux 下块设备驱动开发学习笔记 2(sbull驱动在vmware上测试)
- Linux设备驱动开发详解--笔记6--字符设备驱动
- Linux驱动开发--设备驱动基础笔记 1
- Linux驱动开发-混杂字符设备驱动模型笔记 4
- 一辈子的理财计划:你不理财,财不理你 读后感
- Android 驱动和系统开发. 一个简单的例子
- OPNET结构 (OPNET Architecture) --2
- request_irq() | 注册中断服务
- X509数字证书之一:加密和解密
- linux驱动开发笔记2
- matlab使语句对齐和使正在运行的程序暂停
- js做的日期控件里怎样设置文本框里面不能手动输入日期
- hash小模板
- 内存映射文件
- 详细的DOS命令和符合说明
- mysql查询今天、昨天、7天、近30天、本月数据
- 推荐一系列优秀的Android开发源码(转自安卓巴士)
- case when 遇到null值的处理方法