• 结构体列举

    // 几个结构体
// 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. ZOJ 3203 Light Bulb (三分查找)

    Light Bulb Time Limit: 1 Second      Memory Limit: 32768 KB Compared to wildleopard's wealthiness, h ...

  2. Android HTTP通讯

    这里有一个非常棒的http通讯的总结,我看了以后茅塞顿开. 先贴代码: 01 public class Activity1 extends Activity { 02   03     private ...

  3. Https自签名证书认证及数据请求的封装

    在WWDC 2016开发者大会上,苹果宣布了一个最后期限:到2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能.App Transpor ...

  4. Zookeeper监控工具

    Zookeeper的常用开源监控工具可以参考:http://zqhxuyuan.github.io/2016/12/31/BigData-Monitor-Tool

  5. 打开u盘时提示是否要将其格式化的提示

    早上打开电脑插入U盘后,发现U盘报以下错误:(心中一紧,昨晚写的文档还在其中呢) 修复方法: Win+R 输入cmd 打开 ,执行命令 chkdsk G: /f 其中G为损坏区域所在盘符,即U盘在电脑 ...

  6. 在python3.x下使用如下代码: import cPickle as pk 报错

    在python3.x下使用如下代码: import cPickle as pk会报如下错误:ImportError: No module named 'cPickle' 原因:python2有cPic ...

  7. django 模板使用静态文件

    1.新建项目 2.新建app,并在install_app中添加该app 3.和app文件夹并列新建static.和TEMPLATES  文件夹,分别放静态文件和模板 4.setting.py中设置 T ...

  8. Jeecg 如何执行批量insert或者update操作,高效率

    方法:org.jeecgframework.core.common.dao.jdbc.SimpleJdbcTemplate.batchUpdate     原理: 基于springjdbc封装,批量提 ...

  9. PHP 如何获取二维数组中某个key的集合(高性能查找)

    分享下PHP 获取二维数组中某个key的集合的方法. 具体是这样的,如下一个二维数组,是从库中读取出来的. 代码: $user = array( 0 => array( 'id' => 1 ...

  10. 用js实现预览待上传的本地图片

    js实现预览待上传的本地图片,代码如下: <form name="form5" id="form5" method="post" ac ...