linux powerpc i2c驱动 之 i2c设备层的注册过程
来源:互联网 发布:淘宝出现差评会怎么样 编辑:程序博客网 时间:2024/06/05 11:40
Linux下i2c驱动的加载过程,分为i2c设备层、i2c adapter层与i2c核心层
i2c设备驱动层也就是我们为特定i2c设备编写的驱动,下面是我自己理解的i2c驱动的注册过程
在我们写的i2c设备驱动中,我们会调用i2c_add_driver()开始i2c设备驱动的注册,该函数调用i2c_register_driver完成所有注册操作
- static inline int i2c_add_driver(struct i2c_driver *driver)
- {
- return i2c_register_driver(THIS_MODULE, driver);
- }
i2c_register_driver会调用driver_register() 来将设备驱动添加到总线的设备驱动链表中:
- 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;
- 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 = <strong>driver_register</strong>(&driver->driver);
- if (res)
- return res;
- pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
- INIT_LIST_HEAD(&driver->clients);
- /* Walk the adapters that are already present */
- mutex_lock(&core_lock);
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
- mutex_unlock(&core_lock);
- return 0;
- }
在driver_register中,通过driver_find来判断驱动是否已经注册,然后会调用
bus_add_drive
将设备驱动添加到总线上
- 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 = <strong>bus_add_driver</strong>(drv);
- if (ret)
- return ret;
- ret = driver_add_groups(drv, drv->groups);
- if (ret)
- bus_remove_driver(drv);
- return ret;
- }
在bus_add_driver中初始化priv->klist_devices的值,并将priv赋值给drv->p
通过调用klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers)将驱动信息保存到总线结构中,在此之前将调用driver_attach()
- 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;
- }
- <strong>klist_init</strong>(&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 = <strong>driver_attach</strong>(drv);
- if (error)
- goto out_unregister;
- }
- <strong>klist_add_tail</strong>(&priv->knode_bus, &bus->p->klist_drivers);
- 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);
- }
- }
- kobject_uevent(&priv->kobj, KOBJ_ADD);
- return 0;
- out_unregister:
- kfree(drv->p);
- drv->p = NULL;
- kobject_put(&priv->kobj);
- out_put_bus:
- bus_put(bus);
- return error;
- }
在driver_attach中,通过调用bus_for_each_dev,遍历在总线上挂载的所有设备,并对每个设备(dev)调用__driver_attach()
- int driver_attach(struct device_driver *drv)
- {
- return bus_for_each_dev(drv->bus, NULL, drv, <strong>__driver_attach</strong>);
- }
在__driver_attach里会调用driver_match_device()来判断dev与driv的id是否相同,在i2c驱动里就会调用i2c_bus_type->match程序进行判断,
当id相同时,将会调用driver_probe_device()
- 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 (!<strong>driver_match_device</strong>(drv, dev))
- return 0;
- if (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
- if (!dev->driver)
- <strong>driver_probe_device</strong>(drv, dev);
- up(&dev->sem);
- if (dev->parent)
- up(&dev->parent->sem);
- return 0;
- }
在driver_probe_device(),首先会调用device_is_registered()判断dev是否注册,若没注册则返回;若已经注册,则调用really_probe
- 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 = <strong>really_probe</strong>(dev, drv);
- pm_runtime_put_sync(dev);
- return ret;
- }
在really_probe()里,首先将drv赋值给dev->driver,然后会调用总线的probe函数,在i2c驱动里,
此时将会调用i2c总线的probe函数:i2c_device_probe
- 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)
- {
- //此处调用i2c总线的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;
- }
在i2c_device_probe()里,会根据to_i2c_driver(dev->driver)获取i2c驱动,也就是我们编写的具体的i2c设备驱动的结构体i2c_driver,即
- static struct i2c_driver XXX_driver = {
- .driver = {
- .name = "XXXX_name",
- .owner = THIS_MODULE,
- },
- .probe = XXX_probe,
- .remove = XXX_remove,
- .id_table = XXX_id,
- };
这样就调用了我们驱动的probe()了,这就是我们在驱动里调用i2c_add_driver(),通过driver_register()的一系列调用,最后执行我们所写的probe()
- 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 = <strong>driver->probe</strong>(client, i2c_match_id(driver->id_table, client));//执行我们写的probe函数
- if (status)
- client->driver = NULL;
- return status;
- }
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- Linux PowerPC I2C驱动 之 I2C设备层的注册过程
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- linux powerpc i2c驱动 之 i2c adapter层的注册过程
- linux-i2c驱动 之 i2c设备层的注册过程probe函数如何被调用分析
- linux I2C 驱动之----i2c驱动的注册过程
- Linux下i2c设备的注册过程
- linux powerpc i2c驱动 之 i2c设备…
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux驱动:i2c驱动(三)流程图之注册设备
- linux I2C 驱动之----i2c_client 的注册
- linux I2C 驱动之----i2c_driver的注册 .
- linux I2C 驱动之----i2c_client 的注册
- linux I2C 驱动之----i2c_driver的注册
- 百度2014校招笔试题(二)
- 《#诗盗#~鼠标手》
- XML及HTML文档解析
- 初探使用iOS 7 Sprite Kit与Cocos2d开发游戏的对比
- iOS UIImagePickerController从相册获取图片
- linux powerpc i2c驱动 之 i2c设备层的注册过程
- 《#诗盗#~穿女神装的不一定就是女神,还可能是基友》
- GC日志分析
- 二叉树的非递归遍历
- ubuntu下C++程序编写kate编译执行g++
- hdu4762 Cut the Cake
- AJAX基础
- 字符串扩展
- Java Timer的使用(timer.schedule定时执行)