popsonic的个人空间 https://blog.eetop.cn/81174 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

linux 驱动模块2

已有 1301 次阅读| 2007-2-19 17:02

天气: 晴朗
心情: 高兴

 

配置环境

         开始写什么之前,我们先把环境搭好吧。《linux 设备驱动程序》使用的是2.6.10的内核,不过没有关系,我们使用2.6.X的内核在机制上是相同的。基于2.6内核的操作系统上,我个人认为susefedora 好。至于其他的嘛,debian也不错。我使用的是suse 10.2的系统,您可以从 http://downsload.opensuse.org 来下载。Suse 10.2是基于2.6.18的内核的,比较新而且编译起来也没什么问题。如果您希望得到一个标准的内核那么请访问 http://www.kernel.org

         Jon建议使用标准版的内核源码来编译你自己的内核程序,然而,如果内核被修改而来适应某个特性。我们使用标准版的内核,编译的目标码确并不一定能够正常的在系统中运行。所以,对于我们学习的来说,使用操作系统里自带的就可以了。如果以后正式开发则需要使用标准内核,然后拿到个体机器的时候,再用特殊内核的源码来编译就好了。

         安装的时候注意有个选项是让我们来编译内核的,把它选上。如果没有选也没有关系,进入系统之后把安装盘放进去。找到 kernel_sourcerpm包安装它就可以了。安装完之后,应该是在/usr/src/Linux的目录下。Linux 这个目录是个链接,它指向Linux 的真正目录。一般这个是个带版本号的目录,比如Linux2.6.18.2。如果我们安装了多个版本的内核,那么我们就可以改变Linux 的指向从而来用统一的代码来访问不同内核了。

         我习惯上在安装完了之后把.加到PATH中去。你可以修改/etc/profile这个文件来达到这个目的。最好对linux的启动过程有个了解。注意 rc.local profileinit.d这几个目录和文件里的内容关注一下。它们负责初始化系统,执行检查和进程的运行。

         Suse102中带了 gcc 4.1的编译器,我们最好安装一下Kdevelop c/c++。这个程序可以用来编写我们的驱动模块。当然有很多人喜欢使用gedit 来编写代码,然后编写Makefile,最后编译。当然这样做是有好处的,不过想我这样的懒人,还是使用autogen来产生 Makefile吧。打开终端,键入 gcc –v可以看到你当前的gcc版本。你可以安装gcc的其他版本,不过请记住,gcc是个特殊的程序,它和系统紧密联系着。更换gcc有可能产生不可预料的结果,所以更换之前请做好备份。我的做法是将gcc改名为gcc41然后做一个连接gccgcc41。安装其他gcc的时候也是改名为gccXXXX为版本)。这样的软链接是比较有好处的,感谢那些天才们!

探索

         Hello World 这个让程序向外界说出第一句话的程序总是那么让人振奋。

#include <linux/init.h>

#inlcude <linux/module.h>

MODULE_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);

如果你以前没有太多的看过Linux的内核代码,或者对C语言不是非常了解,请不要对MODULE_LICENSE之类的感到奇怪。这个是宏的运用,在内核和驱动程序中你会看到满地都是这样难懂的东西。而我们现在还没有必要搞懂这到底是什么,到了后面我们再来探讨这些内容。

实践

我们先来运行这个东西把,makefile 的具体内容请参看书中的代码。

我们运行 #make

得到hello.o hello.ko 几个文件。

insmod 命令用于加载模块;rmmod 命令用于卸载模块。

装载: #insmod hello.ko 结果并没有象预期的那样输出Hello,world这句话。(我在path中加入了.路径如果没有加的话,需要使用 #insmod ./hello.ko

再次运行#insmod hello.ko

得到:Error inserting ‘hello.ko’:-1 Invalid module format

很纳闷,第一次没有任何回显,而第二次出错!查看了书上的内容发现在某些系统中不会回显到终端,而是写入了/var/log/message 打开这个文件发现确实输入了这个文件。

尝试#rmmod hello

再次#insmod hello.ko 成功

模块的最大的好处就是你可以在使用它的时候动态装载它,如果不使用它你可以把它从内核中卸载掉。而对于调试来说这样也是很有好处的,可以最大程度上避免驱动程序引起系统的崩溃,同时也为调试带来一些方便。

 

预备知识

         头文件 #include <linux/module.h> #include <linux/init.h> 2个文件是每一个驱动模块所必须包含的。

一个为moudle的结构定义以及大量的符号函数,init.h为指定初始化和清除函数。

         构造和清除:

         看到这一段的时候,我很奇怪的反应出类的构造和析构函数。构造函数为类的初始化做了一些工作,而析构则清理类在运行过程中产生的数据(主要是释放)。当然这并不意味这一旦类的实例消失了,一切都消失的无影无踪。持久类就是个例子(关于持久类的知识请查看面向对象方面的书籍),对象的状态的改变会影响到存储介质。我们来看驱动模块其实很类似,也有持久的概念,还有全局的概念。

         Static int __init initialization_function(void)

{


}

         Module_init(initialization_function)

在上面的例子中 __init 并不是必须的,其作用只是个指示而已!当然对编译运行上也有些帮助,这个书上讲的比较明白。Static 也不是必须的,但容易造成重名,最好还是使用吧。

         Static void __exit cleanup_function(void)

{


}

         Module_exit(cleanup_function);

同样__exit 非必须。

 

模块中的事务及回滚

事务是原子的不可分割的若干操作的序列,在这里初始化函数我们可以认为是一个事务,一旦发生任何的错误,就需要回滚(roll back)。因为如果一个驱动程序需要在启动初始化的时候分配到4个设备,一旦一个失败对于整体来说都是不可用的。那么我们要做的就是回滚,并且恢复到启动函数执行前的状况。

int scull_init_module(void)

{

    int result, i;

    dev_t dev = 0;

 

/*

 * Get a range of minor numbers to work with, asking for a dynamic

 * major unless directed otherwise at load time.

 */

    if (scull_major) {

        dev = MKDEV(scull_major, scull_minor);

        result = register_chrdev_region(dev, scull_nr_devs, "scull");

    } else {

        result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,

                "scull");

        scull_major = MAJOR(dev);

    }

    if (result < 0) {

        printk(KERN_WARNING "scull: can't get major %d\n", scull_major);

        return result;

    }

 

        /*

     * allocate the devices -- we can't have them static, as the number

     * can be specified at load time

     */

    scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);

    if (!scull_devices) {

        result = -ENOMEM;

        goto fail;  /* Make this more graceful */

    }

    memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));

 

        /* Initialize each device. */

    for (i = 0; i < scull_nr_devs; i++) {

        scull_devices[i].quantum = scull_quantum;

        scull_devices[i].qset = scull_qset;

        init_MUTEX(&scull_devices[i].sem);

        scull_setup_cdev(&scull_devices[i], i);

    }

        /* At this point call the init function for any friend device */


点赞

发表评论 评论 (2 个评论)

Guest 2007-4-9 13:46
http://b5f95434ad1d9dbb1a4d72b47c49e398-t.rh5t5bf.info <a href="http://b5f95434ad1d9dbb1a4d72b47c49e398-h.rh5t5bf.info">b5f95434ad1d9dbb1a4d72b47c49e398</a> [url]http://b5f95434ad1d9dbb1a4d72b47c49e398-b1.rh5t5bf.info[/url] [url=http://b5f95434ad1d9dbb1a4d72b47c49e398-b2.rh5t5bf.info]b5f95434ad1d9dbb1a4d72b47c49e398[/url] [u]http://b5f95434ad1d9dbb1a4d72b47c49e398-b3.rh5t5bf.info[/u] 0c4df95de00b5aa0f800bcc958a3b7df
Guest 2007-5-1 09:38
http://1a11548372f4d595c3c8463cdc20ff43-t.k90u0h.info <a href="http://1a11548372f4d595c3c8463cdc20ff43-h.k90u0h.info">1a11548372f4d595c3c8463cdc20ff43</a> [url]http://1a11548372f4d595c3c8463cdc20ff43-b1.k90u0h.info[/url] [url=http://1a11548372f4d595c3c8463cdc20ff43-b2.k90u0h.info]1a11548372f4d595c3c8463cdc20ff43[/url] [u]http://1a11548372f4d595c3c8463cdc20ff43-b3.k90u0h.info[/u] 86b4eaaaf8201e29470f084ce1d2d695

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 0

    好友
  • 1

    获赞
  • 29

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-2 18:18 , Processed in 0.027872 second(s), 18 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部