module_xxx_driver宏定义
在linux驱动中,一般每个模块该函数都需要加载,通常加载步骤是:
static int __init xxx_init(void)
{
....../* 模块各种初始化内容*/
return 0;
}
static void __exit xxx_exit(void)
{
....../* 模块卸载时需要的东西*/
}
module_init(xxx_init);
module_exit(xxx_exit);
i2c注册过程
在i2c驱动中,一般在模块入口函数注册i2c_driver结构体,一般普通操作如下
static struct i2c_driver xxx_driver; /* 定义i2c设备驱动结构体 */
static int __init xxx_init(void)
{
return i2c_add_driver(&xxx_driver); /* 注册i2c驱动 */
}
static void __exit xxx_exit(void)
{
i2c_del_driver(&xxx_driver); /* 注销i2c驱动 */
}
module_init(xxx_init);
module_exit(xxx_exit);
但是,linux也定义了一个宏定义module_i2c_driver(struct i2c_driver)来使我们简化编写过程,一行搞定!如下:
struct i2c_driver xxx_driver;
module_i2c_driver(xxx_driver); /* 只需此步骤就可以将上面一系列代码省去*/
module_i2c_driver()此宏定义执行步骤如下:
在/include/linux/i2c.h文件下的第621行左右有此宏定义
#define module_i2c_driver(__i2c_driver) \
module_driver(__i2c_driver, i2c_add_driver, \
i2c_del_driver)
然后module_driver也是一个宏定义在/include/linux/device.h文件下的1260行左右有此定义
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
将上面展开就是:
static int __init __i2c_driver_init(void)
{
return i2c_add_driver(&__i2c_driver); /* 注册i2c驱动函数 */
}
static void __exit __i2c_driver_exit(void)
{
i2c_del_driver(&__i2c_driver); /* 注销i2c驱动函数 */
}
module_init(__i2c_driver_init);
module_exit(__i2c_driver_exit);
由此可见,module_i2c_driver这个宏定义的作用就是帮我们注册驱动,和上面手动注册过程一模一样。
因此,在注册时,我们既可以手动注册驱动,也可以使用module_i2c_driver宏定义来注册驱动。
platform注册过程
在platform驱动中,一般在驱动入口在注册platform驱动,一般过程如下:
static struct platform_driver xxx_driver;
static int __init xxx_init(void)
{
return platform_driver_register(&xxx_driver); /* platform驱动注册函数*/
}
static void __exit xxx_exit(void)
{
platform_driver_unregister(&xxx_driver); /* platform驱动注销函数 */
}
module_init(xxx_init);
module_exit(xxx_exit);
如果使用module_platform_driver(struct platform_driver)宏定义,那么驱动注册过程将代码将减少很多,如下:
static platform_driver xxx_driver;
module_platform_driver(xxx_driver);
modlue_platform_driver宏定义执行步骤是:
在/include/linux/platform_device文件下第221行有此宏定义
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
和上面module_i2c_driver的内容一样,就是传入进去的注册函数不一样
然后module_driver也是一个宏定义在/include/linux/device.h文件下的1260行左右有此定义,
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
将上面展开就是:
static int __init __platform_driver_init(void)
{
return platform_driver_register(&__platform_driver); /* 注册platform驱动函数 */
}
static void __exit __platform_driver_exit(void)
{
platform_driver_unregister(&__platform_driver); /* 注销platform驱动函数 */
}
module_init(__platform_driver_init);
module_exit(__platform_driver_exit);
有此可见,platform驱动代码既可以写成上面一系列过程也可以写module_platform_driver()宏定义。
SPI 注册过程 (2020/3/22更新)
在SPI驱动中,一般在驱动入口注册驱动函数,如下:
struct spi_driver xxx_driver;
static int __init xxx_init(void)
{
/* 当注册后次spi的操作函数就可以使用了 */
return spi_register_driver(&xxx_driver); /* SPI驱动注册函数 */
}
static void __exit xxx_exit(void)
{
spi_unregister_driver(&xxx_driver); /* SPI驱动注销函数 */
}
module_init(xxx_init);
module_exit(xxx_exit);
如果使用module_spi_driver(struct spi_driver)宏定义来注册的话,就会省去很多代码,如下:
module_spi_driver(xxx_driver);
module_spi_driver宏定义执行步骤是:
在/include/linux/spi.h文件下第214行有此宏定义
#define module_spi_driver(__spi_driver) \
module_driver(__spi_driver, spi_register_driver, \
spi_unregister_driver)
和上面module_i2c_driver的内容一样,就是传入进去的注册函数不一样
然后module_driver也是一个宏定义在/include/linux/device.h文件下的1260行左右有此定义,
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
将上面展开就是:
static int __init __spi_driver_init(void)
{
return spi_register_driver(&__spi_driver); /* 注册spi驱动函数 */
}
static void __exit __spi_driver_exit(void)
{
spi_unregister_driver(&__spi_driver); /* 注销spi驱动函数 */
}
module_init(__spi_driver_init);
module_exit__spi_driver_exit);
有此可见,spi驱动代码既可以写成上面一系列过程也可以写module_spi_driver()宏定义。
好像看来如果都使用宏定义来注册驱动,名字、使用方法差不多,区别就是换了一个不同驱动模型的名字:
i2c_driver->module_i2c_driver
platform_driver->module_platform_driver
spi_driver->module_spi_driver
目前就学了这三个驱动平台,所以总结的也不是很严谨,但是也值得参考,以后学习到更多的linux驱动注册过程,在继续添加。