zoukankan      html  css  js  c++  java
  • platform_driver_register()如何match之后调用probe

    int platform_driver_register(struct platform_driver *drv)
    {
        drv->driver.bus = &platform_bus_type;/*关联总线*/
        /*关联driver的设备方法*/
        if (drv->probe)
            drv->driver.probe = platform_drv_probe;
        if (drv->remove)
            drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
            drv->driver.shutdown = platform_drv_shutdown;
    
        return driver_register(&drv->driver);/*注册驱动*/
    }
    
    /******************************************************************************/
    struct platform_driver {
        int (*probe)(struct platform_device *);/*匹配到设备后调用,下面分析内核代码怎么调用的*/
        int (*remove)(struct platform_device *);
        void (*shutdown)(struct platform_device *);
        int (*suspend)(struct platform_device *, pm_message_t state);
        int (*resume)(struct platform_device *);
        struct device_driver driver;
        const struct platform_device_id *id_table;
    };
    
    struct bus_type platform_bus_type = {
        .name        = "platform",
        .dev_attrs    = platform_dev_attrs,
        .match        = platform_match,
        .uevent        = platform_uevent,
        .pm        = &platform_dev_pm_ops,
    };
    /********************************************************************************/
    
    int driver_register(struct device_driver *drv)
    {
        int ret;
        struct device_driver *other;
    
        BUG_ON(!drv->bus->p);
    
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
            printk(KERN_WARNING "Driver '%s' needs updating - please use "
                "bus_type methods\n", drv->name);
    
        other = driver_find(drv->name, drv->bus);
        if (other) {
            put_driver(other);
            printk(KERN_ERR "Error: Driver '%s' is already registered, "
                "aborting...\n", drv->name);
            return -EBUSY;
        }
    
        ret = bus_add_driver(drv);
        if (ret)
            return ret;
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
            bus_remove_driver(drv);
        return ret;
    }
    
    int bus_add_driver(struct device_driver *drv)
    {
        struct bus_type *bus;
        struct driver_private *priv;
        int error = 0;
    
        bus = bus_get(drv->bus);
        if (!bus)
            return -EINVAL;
    
        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
    
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
            error = -ENOMEM;
            goto out_put_bus;
        }
        klist_init(&priv->klist_devices, NULL, NULL);
        priv->driver = drv;
        drv->p = priv;
        priv->kobj.kset = bus->p->drivers_kset;
        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                         "%s", drv->name);
        if (error)
            goto out_unregister;
    
        if (drv->bus->p->drivers_autoprobe) {
            error = driver_attach(drv);
            if (error)
                goto out_unregister;
        }
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        module_add_driver(drv->owner, drv);
    
        error = driver_create_file(drv, &driver_attr_uevent);
        if (error) {
            printk(KERN_ERR "%s: uevent attr (%s) failed\n",
                __func__, drv->name);
        }
        error = driver_add_attrs(bus, drv);
        if (error) {
            /* How the hell do we get out of this pickle? Give up */
            printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
                __func__, drv->name);
        }
    
        if (!drv->suppress_bind_attrs) {
            error = add_bind_files(drv);
            if (error) {
                /* Ditto */
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
                    __func__, drv->name);
            }
        }
    
        kobject_uevent(&priv->kobj, KOBJ_ADD);
        return 0;
    
    out_unregister:
        kobject_put(&priv->kobj);
        kfree(drv->p);
        drv->p = NULL;
    out_put_bus:
        bus_put(bus);
        return error;
    }
    
    int driver_attach(struct device_driver *drv)
    {
        /*对总线上的每一个设备都调用__driver_attach*/
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
    }
    
    static int __driver_attach(struct device *dev, void *data)
    {
        struct device_driver *drv = data;
    
        /*
         * Lock device and try to bind to it. We drop the error
         * here and always return 0, because we need to keep trying
         * to bind to devices and some drivers will return an error
         * simply if it didn't support the device.
         *
         * driver_probe_device() will spit a warning if there
         * is an error.
         */
    
        if (!driver_match_device(drv, dev))
            return 0;
    
        if (dev->parent)    /* Needed for USB */
            device_lock(dev->parent);
        device_lock(dev);
        if (!dev->driver)
            driver_probe_device(drv, dev);
        device_unlock(dev);
        if (dev->parent)
            device_unlock(dev->parent);
    
        return 0;
    }
    
    static inline int driver_match_device(struct device_driver *drv,
                          struct device *dev)
    {
        /*调用总线的match去匹配设备和驱动*/
        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
    }
    
    int driver_probe_device(struct device_driver *drv, struct device *dev)
    {
        int ret = 0;
    
        if (!device_is_registered(dev))
            return -ENODEV;
    
        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
             drv->bus->name, __func__, dev_name(dev), drv->name);
    
        pm_runtime_get_noresume(dev);
        pm_runtime_barrier(dev);
        ret = really_probe(dev, drv);
        pm_runtime_put_sync(dev);
    
        return ret;
    }
    static int really_probe(struct device *dev, struct device_driver *drv)
    {
        int ret = 0;
    
        atomic_inc(&probe_count);
        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
             drv->bus->name, __func__, drv->name, dev_name(dev));
        WARN_ON(!list_empty(&dev->devres_head));
    
        dev->driver = drv;
        if (driver_sysfs_add(dev)) {
            printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
                __func__, dev_name(dev));
            goto probe_failed;
        }
    /**********************************************************************************/
        if (dev->bus->probe) {/*首先看总线有没有probe函数,若有则调用,而平台总线没有probe*/
            ret = dev->bus->probe(dev);
            if (ret)
                goto probe_failed;
        } else if (drv->probe) {/*然后看驱动有没有probe函数,若有则调用,*/
            ret = drv->probe(dev);
            if (ret)
                goto probe_failed;
        }
    /************************************************************************************/
    
        driver_bound(dev);
        ret = 1;
        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
             drv->bus->name, __func__, dev_name(dev), drv->name);
        goto done;
    
    probe_failed:
        devres_release_all(dev);
        driver_sysfs_remove(dev);
        dev->driver = NULL;
    
        if (ret != -ENODEV && ret != -ENXIO) {
            /* driver matched but the probe failed */
            printk(KERN_WARNING
                   "%s: probe of %s failed with error %d\n",
                   drv->name, dev_name(dev), ret);
        }
        /*
         * Ignore errors returned by ->probe so that the next driver can try
         * its luck.
         */
        ret = 0;
    done:
        atomic_dec(&probe_count);
        wake_up(&probe_waitqueue);
        return ret;
    }
    
    
    /*平台总线的match逻辑*/
    static int platform_match(struct device *dev, struct device_driver *drv)
    {
        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);
    
        /* match against the id table first */
        if (pdrv->id_table)
            return platform_match_id(pdrv->id_table, pdev) != NULL;
    
        /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);/*驱动名字与设备名字要匹配*/
    }

     总结一下:

    platform_driver_register

      driver_register

        bus_add_driver

          driver_attach

            __driver_attach

              driver_probe_device

                really_probe

                   if (dev->bus->probe) {/*首先看总线有没有probe函数,若有则调用,而平台总线没有probe*/
                                                    ret = dev->bus->probe(dev);
                                            if (ret)
                                                    goto probe_failed;
                                             } else if (drv->probe) {/*然后看驱动有没有probe函数,若有则调用,*/
                                                     ret = drv->probe(dev);
                                             if (ret)
                                                    goto probe_failed;
                                            }

  • 相关阅读:
    GitHub设置添加SSH
    Django之Cookie、Session、CSRF、Admin
    Django之强大的Form功能
    Django之Model
    前端:DOM
    前端:JavaScript
    前端:CSS的知识点拾遗
    前端:CSS
    前端:HTML
    Python:线程、进程和协程
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3319131.html
Copyright © 2011-2022 走看看