模块结构介绍
利用Linux设备驱动程序的第一个例程:Hello World模块了解内核驱动模块的结构。
#include <linux/init.h> #include <linux/module.h>
static int hello_init(void) { printk(KERN_ALERT "Hello, Tekkaman Ninja !\n"); return 0; }
static void hello_exit(void) { printk(KERN_ALERT "Goodbye, Tekkaman Ninja !\n Love Linux !Love ARM ! Love KeKe !\n"); }
module_init(hello_init); module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL"); |
1. 所有模块代码中都包含一下两个头文件:
#include <linux/init.h> #include <linux/module.h> |
2. 所有模块代码都应该指定所使用的许可证:
MODULE_LICENSE("Dual BSD/GPL"); |
此外还有可选的其他描述性定义:
MODULE_AUTHOR(""); MODULE_DESCRIPTION(""); MODULE_VERSION(""); MODULE_ALIAS(""); MODULE_DEVICE_TABLE(""); |
上述MODULE_声明习惯上放在文件最后。
3. 初始化和关闭
初始化的实际定义通常如下:
static int _ _init initialization_function(void) { /*初始化代码*/ }
module_init(initialization_function) |
清除函数的实际定义通常如下:
static int _ _exit cleanup_function(void) { /*清除代码*/ }
module_exit(cleanup_function) |
4. 一个简单的Makefile文件:
KERNELDIR = /home/tekkaman/working/SBC2440/linux-2.6.22.2
PWD := $(shell pwd)
INSTALLDIR = /home/tekkaman/working/rootfs/lib/modules
CROSS_COMPILE = arm-9tdmi-linux-gnu-
CC = $(CROSS_COMPILE)gcc
obj-m := hello.o
.PHONY: modules modules_install clean
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
cp hello.ko $(INSTALLDIR)
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions |
obj-m := hello.o
代表了我们要构造的模块名为hell.ko,make 会在该目录下自动找到hell.c文件进行编译。如果 hello.o是由其他的源文件生成(比如file1.c和file2.c)的,则在下面加上(注意红色字体的对应关系):
hello-objs := file1.o file2.o ...... |
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
-C $(KERNELDIR) 指定了内核源代码的位置,其中保存有内核的顶层makefile文件。
M=$(PWD) 指定了模块源代码的位置
modules目标指向obj-m变量中设定的模块。
5. 编译模块
make modules 、 make modules_install 。
[root@Tekkaman-Ninja Helloworld]# make modules make -C /home/tekkaman/working/SBC2440/linux-2.6.22.2 M=/home/tekkaman/working/Linuxdriver/Helloworld modules make[1]: Entering directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2' CC [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.o Building modules, stage 2. MODPOST 1 modules CC /home/tekkaman/working/Linuxdriver/Helloworld/hello.mod.o LD [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.ko make[1]: Leaving directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2' [root@Tekkaman-Ninja Helloworld]# make modules_install cp hello.ko /home/tekkaman/working/rootfs/lib/modules [root@Tekkaman-Ninja Helloworld]# |
6. 在开发板上的操作:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#ls
cs89x0.ko hello.ko p80211.ko prism2_usb.ko
[Tekkaman2440@SBC2440V4]#insmod hello.ko
Hello, Tekkaman Ninja !
[Tekkaman2440@SBC2440V4]#lsmod
Module Size Used by Not tainted
hello 1376 0
[Tekkaman2440@SBC2440V4]#rmmod hello
Goodbye, Tekkaman Ninja !
Love Linux !Love ARM ! Love KeKe !
[Tekkaman2440@SBC2440V4]#lsmod
Module Size Used by Not tainted
[Tekkaman2440@SBC2440V4]# |
另外一个例子
有三个文件,分别为hello.c add.c Makefile
hello.c文件
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("Hello World Module");
MODULE_ALIAS("a simplest module");
extern int add_integar(int a,int b);
extern int sub_integar(int a,int b);
static int __init hello_init()
{
int res = add_integar(1,2);
return 0;
}
static void __exit hello_exit()
{
int res = sub_integar(2,1);
}
module_init(hello_init);
module_exit(hello_exit);
add.c文件
int add_integar(int a,int b)
{
return a+b;
}
int sub_integar(int a,int b)
{
return a-b;
}
Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := main.o
main-objs:=hello.o add.o
else
KDIR := /lib/modules/2.6.35-24-generic/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
然后make,产生main.ko文件
insmod main.ko 加载文件
lsmod 查看加载成功
rmmod main 卸载文件
modprobe main,如同insmod一样,只是他会根据/lib/modules/<$version>modules.dep来连接某些它要依赖的文件。(make dep是连接依赖文件的意思)
二 模块参数
module_param_array(name,type,num,perm);
name 是你的数组的名子(也是参数名), type 是数组元素的类型, num 是一个整型变量, perm 是通常的权限值
例:
static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);
在加载时可以直接修改参数,比如 sudo insmod hello.ko whom=hello,那么打印的信息就是hello而不是world了。
三 内核符号导出概念
EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);
name是指被调用的函数名
阅读(1304) | 评论(0) | 转发(0) |