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;
        }
    
  • 相关阅读:
    那些离不开的 Chrome 扩展插件
    Spring Boot 实战 —— 入门
    Maven 学习笔记
    Linux lvm 分区知识笔记
    Linux 双向 SSH 免密登录
    CentOS Yum 源搭建
    Ubuntu 系统学习
    iOS 测试三方 KIF 的那些事
    Swift 网络请求数据与解析
    iOS Plist 文件的 增 删 改
  • 原文地址:https://www.cnblogs.com/chenfulin5/p/7561407.html
Copyright © 2011-2022 走看看