我已经开始学习 Linux 驱动程序,但我发现它有点困难。
我一直在研究 i2c 驱动程序,我对驱动程序的入口点感到很困惑。驱动程序是否从MOUDULE_INIT()
宏开始?
而且我也想知道如何才能知道驱动程序运行的过程。我得到了这本书,Linux 设备驱动程序,但我仍然很困惑。你可以帮帮我吗?非常感谢。
我将以 i2c 驱动程序为例。里面有这么多功能,我只想知道如何才能在i2c驱动程序中获得功能的协调关系?
我已经开始学习 Linux 驱动程序,但我发现它有点困难。
我一直在研究 i2c 驱动程序,我对驱动程序的入口点感到很困惑。驱动程序是否从MOUDULE_INIT()
宏开始?
而且我也想知道如何才能知道驱动程序运行的过程。我得到了这本书,Linux 设备驱动程序,但我仍然很困惑。你可以帮帮我吗?非常感谢。
我将以 i2c 驱动程序为例。里面有这么多功能,我只想知道如何才能在i2c驱动程序中获得功能的协调关系?
设备驱动程序不是具有main {}
起点和出口点的“程序”。它更像是一个 API 或一个库或一组例程。在这种情况下,它是一组由,声明的入口点,以及列出操作入口点的结构。MODULE_INIT()
MODULE_EXIT()
EXPORT_SYMBOL()
对于块设备include/linux/blkdev.h
,驱动程序应该通过在 (from )中为这些操作声明其函数来提供它可以执行的操作列表:
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 devicesinclude/linux/fs.h
,驱动程序应通过在 (from )中为这些操作声明其函数来提供它可以执行的操作列表:
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
,驱动程序应通过在 (from ) 中为这些操作声明其功能来提供它可以执行的操作列表:
struct platform_driver {
int (*probe)();
int (*remove)();
void (*shutdown)();
int (*suspend)();
int (*resume)();
struct device_driver driver;
const struct platform_device_id *id_table;
};
驱动程序,尤其是字符驱动程序,不必支持列出的每个操作。请注意,有一些宏可以通过命名结构条目来促进这些结构的编码。
驱动程序是否从 MOUDLUE_INIT() 宏开始?
中指定的驱动程序的init()例程MODULE_INIT()
将在引导期间(静态链接时)或动态加载模块时调用。当驱动程序在其init()期间注册自己时,驱动程序将其操作结构传递给设备的子系统。
这些设备驱动程序入口点,例如open()或read(),通常在用户应用程序调用 C 库调用(在用户空间中)和切换到内核空间之后执行。请注意,您正在查看的 i2c 驱动程序是叶设备使用的总线的平台驱动程序,其公开的功能将由其他驱动程序调用。EXPORT_SYMBOL()
只有在中指定的驱动程序的init()例程MODULE_INIT()
才能保证被调用。只有在动态卸载模块时/当模块被动态卸载时,才会执行中指定的驱动程序的exit()例程。MODULE_EXIT()
驱动程序的操作例程将以未知的顺序被异步调用(就像它的中断服务例程一样)。希望用户程序在发出read()或ioctl()操作之前调用open(),并以合理的方式调用其他操作。一个编写良好且健壮的驱动程序应该适应任何操作顺序或顺序,并产生合理的结果以确保系统完整性。
停止将设备驱动程序视为程序可能会有所帮助。他们完全不同。一个程序有一个特定的起点,做一些事情,并且有一个或多个相当明确的(好吧,无论如何他们应该)退出点。驱动程序在第一次加载时有一些事情要做(例如MODULE_INIT()
和其他事情),并且可能会或可能永远不会再做任何事情(您可以强制加载系统实际没有的硬件的驱动程序),并且可能有一些如果驱动程序被卸载,需要做的事情。除此之外,驱动程序通常会提供一些特定的入口点(系统调用、ioctl 等),用户级应用程序可以访问这些入口点以请求驱动程序执行某些操作。
可怕的类比,但想想一个有点像汽车的程序——你上车,启动它,开车到某个地方,然后下车。司机更像是一台自动售货机——你把它插上电源并确保它有货,但人们只是偶尔过来按下按钮让它做点什么。
实际上,您首先要了解(I2C)平台(本机)驱动程序,您需要了解平台驱动程序的 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/7136和 http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel /
内核模块的开始是从初始化函数开始,主要是在函数名前面加上宏__init。
__init 宏向 linux 内核指示以下函数是一个初始化函数,一旦执行初始化函数的代码,用于该初始化函数的资源将是空闲的。
还有其他的marcos,用于检测初始化和释放函数,命名为module_init()和module_exit()[如上所述]。
如果设备驱动程序的目标是在运行时作为可加载和可删除的内核模块运行[即使用 insmod 或 rmmod 命令],则使用这两个宏
简而言之:它从 .probe 开始,并在您执行 insmod 时一直到 init。这也将驱动程序注册到驱动程序子系统并启动 init。每次从用户应用程序调用驱动程序功能时,都会使用回调调用函数。
《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 设备驱动系列》