代码改变世界

probe()函数调用的时间

2013-07-29 20:51  keepgood  阅读(1606)  评论(0)    收藏  举报

probe函数的调用有二种情况:

1 先注册设备,后注册驱动

2 先注册驱动,后注册设备(支持热插拔的设备可采用此方式)

一 设备和驱动的注册流程

1 设备注册过程:
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}

int platform_device_add(struct platform_device *pdev)
{
...
pdev->dev.bus = &platform_bus_type;
...
ret = device_add(&pdev->dev);
...
}

int device_add(struct device *dev)
{
...
error = bus_add_device(dev);
...
bus_probe_device(dev);
...
}

void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
int ret;

if (bus && bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}
}

int device_attach(struct device *dev)
{
int ret = 0;

device_lock(dev);
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
pm_runtime_get_noresume(dev);
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}

static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;

if (!driver_match_device(drv, dev))
return 0;

return driver_probe_device(drv, dev);
}
接下来进入"driver_probe_device",见第3部分

 

2 驱动注册过程:

static struct platform_driver ***_driver = {
.probe = ***_probe,
.driver = {
.owner = THIS_MODULE,
.pm = ***_DEV_PM_OPS_PTR,
.name = DRIVER_NAME,
},
};


static int __init ***_init(void)
{
return platform_driver_register(&***_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;

return driver_register(&drv->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;
}

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_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)
{
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;
}

接下来进入第3部分

3  驱动和设备的公共部分
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) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->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;
}

 

二 probe函数的调用
1 先注册设备,后注册驱动

此种方式最为常见,大多数设备先于驱动注册到内核中。
在内核源代码中,platform 设备的初始化(注册)用arch_initcall()调用,它的initcall 的level为3;而驱动的注册用module_init()调用,即device_initcall(),它的initcall 的level为6。kernel 初始化时(kernel_init@init/main.c),按照内核链接文件中(arm系统:kernel/arch/arm/vmlinux.lds)的__initcall_start段的序列依次执行,这样level小的初始化函数先于level大的初始化函数被调用。
所以platform设备先被注册,驱动加载时会调用驱动程序中的probe(),扫描系统中已注册的设备,找到匹配设备后将驱动和设备绑定。

当设备注册的时候,由于驱动尚未注册,所以执行"__device_attach"时直接返回,未执行"driver_probe_device"进行设备和驱动匹配;后来驱动注册的时候,执行"__driver_attach"的时候设备已经注册,所以进入"driver_probe_device",接着进入"driver_probe_device",然后"really_probe"完成设备和驱动的绑定。

2 先注册驱动,再注册设备
当驱动注册的时候,由于设备尚未注册,所以执行"__driver_attach"时直接返回,未执行"driver_probe_device"进行驱动和设备匹配;后来设备注册的时候,执行"__device_attach"的时候驱动已经注册,所以进入"driver_probe_device",接着进入"driver_probe_device",然后"really_probe"完成驱动和设备的绑定。