• 结构体列举

    // 几个结构体
// 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\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;
}
// 若还没有注册,则在总线上注册该驱动
// 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\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; //指向顶层的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\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;
}
  • 驱动匹配

    // 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\n",
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\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) {
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\n",
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\n",
drv->name, dev_name(dev), ret);
} else {
pr_debug("%s: probe of %s rejects match %d\n",
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;
}

platform_driver_probe 函数解析的更多相关文章

  1. [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")

    javascript eval函数解析json数据时为什么 加上圆括号?为什么要 eval这里要添加 “("("+data+")");//”呢?   原因在于: ...

  2. PHP json_decode 函数解析 json 结果为 NULL 的解决方法

    在做网站 CMS 模块时,对于模块内容 content 字段,保存的是 json 格式的字符串,所以在后台进行模块内容的编辑操作 ( 取出保存的数据 ) 时,需要用到 json_decode() 函数 ...

  3. Matlab中bsxfun和unique函数解析

    一.问题来源 来自于一份LSH代码,记录下来. 二.函数解析 2.1 bsxfun bsxfun是一个matlab自版本R2007a来就提供的一个函数,作用是”applies an element-b ...

  4. socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

    Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...

  5. sigaction函数解析

    http://blog.chinaunix.net/uid-1877180-id-3011232.html sigaction函数解析  sigaction函数的功能是检查或修改与指定信号相关联的处理 ...

  6. driver_register()函数解析

    driver_register()函数解析 /** * driver_register - register driver with bus * @drv: driver to register *  ...

  7. async函数解析

    转载请注明出处:async函数解析 async函数是基于Generator函数实现的,也就是说是Generator函数的语法糖.在之前的文章有介绍过Generator函数语法和异步应用,如果对其不了解 ...

  8. tf.train.shuffle_batch函数解析

    tf.train.shuffle_batch (tensor_list, batch_size, capacity, min_after_dequeue, num_threads=1, seed=No ...

  9. oracle中next_day()、last_day()函数解析

    oracle中next_day()函数解析 Sql代码 当前系统时间的下一星期一的时间select   next_day(sysdate,1) from dual NEXT_DAY(date,char ...

随机推荐

  1. Matlab调用返回游标的存储过程的分析和处理

    2.Matlab调用Oracl带游标参数输出的存储过程 笔者也是将工作之中遇到的问题进行了搜集与整理,才完成该文的编写,希望能帮助到有需要的朋友. 2.1.PLSQL中的存储过程 PROCEDURE ...

  2. HDUOJ-----I NEED A OFFER!

    I NEED A OFFER! Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Tot ...

  3. Python的 numpy中 numpy.ravel() 和numpy.flatten()的区别和使用

    两者所要实现的功能是一致的(将多维数组降为一维), 两者的区别在于返回拷贝(copy)还是返回视图(view),numpy.flatten() 返回一份拷贝,对拷贝所做的修改不会影响(reflects ...

  4. 【LeetCode】154. Find Minimum in Rotated Sorted Array II (3 solutions)

    Find Minimum in Rotated Sorted Array II Follow up for "Find Minimum in Rotated Sorted Array&quo ...

  5. struts2 xml配置文件配置传参数

    传参方式 重定向 第一方式: <action name="search" method="search"            class="c ...

  6. Android学习系列(3)--App自动更新之自定义进度视图和内部存储

    友好的视觉感知和稳定的不出错表现,来自于我们追求美感和考虑的全面性,博客园从技术的角度,一直我都很欣赏.这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用. 这 ...

  7. PopupWindow的简单使用(结合RecyclerView)

    Android弹窗: 在Android中弹出式菜单(以下称弹窗)是使用十分广泛一种菜单呈现的方式,弹窗为用户交互提供了便利.关于弹窗的实现大致有以下两种方式AlertDialog和PopupWindo ...

  8. 图解最小生成树 - 普里姆(Prim)算法

    我们在图的定义中说过,带有权值的图就是网结构.一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边.所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接 ...

  9. Unix环境高级编程(七)fork函数总结

    在Unix/Linux中用fork函数创建一个新的进程.进程是由当前已有进程调用fork函数创建,分叉的进程叫子进程,创建者叫父进程.该函数的特点是调用一次,返回两次,一次是在父进程,一次是在子进程. ...

  10. OpenCV245之SURF源代码分析

    一.fastHessianDetector函数分析 (1)參数 const Mat& sum                积分图片 const Mat& mask_sum vecto ...