分类: LINUX
2008-10-31 14:52:54
模块就是能用命令进行加载到内核或从内核卸载的程序,它们可以使机器在不重启的情况下可以扩展内核功能,其中一种模块类型就是驱动,可以用lsmod命令来查看什么模块已经被加进内核。
当内核需要一个不是驻留在内核里的模块时,它会执行modprobe命令去把模块加载上,而传递给modprobe命令的参数有两种形式,如char-major-180-* usbcore,该种形式定义在/etc/modprobe.d/aliases中,对应的模块名为usbcore.ko,然后modprobe将去查看一下/lib/modules/version/modules.dep看是否有模块必须在加载该模块之前加载,该文件是由depmod -a命令生成的,是关于模块依赖性的,最后modprobe用insmod命令把依赖的模块加载上,再把该模块加载上。
在内核2.3.13之前,内核模块必须有两个功能:初始化功能(init_module()),它是当模块被加载到内核时调用的;卸载功能(cleanup_module()),它是当模块被卸载之前调用的。现在可以用任何名字来实现一个模块的初始化或卸载,但每一个内核模块都必须包含linux/module.h
如果你要用到一些宏扩展如prink(),还需要包含linux/kernel.h。
简单模块例子:
hello.c
#include
#include
#include
MODULE_LICENSE("Dual BSC/GPL");
MODULE_AUTHOR("Sam
Shen
MODULE_DESCRIPTION("Test Module Program");
MODULE_SUPPORTED_DEVICE("Hello,world");
static int _ _init hello_init(void)
{
printk(KERN_ALERT"Hello, world!\n");
return 0;
}
static void _ _exit hello_exit(void)
{
printk(KERN_ALERT"Goodbye, cruel world!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile
obj-m += hello.o
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
(想了解更多关于编译模块,请查看linux/Documentation/kbuild/modules.txt,更多关于内核模块的Makefile,请查看linux/Documentation/kbuild/makefiles.txt)
_ _ init声明是当init函数执行完成后内核能够回收空间,_ _initdata和它有相同的功能,但是是对于变量而不是函数的, _ _exit声明是为了内核能够省略掉cleanup函数,它们可装载模块不受影响。MODULE_*定义在linux/include/linux/module.h,它们不被内核本身使用,只是为了让一些工具查看模块的信息。
按Ctrl+Alt+F5,进入tty5,用modinfo hello.ko查看模块的信息,用sudo insmod hello.ko加载模块,用lsmod | grep hello查看模块是否已加载上,用sudo rmmod hello卸载该模块。所有已经加载的模块都列在文件/proc/modules中,故也可以通过查看hello是否出现在该文件中来判断模块是否已经加载上,一般刚加载的模块加在第一行,如:hello 2432 0 - Live 0xf8974000 (P),其中hello为模块名,2432是模块大小,0是使用数目,-Live是模块状态,0xf8974000是模块位置,(P)为非标准内核模块。
可以给模块传递命令行参数,但不是用argc/argv的机制,而是用module_param()或module_param_array()宏,它们定义在include/linux/moduleparam.h文件中,使用范例:
hello.c
#include
#include
#include
#include
#include
MODULE_LICENSE("Dual BSC/GPL");
MODULE_AUTHOR("Sam
Shen
MODULE_DESCRIPTION("Test Module Program");
MODULE_SUPPORTED_DEVICE("Hello,world");
static short int myshort = 1;
static int myint = 2;
static long int mylong = 8888;
static char *mystring = "shenxiaocheng";
static int myintArray[2] = {-1, 1};
static int arr_argc = 0;
module_param(myshort, short, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer");
module_param(myint, int, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
MODULE_PARM_DESC(myint, "An integer");
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");
module_param_array(myintArray, int, &arr_argc,0000);
MODULE_PARM_DESC(myintArray, "An array of integer");
static int __init hello_init(void)
{
int i;
printk(KERN_ALERT"Hello, world!\n");
printk(KERN_ALERT"myshort is a short interger: %hd\n",myshort);
printk(KERN_ALERT"myint is an integer %d\n", myint);
printk(KERN_ALERT"mylong is a long integer: %ld\n",mylong);
printk(KERN_ALERT"mystring is a string: %s\n", mystring);
for(i=0; i<(sizeof myintArray / sizeof(int)); i++)
printk(KERN_ALERT"myintArray[%d] = %d\n", i, myintArray[i]);
printk(KERN_ALERT"got %d argumeters for myintArray.\n", arr_argc);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT"Goodbye, cruel world!\n");
}
module_init(hello_init);
module_exit(hello_exit);
加载时,可以用sudo insmod hello.ko myshort=5命令为模块传递参数。
如果我们把hello_init和hello_exit函数分开放在start.c和stop.c文件中,则Makefile需要改为
obj-m += startstop.o
startstop-objs := start.o stop.o