文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Linux设备驱动学习--Hello,world模块

Linux设备驱动学习--Hello,world模块

时间:2010-08-04  来源:redri55

最近开始学习Linux驱动开发,以LDD3为主,同时参考宋宝华的《Linux设备驱动开发详解》以及网上的一些资料,记录下自己的学习过程,备忘。   一、内核版的Hello world 模块:  
#include <linux/init.h>
#include <linux/module.h>
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 <linux/module.h>
    #include <linux/init.h>
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_声明习惯上放在文件最后。   3,static int hello_init(void) 模块初始化函数。典型的模块加载函数形式如下:
 
static int _ _initinitialization_function(void) { /*初始化代码*/ } module_init(initialization_function);

初始化函数应该被声明为static,因为这种函数在特定文件之外没其他意义。 __init对内核来讲是种提示,表明该函数仅在初始化期间使用。在模块被装载之后,模块装载器会将该函数扔掉,将初始化花占用的内存释放出来。 module__init 是强制使用的,没有这个定义,初始化这个函数永远不会被调用。这个宏会在模块化的目标代码中增加一个特殊的段,用于说明内核初始化函数所在的位置。   4,printk函数在Linux内核中定义,和printf类似,最大区别在于缺乏对浮点数的支持。 KERN_ALERT定义了这条消息的优先级,原因是具有默认优先级的消息可能不会输出到控制台上。也就是说,没有KERN_ALERT,有可能正常执行了但是看不到打印的消息。   5,static 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.c和Makefile所在的目录。   3,Makefile语法:obj-m := hello.o  代表了我们要构造的模块名为hell.ko,make 会在该目录下自动找到hell.c文件进行编译。如果hello.o是由其他的源文件生成(比如file1.c和file2.c)的,则在下面加上(注意红色字体的对应关系):
hello-objs := file1.o file2.o ......
更加详细的内核Makefile语法可参考以下两篇文档: http://blog.chinaunix.net/u1/40912/showart_340468.html http://www.smth.edu.cn/pc/pccon.php?id=6063&nid=144938&s=all   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 <linux/init.h>
#include <linux/module.h>
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<howmany;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命令时,应使用逗号分隔输入的数组元素。
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载