平台总线设备驱动框架1

来源:互联网 发布:知乎红人 编辑:程序博客网 时间:2024/05/28 15:10


/********************************************************/

内核版本:2.6.35.7

运行平台:三星s5pv210

/********************************************************/

 

1、什么是platform(平台)总线?

相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。

那为什么需要platform总线呢?其实是Linux设备驱动模型为了保持设备驱动的统一性而虚拟出来的总线。因为对于usb设备、i2c设备、pci设备、spi设备等等,他们与cpu的通信都是直接挂在相应的总线下面与我们的cpu进行数据交互的,但是在我们的嵌入式系统当中,并不是所有的设备都能够归属于这些常见的总线,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。所以Linux驱动模型为了保持完整性,将这些设备挂在一条虚拟的总线上(platform总线),而不至于使得有些设备挂在总线上,另一些设备没有挂在总线上。

platform总线相关代码:driver\base\platform.c 文件

相关结构体定义:include\linux\platform_device.h 文件中

 

2、platform总线管理下的2员大将

(1)两个结构体platform_device和platform_driver

对于任何一种Linux设备驱动模型下的总线都由两个部分组成:描述设备相关的结构体和描述驱动相关的结构体

在platform总线下就是platform_device和platform_driver,下面是对两个结构体的各个元素进行分析:

platform_device结构体:(include\linux\platform_device.h)

复制代码
 1 struct platform_device {           //  platform总线设备 2     const char    * name;          //  平台设备的名字 3     int        id;                 //   ID 是用来区分如果设备名字相同的时候(通过在后面添加一个数字来代表不同的设备,因为有时候有这种需求) 4     struct device    dev;          //   内置的device结构体 5     u32        num_resources;      //   资源结构体数量 6     struct resource    * resource; //   指向一个资源结构体数组 7  8     const struct platform_device_id    *id_entry; //  用来进行与设备驱动匹配用的id_table表 9 10     /* arch specific additions */11     struct pdev_archdata    archdata;             //  自留地    添加自己的东西12 };
复制代码

 

platform_device结构体中的struct resource结构体分析:

复制代码
1 struct resource {      // 资源结构体2     resource_size_t start;      // 资源的起始值,如果是地址,那么是物理地址,不是虚拟地址3     resource_size_t end;        // 资源的结束值,如果是地址,那么是物理地址,不是虚拟地址4     const char *name;           // 资源名5     unsigned long flags;        // 资源的标示,用来识别不同的资源6     struct resource *parent, *sibling, *child;   // 资源指针,可以构成链表7 };
复制代码

 

platform_driver结构体:(include\linux\platform_device.h)

复制代码
1 struct platform_driver {2     int (*probe)(struct platform_device *);     //  这个probe函数其实和  device_driver中的是一样的功能,但是一般是使用device_driver中的那个3     int (*remove)(struct platform_device *);    //  卸载平台设备驱动的时候会调用这个函数,但是device_driver下面也有,具体调用的是谁这个就得分析了4     void (*shutdown)(struct platform_device *);5     int (*suspend)(struct platform_device *, pm_message_t state);6     int (*resume)(struct platform_device *);7     struct device_driver driver;                //   内置的device_driver 结构体 8     const struct platform_device_id *id_table;  //  该设备驱动支持的设备的列表  他是通过这个指针去指向  platform_device_id 类型的数组9 };
复制代码

 

(2)两组接口函数(driver\base\platform.c)

int platform_driver_register(struct platform_driver *);       // 用来注册我们的设备驱动    

void platform_driver_unregister(struct platform_driver *);  // 用来卸载我们的设备驱动

int platform_device_register(struct platform_device *);      // 用来注册我们的设备      

void platform_device_unregister(struct platform_device *); // 用来卸载我们的设备

 

3、platform平台总线的初始化

(1)platform平台总线的注册初始化:  platform_bus_init

/***********************************************************************/

platform_bus_init

    early_platform_cleanup               //  进行一些早期的平台清理   

    device_register                          //  注册设备 (在/sys/devices/目录下建立 platform目录对应的设备对象  /sys/devices/platform/) 

    bus_register                              //  总线注册

/************************************************************************/

 

(2)相关结构体

复制代码
 1 struct bus_type { 2     const char        *name;                     //  总线名字 3     struct bus_attribute    *bus_attrs;          //  该总线的属性 4     struct device_attribute    *dev_attrs;       //  该总线下设备的属性 5     struct driver_attribute    *drv_attrs;       //  该总线下设备驱动的属性 6  7     int (*match)(struct device *dev, struct device_driver *drv);     //  该总线下设备与设备驱动的匹配函数 8     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  //   事件函数    热拨插 9     int (*probe)(struct device *dev);                                //   总线下的  探针函数10     int (*remove)(struct device *dev);11     void (*shutdown)(struct device *dev);12 13     int (*suspend)(struct device *dev, pm_message_t state);14     int (*resume)(struct device *dev);15 16     const struct dev_pm_ops *pm;  //  电源管理相关的17 18     struct bus_type_private *p;   //  总线的私有数据  p->subsys.kobj 表示该总线在驱动模型中对应的对象19 };
复制代码

 

 

复制代码
 1 struct bus_type_private { 2     struct kset subsys;                //  这个是bus主要的kset 3     struct kset *drivers_kset;         //  这个kset指针用来指向该总线的 drivers目录的 4     struct kset *devices_kset;         //  这个kse指针用来指向该总线的devices目录的 5     struct klist klist_devices;        //  用来挂接该总线下的设备的一个链表头 6     struct klist klist_drivers;        //   用来挂接该总线下的设备驱动的一个链表头 7     struct blocking_notifier_head bus_notifier; 8     unsigned int drivers_autoprobe:1;  //   是否需要在设备驱动注册时候子自动匹配设备 9     struct bus_type *bus;              //  指向本bus结构体10 };
复制代码

 

(3)函数详解

bus_register:

复制代码
 1 int bus_register(struct bus_type *bus) 2 { 3     int retval; 4     struct bus_type_private *priv;                               //  定义一个bus_type_private 结构体指针 5  6     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //   申请分配内存 7     if (!priv) 8         return -ENOMEM; 9 10     priv->bus = bus;            //   使用 priv->bus 指向我们传进来的bus11     bus->p = priv;              //   通过  bus->p  指向priv    这里其实就是将bus与priv建立关系,这个跟之前的device、class的设计是一样的12 13     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);14 15     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  //   给我们的bus在设备驱动模型中的对象设置名字   bus->p->subsys.kobj16     if (retval)17         goto out;18 19 //   这里就是对bus的私有数据进行一些填充20     priv->subsys.kobj.kset = bus_kset;      //  设置bus对象的父对象     也就是  /sys/bus 这目录 作为他的上层目录  所有的具体的总线类型对象都是在这个目录下21     priv->subsys.kobj.ktype = &bus_ktype;   //  设置bus对象的  对象类型为 bus_ktype22     priv->drivers_autoprobe = 1;            //  配置为在注册设备或者是注册设备驱动时自动进行配置    这个就决定了为什么我们在注册设备或者是设备驱动能够进行自动匹配23 24     retval = kset_register(&priv->subsys);  //  注册kset结构体(内部会调用kobject_add_internal函数,也就是将bus对象添加到 /sys/bus/目录下, /sys/bus/xxx_busType  对应具体的总线)25     if (retval)26         goto out;27 28     retval = bus_create_file(bus, &bus_attr_uevent);  //  在该bus下建立属性文件   (对应的就是 bus下的 uevent属性)29     if (retval)30         goto bus_uevent_fail;31 32     priv->devices_kset = kset_create_and_add("devices", NULL, //  在具体总线的目录下创建 kset 容器对象   /sys/bus/xxx_busType/devices33                          &priv->subsys.kobj);                 //  通过priv->devices_kset指针去指向 这个目录对应的对象34     if (!priv->devices_kset) {35         retval = -ENOMEM;36         goto bus_devices_fail;37     }38 39     priv->drivers_kset = kset_create_and_add("drivers", NULL,   //   /sys/bus/xxx_busType/drivers40                          &priv->subsys.kobj);                   //   通过 priv->drivers_kset 指针去指向  这个目录对应的对象41     if (!priv->drivers_kset) {42         retval = -ENOMEM;43         goto bus_drivers_fail;44     }45 46     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  //  初始化链表  klist47     klist_init(&priv->klist_drivers, NULL, NULL);                            //  初始化链表  klist48 49     retval = add_probe_files(bus);    //  添加探针文件   其实内部做的还是添加属性文件   /sys/bus/xxx_busType/drivers_probe    /sys/bus/xxx_busType/drivers_autoprobe50     if (retval)51         goto bus_probe_files_fail;52 53     retval = bus_add_attrs(bus);      //  根据 bus->bus_attrs 中的属性设置来添加属性文件54     if (retval)55         goto bus_attrs_fail;56 57     pr_debug("bus: '%s': registered\n", bus->name);58     return 0;59 60 bus_attrs_fail:61     remove_probe_files(bus);62 bus_probe_files_fail:63     kset_unregister(bus->p->drivers_kset);64 bus_drivers_fail:65     kset_unregister(bus->p->devices_kset);66 bus_devices_fail:67     bus_remove_file(bus, &bus_attr_uevent);68 bus_uevent_fail:69     kset_unregister(&bus->p->subsys);70     kfree(bus->p);71 out:72     bus->p = NULL;73     return retval;74 }
复制代码

 

4、platform平台设备注册

(1)platform平台总线注册函数:  platform_device_register

/************************************************************************************/

platform_device_register

    device_initialize

    platform_device_add

        device_add           //  这个函数之前分析过了,这里就不再分析了 

/***********************************************************************************/

 

(2)函数分析

复制代码
 1 int platform_device_add(struct platform_device *pdev) 2 { 3     int i, ret = 0; 4  5     if (!pdev) 6         return -EINVAL; 7  8     if (!pdev->dev.parent)               9         pdev->dev.parent = &platform_bus;       //  将平台设备的父设备设置为 platform_bus (对应的就是  /sys/devices/platform 这个目录)10 11     pdev->dev.bus = &platform_bus_type;         //  设置平台设备挂接在 platform总线下     platform_bus_type12 13     if (pdev->id != -1)14         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id); //  给平台设备对应的对象设置名字  name.id  (如果我们的 pdev->id 设置不等于-1时)15     else16         dev_set_name(&pdev->dev, "%s", pdev->name);17 18 //   下面的for 循环是对平台设备资源的一些处理19     for (i = 0; i < pdev->num_resources; i++) {20         struct resource *p, *r = &pdev->resource[i];21 22         if (r->name == NULL)23             r->name = dev_name(&pdev->dev);24 25         p = r->parent;26         if (!p) {27             if (resource_type(r) == IORESOURCE_MEM)28                 p = &iomem_resource;29             else if (resource_type(r) == IORESOURCE_IO)30                 p = &ioport_resource;31         }32 33         if (p && insert_resource(p, r)) {34             printk(KERN_ERR35                    "%s: failed to claim resource %d\n",36                    dev_name(&pdev->dev), i);37             ret = -EBUSY;38             goto failed;39         }40     }41 //////////////////////////////////////////////////////////////////42 43     pr_debug("Registering platform device '%s'. Parent at %s\n",44          dev_name(&pdev->dev), dev_name(pdev->dev.parent));45 46     ret = device_add(&pdev->dev);    //   将平台设备添加到系统中去  /sys/devices/platform/xxx47     if (ret == 0)48         return ret;49 50  failed:51     while (--i >= 0) {52         struct resource *r = &pdev->resource[i];53         unsigned long type = resource_type(r);54 55         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)56             release_resource(r);57     }58 59     return ret;60 }
复制代码

 

5、platform平台设备驱动注册

(1)platform平台设备驱动注册函数: platform_driver_register

/*********************************************************************/

platform_driver_register

    driver_register

        driver_find

        bus_add_driver

            kobject_init_and_add

            driver_attach

            klist_add_tail

            module_add_driver

            driver_create_file

            driver_add_attrs

        driver_add_groups

/************************************************************/

(2)函数详解

platform_driver_register:

复制代码
 1 int platform_driver_register(struct platform_driver *drv) 2 { 3     drv->driver.bus = &platform_bus_type;            //  设置设备驱动 挂接在 platform平台总线下   4  5 //  下面做的就是对 drv 中的函数指针进行填充 6     if (drv->probe) 7         drv->driver.probe = platform_drv_probe;   8     if (drv->remove) 9         drv->driver.remove = platform_drv_remove;10     if (drv->shutdown)11         drv->driver.shutdown = platform_drv_shutdown;12 13     return driver_register(&drv->driver);             //  注册设备驱动14 }
复制代码

 

driver_register:

复制代码
 1 int driver_register(struct device_driver *drv) 2 { 3     int ret; 4     struct device_driver *other;           //    定义一个设备驱动指针  other 5  6     BUG_ON(!drv->bus->p); 7  8     if ((drv->bus->probe && drv->probe) || 9         (drv->bus->remove && drv->remove) ||10         (drv->bus->shutdown && drv->shutdown))11         printk(KERN_WARNING "Driver '%s' needs updating - please use "12             "bus_type methods\n", drv->name);13 14     other = driver_find(drv->name, drv->bus);  //   这个函数其实进行了一个校验  比对当前的 总线下是否存在名字和现在需要注册的设备驱动的名字相同的设备驱动15     if (other) {16         put_driver(other);                     //   如果名字相同 直接打印错误  并退出17         printk(KERN_ERR "Error: Driver '%s' is already registered, "18             "aborting...\n", drv->name);19         return -EBUSY;20     }21 22     ret = bus_add_driver(drv);                  //   在总线挂接设备驱动  就是将设备驱动对应的kobj对象与组织建立关系23     if (ret)24         return ret;25     ret = driver_add_groups(drv, drv->groups);   //  26     if (ret)27         bus_remove_driver(drv);28     return ret;29 }
复制代码

 

bus_add_driver:

复制代码
 1 int bus_add_driver(struct device_driver *drv) 2 { 3     struct bus_type *bus;             //  定义一个bus_type 结构体指针 4     struct driver_private *priv;      //   定义一个 driver_private  指针 5     int error = 0; 6  7     bus = bus_get(drv->bus);       //   获取 drv的bus 8     if (!bus) 9         return -EINVAL;10 11     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);12 13     priv = kzalloc(sizeof(*priv), GFP_KERNEL);  //  给priv 申请分配内存空间14     if (!priv) {15         error = -ENOMEM;16         goto out_put_bus;17     }18     klist_init(&priv->klist_devices, NULL, NULL);  //  初始化 priv->klist_devices 链表19     priv->driver = drv;                            //  使用 priv->driver  指向 drv20     drv->p = priv;                                 //   使用drv->p 指向 priv    这两步见多了  ,跟之前分析的是一样的意思  就是建立关系21     priv->kobj.kset = bus->p->drivers_kset;        //   设置设备驱动对象的父对象(  也就是指向一个 kset )    父对象就是   /sys/bus/bus_type/drivers/  这个目录对应的对象22     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //  添加kobject 对象到目录层次中     就能够在  /sys/bus/bus_type/drivers/ 目录中看到设备驱动对应的文件了23                      "%s", drv->name);                             //  priv->kobj->ktype =  driver_ktype     对象类型24     if (error)25         goto out_unregister;26 27     if (drv->bus->p->drivers_autoprobe) {       //  如果定义了自动匹配设备标志位    则在线下面进行自动匹配28         error = driver_attach(drv);             //  尝试将驱动绑定到设备 也就是通过这个函数进行设备与设备驱动的匹配29         if (error)30             goto out_unregister;31     }32     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);  //  链表挂接:   priv->knode_bus  挂接到  bus->p->klist_drivers 链表头上去33     module_add_driver(drv->owner, drv);34 35     error = driver_create_file(drv, &driver_attr_uevent);   //  建立属性文件:   uevent36     if (error) {37         printk(KERN_ERR "%s: uevent attr (%s) failed\n",38             __func__, drv->name);39     }40     error = driver_add_attrs(bus, drv);                    //  根据总线的   bus->drv_attrs  来建立属性文件41     if (error) {42         /* How the hell do we get out of this pickle? Give up */43         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",44             __func__, drv->name);45     }46 47     if (!drv->suppress_bind_attrs) {48         error = add_bind_files(drv);49         if (error) {50             /* Ditto */51             printk(KERN_ERR "%s: add_bind_files(%s) failed\n",52                 __func__, drv->name);53         }54     }55 56     kobject_uevent(&priv->kobj, KOBJ_ADD);57     return 0;58 59 out_unregister:60     kobject_put(&priv->kobj);61     kfree(drv->p);62     drv->p = NULL;63 out_put_bus:64     bus_put(bus);65     return error;66 }
复制代码

 

driver_attach:

复制代码
  1 int driver_attach(struct device_driver *drv)  2 {  3     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);   //  这个函数的功能就是:   依次去匹配bus总线下的各个设备  4 }  5   6   7 int bus_for_each_dev(struct bus_type *bus, struct device *start,  8              void *data, int (*fn)(struct device *, void *))  9 { 10     struct klist_iter i;                //  定义一个klist_iter 结构体变量  包含:  struct klist   和  struct klist_node 11     struct device *dev;              12     int error = 0; 13  14     if (!bus) 15         return -EINVAL; 16  17     klist_iter_init_node(&bus->p->klist_devices, &i,      //  这个函数的功能就是将 klist_devices  和  knode_bus填充到 i 变量中 18                  (start ? &start->p->knode_bus : NULL)); 19     while ((dev = next_device(&i)) && !error)       //  依次返回出总线上的各个设备结构体device 20         error = fn(dev, data);                      //  对于每一个设备和设备驱动都调用fn这个函数  直道成功  或者全部都匹配不上  21     klist_iter_exit(&i); 22     return error; 23 } 24  25  26  27 static int __driver_attach(struct device *dev, void *data) 28 { 29     struct device_driver *drv = data;      //  定义一个device_driver 指针 30  31     /* 32      * Lock device and try to bind to it. We drop the error 33      * here and always return 0, because we need to keep trying 34      * to bind to devices and some drivers will return an error 35      * simply if it didn't support the device. 36      * 37      * driver_probe_device() will spit a warning if there 38      * is an error. 39      */ 40  41     if (!driver_match_device(drv, dev))           //  通过这个函数进行匹配  调用总线下的match 函数 42         return 0; 43  44     if (dev->parent)    /* Needed for USB */ 45         device_lock(dev->parent); 46     device_lock(dev); 47     if (!dev->driver) 48         driver_probe_device(drv, dev);   //  调用probe函数 49     device_unlock(dev); 50     if (dev->parent) 51         device_unlock(dev->parent); 52  53     return 0; 54 } 55  56  57  58 int driver_probe_device(struct device_driver *drv, struct device *dev) 59 { 60     int ret = 0; 61  62     if (!device_is_registered(dev))     //  判断这个设备是否已经注册了 63         return -ENODEV; 64  65     pr_debug("bus: '%s': %s: matched device %s with driver %s\n", 66          drv->bus->name, __func__, dev_name(dev), drv->name); 67  68     pm_runtime_get_noresume(dev); 69     pm_runtime_barrier(dev); 70     ret = really_probe(dev, drv);       //    在这个函数中就会调用设备驱动或者是总线下的 probe  函数 71     pm_runtime_put_sync(dev); 72  73     return ret; 74 } 75  76  77 static int really_probe(struct device *dev, struct device_driver *drv) 78 { 79     int ret = 0; 80  81     atomic_inc(&probe_count); 82     pr_debug("bus: '%s': %s: probing driver %s with device %s\n", 83          drv->bus->name, __func__, drv->name, dev_name(dev)); 84     WARN_ON(!list_empty(&dev->devres_head)); 85  86     dev->driver = drv;                  //   使用 dev->driver  指针去指向 drv  这就使得这两者建立了一种关系 87     if (driver_sysfs_add(dev)) { 88         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", 89             __func__, dev_name(dev)); 90         goto probe_failed; 91     } 92  93     if (dev->bus->probe) {             //   如果总线下的probe函数存在 则调用优先调用这个函数 94         ret = dev->bus->probe(dev); 95         if (ret) 96             goto probe_failed; 97     } else if (drv->probe) {            //  否则调用设备驱动中的probe函数 98         ret = drv->probe(dev);  //   所以由此可知:  总线中的probe函数具有更高的优先级 99         if (ret)100             goto probe_failed;101     }102 103     driver_bound(dev);104     ret = 1;105     pr_debug("bus: '%s': %s: bound device %s to driver %s\n",106          drv->bus->name, __func__, dev_name(dev), drv->name);107     goto done;108 109 probe_failed:110     devres_release_all(dev);111     driver_sysfs_remove(dev);112     dev->driver = NULL;113 114     if (ret != -ENODEV && ret != -ENXIO) {115         /* driver matched but the probe failed */116         printk(KERN_WARNING117                "%s: probe of %s failed with error %d\n",118                drv->name, dev_name(dev), ret);119     }120     /*121      * Ignore errors returned by ->probe so that the next driver can try122      * its luck.123      */124     ret = 0;125 done:126     atomic_dec(&probe_count);127     wake_up(&probe_waitqueue);128     return ret;129 }
复制代码

上面说到了当注册platform平台设备驱动时会进行自动匹配的原理,那么当我们注册platform平台设备时进行自动匹配的代码在哪里呢?

其实这个之前在分析device_create函数时就已经分析过了,只不过没有去详细的分析:

/**********************************************/

platform_device_add

    device_add

        bus_probe_device     //  关键就在这个函数

/*********************************************/

函数分析:

复制代码
 1 void bus_probe_device(struct device *dev) 2 { 3     struct bus_type *bus = dev->bus;             //  获取设备中的总线类型   bus_type 4     int ret; 5  6     if (bus && bus->p->drivers_autoprobe) {       //  如果总线存在  并且  设置了自动进行设备与设备驱动匹配标志位 7         ret = device_attach(dev);                           //  则调用这个函数进行匹配 8         WARN_ON(ret < 0); 9     }10 }11 12 13 14 15 int device_attach(struct device *dev)16 {17     int ret = 0;18 19     device_lock(dev);20     if (dev->driver) {    //    如果我们的设备早就绑定了设备驱动     那么执行下面的21         ret = device_bind_driver(dev);22         if (ret == 0)23             ret = 1;24         else {25             dev->driver = NULL;26             ret = 0;27         }28     } else {     //   我们就分析这条29         pm_runtime_get_noresume(dev);30         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);   //  遍历总线的链表匹配对应的设备驱动31         pm_runtime_put_sync(dev);32     }33     device_unlock(dev);34     return ret;35 }36 //  到这里之后就和上面的其实是一样的了
复制代码

总结:  所以由此可知,当我们不管是先注册设备还是先注册设备驱动都会进行一次设备与设备驱动的匹配过程,匹配成功之后就会调用probe函数,

匹配的原理就是去遍历总线下的相应的链表来找到挂接在他下面的设备或者设备驱动,所以由此可以看出来,这个东西的设计其实是很美的。

 

6、platform总线下的匹配函数

(1)platform_match函数

复制代码
 1 static int platform_match(struct device *dev, struct device_driver *drv) // 总线下的设备与设备驱动的匹配函数 2 { 3     struct platform_device *pdev = to_platform_device(dev);      //  通过device  变量获取到 platform_device  4     struct platform_driver *pdrv = to_platform_driver(drv);      //   通过 driver 获取  platform_driver 5  6     /* match against the id table first */ 7     if (pdrv->id_table)    //   如果pdrv中的id_table 表存在 8         return platform_match_id(pdrv->id_table, pdev) != NULL;  //  匹配id_table 9  10     /* fall-back to driver name match */   //  第二个就是指直接匹配 pdev->name     drv->name  名字是否形同11     return (strcmp(pdev->name, drv->name) == 0);12 }13 14 15 16 17 static const struct platform_device_id *platform_match_id(18             const struct platform_device_id *id,19             struct platform_device *pdev)20 {21     while (id->name[0]) {  //  循环去比较id_table数组中的各个id名字是否与pdev->name 相同22         if (strcmp(pdev->name, id->name) == 0) {23             pdev->id_entry = id;       // 将id_table数组中的名字匹配上的 这个数组项 指针赋值给 pdev->id_entry24             return id;         //  返回这个指针25         }26         id++;27     }28     return NULL;29 }
复制代码

总结: 由上面可知platform总线下设备与设备驱动的匹配原理就是通过名字进行匹配的,先去匹配platform_driver中的id_table表中的各个名字与platform_device->name

名字是否相同,如果相同表示匹配成功直接返回,否则直接匹配platform_driver->name与platform_driver->name是否相同,相同则匹配成功,否则失败。

 

 

 

参考:《朱友鹏嵌入式Linux开发\5.Linux驱动开发\5.5.linux设备驱动模型》

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝账号处于下单保护状态怎么办 淘宝卖家物流单号写错了怎么办 有个人给我发直播消息怎么办 网贷申请多了现在秒拒怎么办 顺丰快递寄的瓜果坏了怎么办 淘宝退货快递公司填错了怎么办 不小心把淘宝账号注销了怎么办 腾讯视频会员开通一个月贵怎么办 微交易买美国指数输了四千块怎么办 淘宝地址中包含了违禁词怎么办 微信支付失败但是钱扣了怎么办 支付宝向别人收款交易关闭了怎么办 从淘宝充的晋江币充值异常怎么办 接手转让店铺会员要求退卡怎么办 转转买手机卖家拒绝退款怎么办 淘宝买的东西电话号码留错了怎么办 平板电脑没电关机没保存文件怎么办 恢复出厂设置需要谷歌账号怎么办 华为手机云端里照片删除了怎么办 客户退货卖家一直没收到货怎么办 在淘宝买到假货投诉不管用怎么办 差评不接电话不回旺旺不要钱怎么办 饿了么同行恶意差评怎么办 苹果手机更新后淘宝用不了怎么办 淘宝网快递丢件了买家怎么办 评价后忘了截图五星好评怎么办 在淘宝被骗了好评返现怎么办 苹果4s微信版本过低怎么办 微信版本太低无法登录怎么办 苹果4微信版本低登录不了怎么办 安卓手机微信版本低登录不了怎么办 苹果微信版本低登录不了怎么办 安装包与当前版本不兼容怎么办 游戏与苹果手机系统不兼容怎么办 闲鱼买家申请退款不退货怎么办 在淘宝买的战地1登录不了怎么办 支付宝转账到注销的账号怎么办 支付宝用户支付密码被锁定怎么办 淘宝提现需要的手机宝令怎么办 手机换号码了支付宝账号怎么办 卖家收到货迟迟不给退款怎么办