Linux下i2c设备的注册过程

来源:互联网 发布:mac系统怎么保存文件 编辑:程序博客网 时间:2024/05/21 09:20

linux内核下,我们通过i2c_add_driver注册i2c设备,注册成功之后会调用我们写好的probe函数,下面就来梳理一下i2c设备从注册到调用probe的过程。


注册i2c设备,传入的参数是i2c_driver结构体指针。

static int __init bq24296_battery_init(void){int ret;ret = i2c_add_driver(&bq24296_battery_driver);if (ret)printk(KERN_ERR "Unable to register BQ24296 driver\n");return ret;}

/* use a define to avoid include chaining to get THIS_MODULE */#define i2c_add_driver(driver) \i2c_register_driver(THIS_MODULE, driver)

/* * An i2c_driver is used with one or more i2c_client (device) nodes to access * i2c slave chips, on a bus instance associated with some i2c_adapter. */int i2c_register_driver(struct module *owner, struct i2c_driver *driver){int res;/* Can't register until after driver model init */if (unlikely(WARN_ON(!i2c_bus_type.p)))return -EAGAIN;/* add the driver to the list of i2c drivers in the driver core */driver->driver.owner = owner;driver->driver.bus = &i2c_bus_type;/* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */res = driver_register(&driver->driver);//driver_register 将设备驱动添加到总线的设备驱动链表中if (res)return res;/* Drivers should switch to dev_pm_ops instead. */if (driver->suspend)pr_warn("i2c-core: driver [%s] using legacy suspend method\n",driver->driver.name);if (driver->resume)pr_warn("i2c-core: driver [%s] using legacy resume method\n",driver->driver.name);pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);INIT_LIST_HEAD(&driver->clients);/* Walk the adapters that are already present */i2c_for_each_dev(driver, __process_new_driver);return 0;}

/** * driver_register - register driver with bus * @drv: driver to register * * We pass off most of the work to the bus_add_driver() call, * since most of the things we have to do deal with the bus * structures. */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) {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;}kobject_uevent(&drv->p->kobj, KOBJ_ADD);return ret;}

/** * bus_add_driver - Add a driver to the bus. * @drv: driver. */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;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);if (drv->bus->p->drivers_autoprobe) {error = driver_attach(drv);if (error)goto out_unregister;}module_add_driver(drv->owner, drv);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);}}return 0;out_unregister:kobject_put(&priv->kobj);kfree(drv->p);drv->p = NULL;out_put_bus:bus_put(bus);return error;}


/** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the driver with each one.  If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. */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))//判断drv和dev的id是否相同,当id相同时才能继续调用driver_probe_devicereturn 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;}

/** * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held.  When called for a * USB interface, @dev->parent lock must be held as well. */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_barrier(dev);ret = really_probe(dev, drv);pm_request_idle(dev);return ret;}
static int really_probe(struct device *dev, struct device_driver *drv){int ret = 0;int local_trigger_count = atomic_read(&deferred_trigger_count);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 using pinctrl, bind pins now before probing */ret = pinctrl_bind_pins(dev);if (ret)goto probe_failed;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); //调用i2c总线的probe函数 i2c_device_probeif (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;dev_set_drvdata(dev, NULL);if (ret == -EPROBE_DEFER) {/* Driver requested deferred probing */dev_info(dev, "Driver %s requests probe deferral\n", drv->name);driver_deferred_probe_add(dev);/* Did a trigger occur while probing? Need to re-trigger if yes */if (local_trigger_count != atomic_read(&deferred_trigger_count))driver_deferred_probe_trigger();} else 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;done:atomic_dec(&probe_count);wake_up(&probe_waitqueue);return ret;}

static int i2c_device_probe(struct device *dev){struct i2c_client*client = i2c_verify_client(dev);struct i2c_driver*driver;int status;if (!client)return 0;driver = to_i2c_driver(dev->driver);if (!driver->probe || !driver->id_table)return -ENODEV;client->driver = driver;if (!device_can_wakeup(&client->dev))device_init_wakeup(&client->dev,client->flags & I2C_CLIENT_WAKE);dev_dbg(dev, "probe\n");status = driver->probe(client, i2c_match_id(driver->id_table, client));//调用i2c设备驱动的probe函数if (status) {client->driver = NULL;i2c_set_clientdata(client, NULL);}return status;}

以上就是从i2c_add_driver到i2c_driver中注册probe函数被调用的全部流程。



原创粉丝点击