好好学习,天天向上
分类: LINUX
2011-04-06 18:05:40
(LDD3笔记)
驱动可以编译为模块,也可以静态编译到内核中,调试的时候一般作为模块。
一个最基本的模块
hello.c:
#include
#include
static int __init hello_init(void)
{
printk(KERN_ALERT "hello world init!\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "hello world exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile:
obj-m := hello.o
KDIR := /home/linux-2.6.9
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
.PHONY:clean
clean:
-rm *.o *.ko
在make之前,你得有内核源码,比如我的是/home/linux-2.6.9,而且应该在源码下make menuconfig一次,再make modules(可以中途结束掉,这是为了产生modpost工具)。
之后再cd到测试模块目录,make就可以在当前目录下产生hello.ko模块文件。
如果你的内核源码和你的linux内核版本一致,你就可以用insmod hello.ko挂载模块了,然后你会在系统日志中看到hello world init等信息,如果版本不一致,就会看到如下错误信息:insmod: error inserting 'hello.ko': -1 Invalid module format
你可以使用uname –r查看当前系统内核的版本信息,然后再去下载相应的内核源码。
总结:
在学习开发驱动之前,你要有对应自己linux的内核源代码(kernel.org上下载)。
模块使用module_init注册,使用module_exit退出
内核可以使用printk打印信息
加载模块的工具有insmod, modprob,卸载模块的工具:rmmod
查看模块信息:modinfo xxx
给模块添加信息
我们可以给自己的模块添加版权,作者等信息,通过使用下面的宏来实现:
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description); //关于模块做什么的声明
MODULE_VERSION(version_string); //一个代码修订版本号
MODULE_DEVICE_TABLE(table_info); //来告知用户空间, 模块支持那些设备
MODULE_ALIAS(alternate_name); //模块为人所知的另一个名字
MODULE_LICENSE(license);
修改hello.c:
#include
#include
static int __init hello_init(void)
{
printk(KERN_ALERT "hello world init!\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "hello world exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("crazycode");
重新make后,用modinfo查看模块信息:modinfo hello.ko
filename: hello.ko
author: crazycode
vermagic: 2.6.32 SMP mod_unload modversions 686 4KSTACKS
depends:
导出符号
如果想使自己模块的函数或者变量在模块外部可见,可以使用:
EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(name);//仅定义了license为GPL的模块可见
模块参数
#include
module_param(variable, type, perm);
module_param_array(name,type,num,perm);创建模块参数, 可以被用户在模块加载时调整( 或者在启动时间, 对于内嵌代码).
类型type可以是 bool, charp, int, invbool, short, ushort, uint, ulong, 或者 intarray.
num是数组元素的个数
权限perm定义在
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
给hello模块添加参数:
hello.c
#include
#include
#include
static char *name="crazy";
static int times=1;
module_param(name,charp,S_IRUGO);
module_param(times,int,S_IRUGO);
static int __init hello_init(void)
{
int i;
printk(KERN_ALERT "hello world init!\n");
for(i=0;i
printk("welcome %s !\n",name);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "hello world exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("crazycode");
重新make之后,加载它:insmod hello.ko name=”crazycode” times=5
然后在系统日志中可以看到:
Apr 6 06:16:57 localhost kernel: welcome ”crazycode” !
Apr 6 06:16:57 localhost last message repeated 4 times