(本章基于:Linux-3.13.0-32)
Linux总线设备驱动模型结构如下图:
设备(device)和驱动(driver)分别挂载在总线(bus)上,总线再通过自身的匹配函数(match)帮助device找到对应driver或者帮助driver找到对应的device;
数据结构
总线(bus)结构
struct bus_type {
//总线名
const char *name;
//匹配函数
int (*match)(struct device *dev, struct device_driver *drv);
......
}
驱动(driver)结构
struct device_driver {
//驱动名
const char *name;
//需挂载的总线
struct bus_type *bus;
//驱动处理函数
int (*probe) (struct device *dev);
........
}
设备(device)结构
struct device {
//设备名
const char *init_name;
//需挂载的总线
struct bus_type *bus;
......
}
相关操作函数
bus注册注销
int bus_register(struct bus_type *bus);
int bus_unregister(struct bus_type *bus);
成功注册bus后可在/sys/bus下看到对应的目录;
driver注册注销
int driver_register(struct device_driver *drv);
int driver_unregister(struct device_driver *drv);
成功注册driver后可在/sys/bus下对应的总线目录下的drivers中看到此驱动;
device注册注销
int device_register(struct device *dev);
int device_unregister(struct device *dev);
成功注册device后可在/sys/bus/下对应的总线目录下的devices中看到此设备;
例:
本例分三个小模块bus、driver、device,bus使用名称匹配driver与device。依次挂载模块bus、driver、device,bus匹配device到对应的驱动driver并执行其中的驱动处理函数probe()。反之依次挂载bus、device、driver可以得到同样的效果;
注意:
1、注册device时我们将名称参数保存在成员init_name中,但在注册过程中会将init_name中的名称拷贝到kobj.name中,并将init_name置空。这点在匹配函数的编写中非常重要;
2、driver、device中均需要使用bus中使用EXPORT_SYMBOL导出的bus变量名,但事实上driver、device无法获取到这一变量,这是由于2.6.26之后产生的一个内核BUG,解决办法见:http://blog.csdn.net/stone8761/article/details/74744550
my_bus.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
int my_match(struct device *dev, struct device_driver *drv)
{
if(dev->kobj.name && drv->name) {
return !strncmp(dev->kobj.name, drv->name, strlen(drv->name));
} else {
return 0;
}
}
struct bus_type my_bus_type = {
.name = "my_bus",
.match = my_match,
};
EXPORT_SYMBOL_GPL(my_bus_type);
static __init int hello_init(void)
{
bus_register(&my_bus_type);
return 0;
}
static __exit void hello_exit(void)
{
bus_unregister(&my_bus_type);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stone");
my_driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
int my_probe(struct device *dev)
{
printk(KERN_INFO "found the driver!!!!!\n");
return 0;
}
extern struct bus_type my_bus_type;
struct device_driver my_driver = {
.name = "my_driver_device",
.bus = &my_bus_type,
.probe = my_probe,
};
static __init int hello_init(void)
{
if(driver_register(&my_driver)) {
printk(KERN_WARNING "driver_register error!\n");
return 1;
}
return 0;
}
static __exit void hello_exit(void)
{
driver_unregister(&my_driver);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stone");
my_device.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
extern struct bus_type my_bus_type;
void my_release(struct device *dev)
{
return;
}
struct device my_device = {
.init_name = "my_driver_device",
.bus = &my_bus_type,
.release = my_release,
};
static __init int hello_init(void)
{
if(device_register(&my_device)) {
printk(KERN_WARNING "device_register error!\n");
return 1;
}
printk(KERN_INFO "device init!\n");
return 0;
}
static __exit void hello_exit(void)
{
device_unregister(&my_device);
printk(KERN_INFO "device exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stone");