zoukankan      html  css  js  c++  java
  • platform_driver_probe 函数解析

    • 结构体列举

        // 几个结构体
        // include/linux/device.h
        struct bus_type {
            const char		*name;                  // "platform" platform_driver_register() define
            struct bus_attribute	*bus_attrs;
            struct device_attribute	*dev_attrs;     // platform_driver_register() define
            struct driver_attribute	*drv_attrs;
            int (*match)(struct device *dev, str    // platform_driver_register() define   uct device_driver *drv);
            int (*uevent)(struct device *dev, str   // platform_driver_register() define   uct kobj_uevent_env *env);
            int (*probe)(struct device *dev);
            int (*remove)(struct device *dev);
            void (*shutdown)(struct device *dev);
            int (*suspend)(struct device *dev, pm_message_t state);
            int (*resume)(struct device *dev);
            const struct dev_pm_ops *pm;        // platform_driver_register() define
            struct iommu_ops *iommu_ops;
            struct subsys_private *p;
        };
    
        // include/linux/device.h
        struct device_driver {
            const char		*name;      //"omap2_mcspi"  ---> omap2_mcspi_driver  define
            struct bus_type		*bus;   // &platform_bus_type  ---> platform_driver_register() define
            struct module		*owner; // THIS_MODULE  ---> omap2_mcspi_driver  define
            const char		*mod_name;  /* used for built-in modules */
            bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */
            const struct of_device_id	*of_match_table;
            int (*probe) (struct device *dev);  // platform_drv_probe  ---> platform_driver_register() define
            int (*remove) (struct device *dev); // platform_drv_remove  ---> platform_driver_register() define
            void (*shutdown) (struct device *dev); //platform_drv_shutdown ---> platform_driver_register() define
            int (*suspend) (struct device *dev, pm_message_t state);
            int (*resume) (struct device *dev);
            const struct attribute_group **groups;
            const struct dev_pm_ops *pm;       // &omap2_mcspi_pm_ops -----> omap2_mcspi_driver  define
            struct driver_private *p;          // priv   bus_add_driver()
        };
    
        // include/linux/platform_device.h
        struct platform_driver {
            int (*probe)(struct platform_device *);  //omap2_mcspi_probe; -----> platform_driver_probe() define
            int (*remove)(struct platform_device *); //__exit_p(omap2_mcspi_remove), ------>  omap2_mcspi_driver  define
            void (*shutdown)(struct platform_device *);
            int (*suspend)(struct platform_device *, pm_message_t state);
            int (*resume)(struct platform_device *);
            struct device_driver driver;      //-----> omap2_mcspi_driver  define
            const struct platform_device_id *id_table;
        };
        extern int platform_driver_probe(struct platform_driver *driver,
                int (*probe)(struct platform_device *));
    
    • 开头,我们要找的是怎么这个 omap2_mcspi_probe 是在哪里被调用

    • 平台驱动probe 总函数

        //  drivers/spi/spi-omap2-mcspi.c
        //  这个是开头
        static struct platform_driver omap2_mcspi_driver = {
            .driver = {
                .name =		"omap2_mcspi",
                .owner =	THIS_MODULE,
                .pm =		&omap2_mcspi_pm_ops
            },
            .remove =	__exit_p(omap2_mcspi_remove),
        };
        platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
    
        //platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
        int __init_or_module platform_driver_probe(struct platform_driver *drv,
                int (*probe)(struct platform_device *))
        {
            int retval, code;
    
            /* make sure driver won't have bind/unbind attributes */
            drv->driver.suppress_bind_attrs = true;
    
            /* temporary section violation during probe() */
            // omap2_mcspi_driver.prove = omap2_mcspi_probe;
            drv->probe = probe;
            // platform_driver_register(&omap2_mcspi_driver)  ---> next define
            retval = code = platform_driver_register(drv);
    
            // ... ...
            return retval;
        }
        EXPORT_SYMBOL_GPL(platform_driver_probe);
    
    • 平台驱动注册

        // drivers/base/platform.c ---> 在下面被引用
        struct bus_type platform_bus_type = {
            .name		= "platform",
            .dev_attrs	= platform_dev_attrs,
            .match		= platform_match,
            .uevent		= platform_uevent,
            .pm		= &platform_dev_pm_ops,
        };
        EXPORT_SYMBOL_GPL(platform_bus_type);
        //platform_driver_register(&omap2_mcspi_driver)
        int platform_driver_register(struct platform_driver *drv)
        {
            drv->driver.bus = &platform_bus_type; //  ---> 在上面被定义
            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;
            // driver_register(&omap2_mcspi_driver->driver);
            return driver_register(&drv->driver);
        }
        EXPORT_SYMBOL_GPL(platform_driver_register);
    
    • 驱动注册

        // drivers/base/driver.c
        // driver_register(&drv->driver);
        // driver_register(&omap2_mcspi_driver->driver);
        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
    ", drv->name);
            // 查找这个驱动是否已经在总线上注册,并增加引用计数,若已经注册,则返回提示信息。
            other = driver_find(drv->name, drv->bus);
            // 如果已经被注册,则返回提示错误并且减少引用计数。
            if (other) {
                put_driver(other);
                printk(KERN_ERR "Error: Driver '%s' is already registered, "
                    "aborting...
    ", drv->name);
                return -EBUSY;
            }
            // 若还没有注册,则在总线上注册该驱动
            // bus_add_driver(&omap2_mcspi_driver->driver)
            ret = bus_add_driver(drv);
            if (ret)
                return ret;
            //
            ret = driver_add_groups(drv, drv->groups);
            if (ret)
                bus_remove_driver(drv);
            return ret;
        }
        EXPORT_SYMBOL_GPL(driver_register);
    
    • 总线添加驱动

        // drivers/base/bus.c
        // int bus_add_driver(&omap2_mcspi_driver->driver)
        int bus_add_driver(struct device_driver *drv)
        {
            struct bus_type *bus;
            struct driver_private *priv;
            int error = 0;
            //用于增加该bus所属的顶层bus的kobject的引用计数,返回的是其所属的顶层bus的指针。
            bus = bus_get(drv->bus); // platform_bus_type
            if (!bus)
                return -EINVAL;
    
            pr_debug("bus: '%s': add driver %s
    ", 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;
    
            //指向顶层的bus的p->drivers_kset
            //设置私有数据的父容器,在这一步中,设置了kset为platform下的drivers_kset结构,也就是drivers呢个目录
            priv->kobj.kset = bus->p->drivers_kset;
            //初始化kobj对象,设置容器操作集并建立相应的目录,这里由于没有提供parent,所以会使用父容器中的kobj为父对象
            error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                             "%s", drv->name);
            if (error)
                goto out_unregister;
    
            //检测所属总线的drivers_autoprobe属性是否为真
            if (drv->bus->p->drivers_autoprobe) {
                // driver_attach(&omap2_mcspi_driver->driver)
                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);
            // 建立uevent属性文件
            error = driver_create_file(drv, &driver_attr_uevent);
            if (error) {
                printk(KERN_ERR "%s: uevent attr (%s) failed
    ",
                    __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
    ",
                    __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
    ",
                        __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;
        }
    
    • 驱动匹配

        // drivers/base/dd.c
        // driver_attach(&omap2_mcspi_driver->driver)
        int driver_attach(struct device_driver *drv)
        {   //    bus_for_each_dev(platform_bus_type, NULL, &omap2_mcspi_driver->driver, __driver_attach);
            return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
        }
        EXPORT_SYMBOL_GPL(driver_attach);
    
        // drivers/base/bus.c
        //  bus_for_each_dev(platform_bus_type, NULL, &omap2_mcspi_driver->driver, __driver_attach);
        int bus_for_each_dev(struct bus_type *bus, struct device *start,
                     void *data, int (*fn)(struct device *, void *))
        {
            struct klist_iter i;
            struct device *dev;
            int error = 0;
    
            if (!bus)
                return -EINVAL;
    
            klist_iter_init_node(&bus->p->klist_devices, &i,
                         (start ? &start->p->knode_bus : NULL));
            while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
                //这里调用的是上面的回调函数 __driver_attach
                // 遍历所有在这个总线上的设备去匹配这个驱动
                //__driver_attach(dev, &omap2_mcspi_driver->driver)
            klist_iter_exit(&i);
            return error;
        }
        EXPORT_SYMBOL_GPL(bus_for_each_dev);
    
    • 驱动配置设备

        // drivers/base/dd.c/
        static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
        {
            return drv->bus->match ? drv->bus->match(dev, drv) : 1;
        }
        //__driver_attach(dev, &omap2_mcspi_driver->driver)
        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); // ----> next ----->
            device_unlock(dev);
            if (dev->parent)
                device_unlock(dev->parent);
    
            return 0;
        }
    
    • 驱动配置设备

        // drivers/base/dd.c
        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
    ",
                 drv->bus->name, __func__, dev_name(dev), drv->name);
    
            pm_runtime_get_noresume(dev);
            pm_runtime_barrier(dev);
            ret = really_probe(dev, drv); // ---> next  really probe
            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
    ",
                 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
    ",
                    __func__, dev_name(dev));
                goto probe_failed;
            }
    
            if (dev->bus->probe) {
                ret = dev->bus->probe(dev);
                if (ret)
                    goto probe_failed;
            } else if (drv->probe) {
                ret = drv->probe(dev);// 这里调用了最前面的omap2_mcspi_probe
                if (ret)
                    goto probe_failed;
            }
    
            driver_bound(dev);
            ret = 1;
            pr_debug("bus: '%s': %s: bound device %s to driver %s
    ",
                 drv->bus->name, __func__, dev_name(dev), drv->name);
            goto done;
        // fail ....-> release all
        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
    ",
                       drv->name, dev_name(dev), ret);
            } else {
                pr_debug("%s: probe of %s rejects match %d
    ",
                       drv->name, dev_name(dev), ret);
            }
            /*
             * Ignore errors returned by ->probe so that the next driver can try
             * its luck.
             */
            ret = 0;
        // success -->exit
        done:
            atomic_dec(&probe_count);
            wake_up(&probe_waitqueue);
            return ret;
        }
    
  • 相关阅读:
    基于Vue.js的表格分页组件
    浅谈Vue.js
    利用js2image把代码压缩成圣诞树
    在AngularJS中的使用Highcharts图表控件
    使用Uploadify(UploadiFive)多文件上传控件遇到的坑
    iOS开源项目周报0323
    安卓开源项目周报0322
    前端开源项目周报0321
    iOS开源项目周报0316
    安卓开源项目周报0315
  • 原文地址:https://www.cnblogs.com/chenfulin5/p/7561407.html
Copyright © 2011-2022 走看看