[国嵌攻略][125][总线设备驱动模型]

总线模型

随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求越来越高,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函数。

原文地址:https://www.cnblogs.com/d442130165/p/5259776.html