总线模型
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求越来越高,2.4内核已经难以满足这些需求。为了适应这种形势的需要,从Linux2.6内核开始提供了全新的设备驱动模型。
总线驱动设备模型
这个模型首先有一条总线,然后是总线上挂载有很多驱动。当有设备插到总线上的时候,总线会把设备和驱动进行匹配,当设备匹配到驱动时,总线把控制权交给相应的驱动处理;当设备从总线上拔掉的时候,总线会找到相应的驱动来处理相应的事件。这样驱动就可以支持热插拔,并且当驱动从一种总线(如USB)改到另一种总线(如MINIPCI)时,驱动需要修改的部分很少,提高了驱动的可移植性。
总线
1.描述结构
在Linux内核中,总线由bus_type结构表示,定义在<linux/device.h>
struct bus_type{
const char *name; //总线名称
int (*match)(struct device *dev, struct device_driver *drv); //匹配函数,驱动与设备的匹配函数。如果返回非零表示匹配成功,否则匹配失败。物理总线通过设备中的ID与驱动进行匹配,虚拟总线通过设备的名字与驱动进行匹配。
......
}
2.总线的注册与注销
总线的注册使用:
bus_register(struct bus_type *bus)
若成功,新的总线将被添加进系统,并可以在/sys/bus下看到相应的目录
总线的注销使用:
void bus_unregister(struct bus_type *bus)
busmod.c
/******************************************************************** *头文件 *********************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> /******************************************************************** *总线匹配 *********************************************************************/ //总线匹配 int bus_match(struct device *dev, struct device_driver *drv){ //名称匹配 int isMatch; isMatch = !strncmp(dev->kobj.name, drv->name, strlen(drv->name)); return isMatch; } /******************************************************************** *模块安装 *********************************************************************/ //总线结构 struct bus_type busmod = { .name = "busmod", //总线名称 .match = bus_match //匹配函数 }; //安装模块 static int ibus_init(void){ //注册总线 bus_register(&busmod); return 0; } //卸载模块 static void ibus_exit(void){ //注销总线 bus_unregister(&busmod); } /******************************************************************** *模块声明 *********************************************************************/ MODULE_LICENSE("GPL"); MODULE_AUTHOR("D"); MODULE_DESCRIPTION(""); MODULE_VERSION("v1.0"); EXPORT_SYMBOL(busmod); module_init(ibus_init); module_exit(ibus_exit);
驱动
1.描述结构
在Linux内核中,驱动由device_driver结构来表示。
struct device_driver{
const char *name; //驱动名称
struct bus_type *bus; //驱动程序所在的总线
int (*probe)(struct device *dev); //驱动函数,当总线找到与设备匹配的驱动时,调用该函数对设备进行处理
......
}
2.驱动的注册与注销
驱动的注册使用:
int driver_register(struct device_driver *drv)
若成功,新的驱动将被添加进系统,并可以在/sys/bus/xxx/drivers下看到该驱动。
驱动的注销使用:
void driver_unregister(struct device_driver *drv)
drvmod.c
/******************************************************************** *头文件 *********************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> /******************************************************************** *全局变量 *********************************************************************/ extern struct bus_type busmod; /******************************************************************** *驱动处理 *********************************************************************/ //驱动处理 int drv_probe(struct device *dev){ printk("Driver found the device it can be handle! "); return 0; } /******************************************************************** *模块安装 *********************************************************************/ //驱动结构 struct device_driver drvmod = { .name = "drvmod", //驱动名称 .bus = &busmod, //所属总线 .probe = drv_probe, //驱动函数 }; //安装模块 static int idrv_init(void){ //注册驱动 driver_register(&drvmod); return 0; } //卸载模块 static void idrv_exit(void){ //注销驱动 driver_unregister(&drvmod); } /******************************************************************** *模块声明 *********************************************************************/ MODULE_LICENSE("GPL"); MODULE_AUTHOR("D"); MODULE_DESCRIPTION(""); MODULE_VERSION("v1.0"); module_init(idrv_init); module_exit(idrv_exit);
设备
1.描述结构
在Linux内核中,设备由struct device结构表示。
struct device{
const char *init_name; //设备名称,必须与驱动名称相同
struct bus_type *bus; //设备所在的总线
struct kobject kobj.name; //当调用device_register函数时,init_name会被赋值到该变量,然后清空init_name。
......
}
2.设备的注册与注销
设备的注册使用:
int device_register(struct device *dev)
若成功,新的设备将被添加进系统,并可以在/sys/bus/xxx/devices下看到该设备。
设备的注销使用:
void device_unregister(struct device *dev)
devmod.c
/******************************************************************** *头文件 *********************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> /******************************************************************** *全局变量 *********************************************************************/ extern struct bus_type busmod; /******************************************************************** *模块安装 *********************************************************************/ //设备结构 struct device devmod = { .init_name = "drvmod", //设备名称,必须与驱动名称相同 .bus = &busmod //所属总线 }; //安装模块 static int idev_init(void){ //注册设备 device_register(&devmod); return 0; } //卸载模块 static void idev_exit(void){ //注销设备 device_unregister(&devmod); } /******************************************************************** *模块声明 *********************************************************************/ MODULE_LICENSE("GPL"); MODULE_AUTHOR("D"); MODULE_DESCRIPTION(""); MODULE_VERSION("v1.0"); module_init(idev_init); module_exit(idev_exit);
先有驱动后有设备和先有设备后有设备,总线都能让驱动和设备匹配。
第一种情况:
总线上面已经挂载了驱动,然后添加设备,总线会拿match函数去对设备与每个驱动进行匹配。如果能够匹配,那么会调用相应的probe函数。
第二种情况:
总线上面已经挂载了设备,然后添加驱动,总线会拿match函数去对驱动与每个设备进行匹配。如果能够匹配,那么会调用相应的probe函数。