Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1454832
  • 博文数量: 704
  • 博客积分: 10140
  • 博客等级: 上将
  • 技术积分: 6230
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-15 20:41
文章分类

全部博文(704)

文章存档

2013年(1)

2012年(16)

2011年(536)

2010年(151)

分类: LINUX

2010-08-06 18:02:57

最近开始学习Linux驱动开发,以LDD3为主,同时参考宋宝华的《Linux设备驱动开发详解》以及网上的一些资料,记录下自己的学习过程,备忘。
 
一、内核版的Hello world 模块:
 
#include
#include
MOUDLE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
        printk(KERN_ALERT "hello, world!\n");
        return 0;
}
static void hello_exit(void)
{
        printk(KERN_ALERT "Goodbye,cruel world!\n");
}
module_init(hello_init);
module_exit(hello_exit);
 
关于这个程序的说明:
 
1大部分头文件都包含下面两行代码:

    #include
    #include

module.h 包含有可装载模块需要的大量符合和函数的定义。包含init.h 的目的是指定初始化和清除函数。另外,大部分模块还包括moduleparam.h,这样我们可以在装载模块的时想模块传递函数。
 
2模块应指定代码所使用的许可证,即:MOUDLE_LICENSE("Dual BSD/GPL");
如果不声明LICENSE,模块被加载是,将受到内核被污染(kernel tainted)的警告。
此外还有可选的其他描述性定义

MODULE_AUTHOR("");
MODULE_DESCRIPTION("");
MODULE_VERSION("");
MODULE_ALIAS("");
MODULE_DEVICE_TABLE("");
 
上述MODULE_声明习惯上放在文件最后。
 
3static int hello_init(void) 模块初始化函数。典型的模块加载函数形式如下:

 
static int _ _initinitialization_function(void)
{
/*初始化代码*/
}
module_init(initialization_function);

初始化函数应该被声明为static,因为这种函数在特定文件之外没其他意义。
__init对内核来讲是种提示,表明该函数仅在初始化期间使用。在模块被装载之后,模块装载器会将该函数扔掉,将初始化花占用的内存释放出来。
module__init 是强制使用的,没有这个定义,初始化这个函数永远不会被调用。这个宏会在模块化的目标代码中增加一个特殊的段,用于说明内核初始化函数所在的位置。
 
4printk函数在Linux内核中定义,和printf类似,最大区别在于缺乏对浮点数的支持。
KERN_ALERT定义了这条消息的优先级,原因是具有默认优先级的消息可能不会输出到控制台上。也就是说,没有KERN_ALERT,有可能正常执行了但是看不到打印的消息。
 
5static void hello_exit(void)模块清除函数。典型的模块清除函数形式如下:
static int _ _exit cleanup_function(void)
{
/*清除代码*/
}
module_exit(cleanup_function);
如果模块被直接内嵌到内核中,或者内核中的配置不允许卸载模块,那么__exit的函数将被简单的丢弃。因此该函数只能在被卸载后再系统关闭的时候被调用。
另外,如果一个函数未定义清除函数,则内核不允许卸载该模块。
 
二、编译和装载
1将该程序保存为hello.c,编写一个最简单的Makefile,在Makefile中输入如下一行:

    obj-m := hello.o

2, 执行命令 make -C /usr/src/linux-headers-2.6.32-24-generic/ M=$(pwd) modules,之后生成hello.ko模块。

-C选项指定的是Linux内核源码所在的目录,M=后指定的是hello.cMakefile所在的目录。
 
3Makefile语法:obj-m := hello.o  代表了我们要构造的模块名为 hell.ko,make 会在该目录下自动找到hell.c文件进行编译。如果hello.o是由其他的源文件生成(比如file1.c和 file2.c)的,则在下面加上(注意红色字体的对应关系):
hello-objs := file1.o file2.o ......
更加详细的内核Makefile语法可参考以下两篇文档:
 
4,通过insmod ./hello.ko 命令可以加载该模块,输出“hello world!”,
   通过rmmod ./hello 命令可以卸载hello模块,输出“Goodbye,cruel world!”。
 
三、模块参数
为了增加驱动程序的灵活性,内核允许对驱动程序指定参数,而这些参数可在加载驱动程序模块时改变。
这些参数的值可由insmod或者modprobe在加载时指定;后者也可以从它的配置文件(/etc/modprobe.conf)读取参数的值。这两个命令可在命令行里接受几种参数类型的赋值。
我们可以用“module_param(参数名,参数类型,参数读/写权限)”为模块定义参数。可以对hello模块)做一些改进。 我们增加 2个参数:一个整型值,称为howmany,一个字符串称为whom。 在装载这个增强的模块时,将向whom问候howmany次。这样我们可以用下面的命令来装载该模块:
    insmod hellop.ko howmany=5 whom=“Students”
 
 hellop.c代码如下:
#include
#include
MODULE_LICENSE("Dual BSD/GPL");

static char *whom = "world";
static int howmany = 1;

module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

static int hello_init(void)
{
        int i;
        for(i=0;i        {
                printk(KERN_ALERT "Hello %s\n",whom);
        }
        return 0;
}
static void hello_exit(void)
{
       printk(KERN_ALERT "Hello world exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
内核支持的模块参数类型包括byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool 或invbool(布尔的反),以‘u’开头的为无符号值。
除此之外,模块也可以拥有参数数组,形式为“module_param_array(数组名,数组类型,数组长,参数读/写权限)”。运行 insmod或modprobe命令时,应使用逗号分隔输入的数组元素。
阅读(1381) | 评论(0) | 转发(0) |
0

上一篇:关于open函数的内部问题

下一篇:poll()

给主人留下些什么吧!~~