程序启动的Linux设备驱动程序?

时间:2012-10-16 14:37:53

标签: linux-kernel linux-device-driver

我已经开始学习Linux驱动程序,但我发现它有点困难。

我一直在研究i2c驱动程序,我对驱动程序的入口点感到很困惑。驱动程序是否从MOUDULE_INIT()宏开始?

我还想知道如何知道驱动程序如何运行的过程。我得到了这本书,Linux设备驱动程序,但我仍然很困惑。你可以帮帮我吗?非常感谢。

我将以i2c驱动程序为例。其中有很多功能,我只想知道如何在i2c驱动程序中协调各种功能?

6 个答案:

答案 0 :(得分:11)

设备驱动程序不是具有起始点和出口点main {}的“程序”。它更像是API或库或例程集合。在这种情况下,它是由MODULE_INIT()MODULE_EXIT(),可能是EXPORT_SYMBOL()声明的一组入口点,以及列出操作的入口点的结构

对于块设备,驱动程序应通过为(来自include/linux/blkdev.h)的那些操作声明其功能来提供它可以执行的操作列表:

struct block_device_operations {
        int (*open) ();
        int (*release) ();
        int (*ioctl) ();
        int (*compat_ioctl) ();
        int (*direct_access) ();
        unsigned int (*check_events) ();
        /* ->media_changed() is DEPRECATED, use ->check_events() instead */
        int (*media_changed) ();
        void (*unlock_native_capacity) ();
        int (*revalidate_disk) ();
        int (*getgeo)();
        /* this callback is with swap_lock and sometimes page table lock held */
        void (*swap_slot_free_notify) ();
        struct module *owner;
};

对于 char devices ,驱动程序需要通过为(来自include/linux/fs.h)的那些操作声明其函数来提供它可以执行的操作列表:

struct file_operations {
        struct module *owner;
        loff_t (*llseek) ();
        ssize_t (*read) ();
        ssize_t (*write) ();
        ssize_t (*aio_read) ();
        ssize_t (*aio_write) ();
        int (*readdir) ();
        unsigned int (*poll) ();
        long (*unlocked_ioctl) ();
        long (*compat_ioctl) ();
        int (*mmap) ();
        int (*open) ();
        int (*flush) ();
        int (*release) ();
        int (*fsync) ();
        int (*aio_fsync) ();
        int (*fasync) ();
        int (*lock) ();
        ssize_t (*sendpage) ();
        unsigned long (*get_unmapped_area)();
        int (*check_flags)();
        int (*flock) ();
        ssize_t (*splice_write)();
        ssize_t (*splice_read)();
        int (*setlease)();
        long (*fallocate)();
};

对于平台设备,驱动程序应通过为(来自include/linux/platform_device.h)的那些操作声明其功能来提供它可以执行的操作列表:

struct platform_driver {
        int (*probe)();
        int (*remove)();
        void (*shutdown)();
        int (*suspend)();
        int (*resume)();
        struct device_driver driver;
        const struct platform_device_id *id_table;
};

驱动程序,尤其是char驱动程序,不必支持列出的每个操作。请注意,有一些宏可以通过命名结构条目来促进这些结构的编码。

  

驱动程序是否从MOUDLUE_INIT()宏开始?

MODULE_INIT()中指定的驱动程序的 init()例程将在引导期间(静态链接时)或模块动态加载时被调用。当驱动程序在 init()期间注册时,驱动程序将其操作结构传递给设备的子系统。

这些设备驱动程序入口点,例如 open() read()通常在用户应用程序调用C库调用(在用户空间中)和切换到内核空间后执行。请注意,您正在查看的i2c驱动程序是 leaf 设备使用的总线的platform driverEXPORT_SYMBOL()公开的其功能将由其他驱动程序调用

只保证调用MODULE_INIT()中指定的驱动程序的 init()例程。 MODULE_EXIT()中指定的驱动程序的 exit()例程仅在/动态卸载模块时执行。驱动程序的op例程将以未知顺序异步调用(就像它的中断服务例程一样)。希望用户程序在发出 read() ioctl()操作之前调用 open(),并在合理的情况下调用其他操作时尚。一个编写良好且功能强大的驱动程序应该适应任何顺序或操作顺序,并产生合理的结果以确保系统完整性。

答案 1 :(得分:2)

这可能有助于停止将设备驱动程序视为程序。他们完全不同。一个程序有一个特定的起点,做一些东西,并有一个或多个相当好的定义(好吧,他们应该,无论如何)退出点。驱动程序在第一次加载时会有一些事情要做(例如MODULE_INIT()和其他东西),可能会或可能不会再做任何事情(你可以强行加载你的系统实际上没有的硬件驱动程序) ,如果驱动程序被卸载,可能会有一些需要完成的事情。除此之外,驱动程序通常会提供一些特定的入口点(系统调用,ioctl等),用户登陆应用程序可以访问这些入口点以请求驱动程序执行某些操作。

可怕的类比,但想到一个类似汽车的程序 - 你进去,启动它,开车到某个地方,然后离开。一个驱动程序更像是一个自动售货机 - 你插上它并确保它的库存,但是人们只是偶尔出现并按下按钮使它做某事。

答案 2 :(得分:0)

实际上,您首先需要了解(I2C)平台(Native)驱动程序,您需要了解平台驱动程序的MOUDULE_INIT()与其他可加载模块的对比情况。

/*
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module).  There can only
* be one per module.*/

对于i2c驱动程序,您可以参考此链接http://www.linuxjournal.com/article/7136http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel/

答案 3 :(得分:0)

内核模块的开始是从初始化函数开始的,它主要用函数名称前面的宏 __ init 来解决。

__init宏向linux内核指示以下函数是初始化函数,并且一旦执行初始化函数的代码,将用于此初始化函数的资源将是空闲的。

还有其他用于检测初始化和释放功能的marcos,名为module_init()和module_exit()[如上所述]。

如果设备驱动程序的目标是在运行时作为可加载和可移除的内核模块运行,则使用这两个宏[即使用insmod或rmmod命令]

答案 4 :(得分:0)

简洁明了:它从.probe开始,一旦你做insmod就一直转到init。这也是用驱动子系统注册驱动程序并启动init。 每次从用户应用程序调用驱动程序功能时,都会使用回调函数调用函数。

答案 5 :(得分:-1)

“Linux设备驱动程序”是一本好书但它已经老了!

基本示例:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Name and e-mail");
MODULE_DESCRIPTION("my_first_driver"); 

static int __init insert_mod(void)
{
    printk(KERN_INFO "Module constructor");
    return 0;
}

static void __exit remove_mod(void)
{
    printk(KERN_INFO "Module destructor");
}

module_init(insert_mod);
module_exit(remove_mod);

最新的教程,写得非常好,是“Linux Device Drivers Series