• 什么?又来看驱动的过程了?是滴,必需滴--I2C设备的注册过程(小白篇)


    为什么写?临时起意。

    写什么?一个Battery Fuel Guage,I2C设备驱动的注册过程。

    遇到一个电池Guage的使用,写一下对I2C设备注册的整个过程。该电池Gauage型号是Maxim
    max1720x/max1721x。

    驱动入口,通常就是probe函数,例如:

    static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id),在这个函数中,进行Guage的初始化/信息获取等操作。

    那问题来了,这个接口的参数怎么来的呢?是啥作用?带着这两个问题,简单跟一内核代码(kernle4.19)。

    接口隶属于下面的结构:

    1. static struct i2c_driver max1720x_i2c_driver = {
    2. .driver = {
    3. .name = "max1720x", //这个名字在驱动和设备的匹配中没有起到作用,仅仅是在设备表示上有意义.
    4. #ifdef CONFIG_OF //OF open firmware.
    5. .of_match_table = of_match_ptr(max1720x_dt_match), // of: open firmware
    6. #endif
    7. .pm = &max1720x_pm_ops,
    8. },
    9. .probe = max1720x_probe,
    10. .remove = max1720x_remove,
    11. .id_table = max1720x_id,
    12. };
    13. /* module_i2c_driver(max1720x_i2c_driver); */

    很清楚能够看到这是一个struct i2c_driver 类型的变量的一个成员函数。那么,这个变量如何使用?可以看到,内核设备驱动的统一入口使用了它。

    1. static int __init max1720x_battery_init(void)
    2. {
    3. int ret;
    4. ret = i2c_add_driver(&max1720x_i2c_driver);
    5. if (ret)
    6. printk(KERN_ERR "Unable to register MAX1720x driver\n");
    7. return ret;
    8. }
    9. module_init(max1720x_battery_init); //这个module_init就是设备驱动的统一入口,后面再细说。反正内核启动之后,会逐一去运行module_init中的函数。

    module_init( xxx ),这个暂且不提,就知道系统内核启动过程中会去调用其参数(接口)就行。

    max1720x_battery_init( xxx )函数提只进行了一项操作--> i2c_add_driver ( xxx );

    好,现在注意力集中了,我们要正式进入linux 内核的世界 了,英踹斯汀。

    i2c_add_driver( xxx )定义在linux/include/i2c.h

    1. /* use a define to avoid include chaining to get THIS_MODULE */
    2. #define i2c_add_driver(driver) \
    3. i2c_register_driver(THIS_MODULE, driver)
    4. //第一句的注释是没看懂没关系,老规矩,先别急,随着眼界的不断提高,慢慢就懂了。
    5. //这是一个宏,对应的定义位于 driver/i2c/i2c-core.c , 我们正式来到了i2c的驱动核心了。
    6. /*
    7. * An i2c_driver is used with one or more i2c_client (device) nodes to access
    8. * i2c slave chips, on a bus instance associated with some i2c_adapter.
    9. * 这个注释能想到,刚开始学习驱动时候,一个驱动对应多个同类型设备的概念。
    10. */
    11. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
    12. {
    13. int res;
    14. /* Can't register until after driver model init */
    15. if (unlikely(WARN_ON(!i2c_bus_type.p)))
    16. return -EAGAIN;
    17. /* add the driver to the list of i2c drivers in the driver core */
    18. driver->driver.owner = owner;
    19. driver->driver.bus = &i2c_bus_type; //先给要注册到内核的驱动对应的总线。显然,这个是i2c总线。物理上,总线是通常直接到CPU,总线上安插着控制器和多个设备。
    20. INIT_LIST_HEAD(&driver->clients);
    21. /* When registration returns, the driver core
    22. * will have called probe() for all matching-but-unbound devices.
    23. */
    24. res = driver_register(&driver->driver); //这里注册的不是i2c_driver 的实例(max1720x_i2c_driver),而是device_driver 的一个变量。这里借用C++面向对象的说法,i2c_driver 继承了struct device_driver。 可以说注册的是父类的一个实例。
    25. if (res)
    26. return res;
    27. pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
    28. /* Walk the adapters that are already present */ //这个操作很神奇,为什么要去遍历控制器adapter?老规矩,先别急,随着眼界的不断提高,慢慢就懂了。目前知道一个事情就行了,bus对附着着的设备一视同仁,都是设备。
    29. i2c_for_each_dev(driver, __process_new_driver);
    30. return 0;
    31. }
    32. EXPORT_SYMBOL(i2c_register_driver); //简单的说,就是这里定义,他出使用。

    重点看下    res = driver_register(&driver->driver); 定义位于:driver/base/driver.c。将要进行一个最基本struct device_driver变量的一个注册操作。

    1. /**
    2. * driver_register - register driver with bus
    3. * @drv: driver to register
    4. *
    5. * We pass off most of the work to the bus_add_driver() call,
    6. * since most of the things we have to do deal with the bus
    7. * structures. //可见这个bus多重要。要想富,先铺路啊。
    8. */
    9. int driver_register(struct device_driver *drv) //驱动模型的最小粒度数据结构
    10. {
    11. int ret;
    12. struct device_driver *other;
    13. BUG_ON(!drv->bus->p); //很好玩的一个调试手段,英踹斯汀
    14. if ((drv->bus->probe && drv->probe) || //drv->probe肯定得是空,为什么?因为父类的方法一定是需要重写的方法。父类只负责内核的设备模型,而具体实现/行为是每个设备自己实现。
    15. (drv->bus->remove && drv->remove) ||
    16. (drv->bus->shutdown && drv->shutdown))
    17. printk(KERN_WARNING "Driver '%s' needs updating - please use "
    18. "bus_type methods\n", drv->name);
    19. other = driver_find(drv->name, drv->bus); //这里要干什么?内核要确认目前的总线上并没有哦注册同名的驱动,如果有重名的,说明有冲突或者说已经注册过驱动了。
    20. if (other) {
    21. printk(KERN_ERR "Error: Driver '%s' is already registered, "
    22. "aborting...\n", drv->name);
    23. return -EBUSY;
    24. }
    25. ret = bus_add_driver(drv); //父类driver负责设备模型,将驱动加入和内核世界。这里会走驱动和设备的匹配过程。暂时按下不表。
    26. if (ret)
    27. return ret;
    28. ret = driver_add_groups(drv, drv->groups); //将device_driver放入到驱动组用于设备模型构建。
    29. if (ret) {
    30. bus_remove_driver(drv);
    31. return ret;
    32. }
    33. kobject_uevent(&drv->p->kobj, KOBJ_ADD); //uevent又是一个英踹斯汀话题,暂时按下不表。
    34. return ret;
    35. }
    36. EXPORT_SYMBOL_GPL(driver_register);

    我们来看看这个功能最复杂的也是最重要的bus_add_driver函数.

    1. /**
    2. * bus_add_driver - Add a driver to the bus.
    3. * @drv: driver.
    4. */
    5. int bus_add_driver(struct device_driver *drv)
    6. {
    7. struct bus_type *bus;
    8. struct driver_private *priv;
    9. int error = 0;
    10. bus = bus_get(drv->bus);
    11. if (!bus)
    12. return -EINVAL;
    13. pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
    14. priv = kzalloc(sizeof(*priv), GFP_KERNEL); //为driver申请私有数据空间
    15. if (!priv) {
    16. error = -ENOMEM;
    17. goto out_put_bus;
    18. }
    19. klist_init(&priv->klist_devices, NULL, NULL);
    20. priv->driver = drv;
    21. drv->p = priv;
    22. priv->kobj.kset = bus->p->drivers_kset;
    23. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
    24. "%s", drv->name); //设备模型
    25. if (error)
    26. goto out_unregister;
    27. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    28. if (drv->bus->p->drivers_autoprobe) { //i2c_bus 中没有初始化p。那如果初始化了,会有什么好处?设计上的优势?
    29. if (driver_allows_async_probing(drv)) {
    30. pr_debug("bus: '%s': probing driver %s asynchronously\n",
    31. drv->bus->name, drv->name);
    32. async_schedule(driver_attach_async, drv);
    33. } else {
    34. error = driver_attach(drv); //驱动和对应的设备进行链接/和对应的bus进行链接
    35. if (error)
    36. goto out_unregister;
    37. }
    38. }
    39. module_add_driver(drv->owner, drv); //
    40. error = driver_create_file(drv, &driver_attr_uevent);
    41. if (error) {
    42. printk(KERN_ERR "%s: uevent attr (%s) failed\n",
    43. __func__, drv->name);
    44. }
    45. error = driver_add_groups(drv, bus->drv_groups);
    46. if (error) {
    47. /* How the hell do we get out of this pickle? Give up */
    48. printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
    49. __func__, drv->name);
    50. }
    51. if (!drv->suppress_bind_attrs) {
    52. error = add_bind_files(drv); //这是在做什么?
    53. if (error) {
    54. /* Ditto */
    55. printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
    56. __func__, drv->name);
    57. }
    58. }
    59. return 0;
    60. out_unregister:
    61. kobject_put(&priv->kobj);
    62. /* drv->p is freed in driver_release() */
    63. drv->p = NULL;
    64. out_put_bus:
    65. bus_put(bus);
    66. return error;
    67. }

     来到,driver_attach(...); driver/base/dd.c

    1. /**
    2. * driver_attach - try to bind driver to devices.
    3. * @drv: driver.
    4. *
    5. * Walk the list of devices that the bus has on it and try to
    6. * match the driver with each one. If driver_probe_device()
    7. * returns 0 and the @dev->driver is set, we've found a
    8. * compatible pair.
    9. * 这段注释很优美,能够知道很多内容。1. 内核中已有设备list。2. 用当前的driver去遍历 3. 遍历bus上已经有的所有设备。
    10. */
    11. int driver_attach(struct device_driver *drv)
    12. {
    13. return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //__driver_attach,作为参数传入的函数调用。优美!
    14. }
    15. EXPORT_SYMBOL_GPL(driver_attach);

    接着是,drivers/base/bus.c

    1. /**
    2. * bus_for_each_dev - device iterator.
    3. * @bus: bus type.
    4. * @start: device to start iterating from.
    5. * @data: data for the callback.
    6. * @fn: function to be called for each device.
    7. *
    8. * Iterate over @bus's list of devices, and call @fn for each, //这个fn厉害了!
    9. * passing it @data. If @start is not NULL, we use that device to
    10. * begin iterating from.
    11. *
    12. * We check the return of @fn each time. If it returns anything
    13. * other than 0, we break out and return that value.
    14. *
    15. * NOTE: The device that returns a non-zero value is not retained
    16. * in any way, nor is its refcount incremented. If the caller needs
    17. * to retain this data, it should do so, and increment the reference
    18. * count in the supplied callback.
    19. */
    20. int bus_for_each_dev(struct bus_type *bus, struct device *start,
    21. void *data, int (*fn)(struct device *, void *))
    22. {
    23. struct klist_iter i; //是不是有点迭代器内味。
    24. struct device *dev;
    25. int error = 0;
    26. if (!bus || !bus->p)
    27. return -EINVAL;
    28. klist_iter_init_node(&bus->p->klist_devices, &i,
    29. (start ? &start->p->knode_bus : NULL));
    30. while ((dev = next_device(&i)) && !error) //原来设备时这么来的,某bus上的设备列表。
    31. error = fn(dev, data); //从上面的调用,可以看到这个data就是struct driver *device_driver, 这里即i2c_driver中的device_driver. fn即__driver_attach()
    32. klist_iter_exit(&i);
    33. return error;
    34. }
    35. EXPORT_SYMBOL_GPL(bus_for_each_dev);

    来了来了,fb( dev, data) -> __driver_attach(dev,drv):

    1. static int __driver_attach(struct device *dev, void *data)
    2. {
    3. struct device_driver *drv = (struct device_driver*) data; //进行强行类型转换。这里的void*是无类型指针,可以指向任何类型,不要尝试进行解引用。英踹斯汀。
    4. /*
    5. * Lock device and try to bind to it. We drop the error
    6. * here and always return 0, because we need to keep trying
    7. * to bind to devices and some drivers will return an error
    8. * simply if it didn't support the device.
    9. * 优美的注释,可以说“清水出芙蓉,天然去雕饰”的注释,为什么返回0,因为我允许你可以范错误。
    10. * driver_probe_device() will spit a warning if there
    11. * is an error.
    12. */
    13. if (!driver_match_device(drv, dev)) //通过idtable中的名称和设备树中的名称进行匹配;确定系统启动过程中,dt正确,对应的设备创建合理,最后bus上挂有对应的设备.
    14. return 0;
    15. if (lock_parent(dev))
    16. device_lock(dev->parent);
    17. device_lock(dev);
    18. if (!dev->driver) //这个必然为空,大家想想为什么?(想想多态性,用父类的指针指向子类时候,对应的接口,我们会根据上下文context,决定要调用子类中的的接口,这里父类的接口一定格式一个虚,需要子类复写。所以,这里的作为父类的device,移动不用实现)
    19. driver_probe_device(drv, dev); //准备调用驱动中的probe接口,进行设备和驱动的绑定,这里对应的就是max1270x电池设备驱动的max1720x_probe。
    20. device_unlock(dev);
    21. if (lock_parent(dev))
    22. device_unlock(dev->parent);
    23. return 0;
    24. }

    最核心的时候到了,driver_probe_device(...);

    1. /**
    2. * driver_probe_device - attempt to bind device & driver together
    3. * @drv: driver to bind a device to
    4. * @dev: device to try to bind to the driver
    5. *
    6. * This function returns -ENODEV if the device is not registered,
    7. * 1 if the device is bound successfully and 0 otherwise.
    8. *
    9. * This function must be called with @dev lock held. When called for a
    10. * USB interface, @dev->parent lock must be held as well.
    11. *
    12. * If the device has a parent, runtime-resume the parent before driver probing.
    13. */
    14. int driver_probe_device(struct device_driver *drv, struct device *dev)
    15. {
    16. int ret = 0;
    17. if (!device_is_registered(dev))
    18. return -ENODEV;
    19. pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
    20. drv->bus->name, __func__, dev_name(dev), drv->name);
    21. if (dev->parent)
    22. pm_runtime_get_sync(dev->parent);
    23. pm_runtime_barrier(dev); //英踹斯汀,暂时按下不表。
    24. ret = really_probe(dev, drv); //这个名称起的真是好,真正的探寻设备。
    25. pm_request_idle(dev);
    26. if (dev->parent)
    27. pm_runtime_put(dev->parent);
    28. return ret;
    29. }

    really_probe(...)//简单的说就是真正的探测设备来了。要用子类/具体类型的设备驱动来绑定对应的dts中定义的设备。

    1. static int really_probe(struct device *dev, struct device_driver *drv)
    2. {
    3. int ret = 0;
    4. int local_trigger_count = atomic_read(&deferred_trigger_count);
    5. atomic_inc(&probe_count);
    6. pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
    7. drv->bus->name, __func__, drv->name, dev_name(dev));
    8. WARN_ON(!list_empty(&dev->devres_head));
    9. dev->driver = drv;
    10. /* If using pinctrl, bind pins now before probing */
    11. ret = pinctrl_bind_pins(dev); //将设备和用pin(GPIO)的情况绑定,英踹斯汀。
    12. if (ret)
    13. goto probe_failed;
    14. if (driver_sysfs_add(dev)) {
    15. printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
    16. __func__, dev_name(dev));
    17. goto probe_failed;
    18. }
    19. if (dev->pm_domain && dev->pm_domain->activate) {
    20. ret = dev->pm_domain->activate(dev); //激活设备,优美。
    21. if (ret)
    22. goto probe_failed;
    23. }
    24. if (dev->bus->probe) { //如果对应的总线上有probe接口,那么调用总线的probe. 最终还是call到了所注册驱动的probe接口.
    25. ret = dev->bus->probe(dev); //这个probe就是i2c_bus 中的probe,我们回到i2c-core.c
    26. if (ret)
    27. goto probe_failed;
    28. } else if (drv->probe) {
    29. ret = drv->probe(dev); //driver都没实现,怎么会有接口实现呢?
    30. if (ret)
    31. goto probe_failed;
    32. }
    33. pinctrl_init_done(dev);
    34. if (dev->pm_domain && dev->pm_domain->sync)
    35. dev->pm_domain->sync(dev);
    36. driver_bound(dev); //新面孔
    37. ret = 1;
    38. pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
    39. drv->bus->name, __func__, dev_name(dev), drv->name);
    40. goto done;
    41. probe_failed:
    42. devres_release_all(dev);
    43. driver_sysfs_remove(dev);
    44. dev->driver = NULL;
    45. dev_set_drvdata(dev, NULL);
    46. if (dev->pm_domain && dev->pm_domain->dismiss)
    47. dev->pm_domain->dismiss(dev);
    48. switch (ret) {
    49. case -EPROBE_DEFER:
    50. /* Driver requested deferred probing */
    51. dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
    52. driver_deferred_probe_add(dev);
    53. /* Did a trigger occur while probing? Need to re-trigger if yes */
    54. if (local_trigger_count != atomic_read(&deferred_trigger_count))
    55. driver_deferred_probe_trigger();
    56. break;
    57. case -ENODEV:
    58. case -ENXIO:
    59. pr_debug("%s: probe of %s rejects match %d\n",
    60. drv->name, dev_name(dev), ret);
    61. break;
    62. default:
    63. /* driver matched but the probe failed */
    64. printk(KERN_WARNING
    65. "%s: probe of %s failed with error %d\n",
    66. drv->name, dev_name(dev), ret);
    67. }
    68. /*
    69. * Ignore errors returned by ->probe so that the next driver can try
    70. * its luck.
    71. */
    72. ret = 0;
    73. done:
    74. atomic_dec(&probe_count);
    75. wake_up(&probe_waitqueue);
    76. return ret;
    77. }

    i2c-core.c中的i2c_bus_type -> probe

    1. static int i2c_device_probe(struct device *dev)
    2. {
    3. struct i2c_client *client = i2c_verify_client(dev); //这个verify是具体如何check的呢?
    4. struct i2c_driver *driver;
    5. int status;
    6. if (!client)
    7. return 0;
    8. if (!client->irq) {
    9. int irq = -ENOENT;
    10. if (dev->of_node) {
    11. irq = of_irq_get_byname(dev->of_node, "irq");
    12. if (irq == -EINVAL || irq == -ENODATA)
    13. irq = of_irq_get(dev->of_node, 0);
    14. } else if (ACPI_COMPANION(dev)) {
    15. irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
    16. }
    17. if (irq == -EPROBE_DEFER)
    18. return irq;
    19. if (irq < 0)
    20. irq = 0;
    21. client->irq = irq;
    22. }
    23. driver = to_i2c_driver(dev->driver); //来了来了, 跑到了最后的i2c_drvier了;具体类型的bus,具体设备类型的驱动。是i2c就是i2c_driver, 完美!
    24. if (!driver->probe || !driver->id_table)
    25. return -ENODEV;
    26. if (client->flags & I2C_CLIENT_WAKE) {
    27. int wakeirq = -ENOENT;
    28. if (dev->of_node) {
    29. wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); //唤醒系统功能?
    30. if (wakeirq == -EPROBE_DEFER)
    31. return wakeirq;
    32. }
    33. device_init_wakeup(&client->dev, true); //注册的设备是否具有唤醒系统功能,英踹斯汀,暂时按下不表。
    34. if (wakeirq > 0 && wakeirq != client->irq)
    35. status = dev_pm_set_dedicated_wake_irq(dev, wakeirq);
    36. else if (client->irq > 0)
    37. status = dev_pm_set_wake_irq(dev, client->irq);
    38. else
    39. status = 0;
    40. if (status)
    41. dev_warn(&client->dev, "failed to set up wakeup irq");
    42. }
    43. dev_dbg(dev, "probe\n");
    44. status = of_clk_set_defaults(dev->of_node, false);
    45. if (status < 0)
    46. goto err_clear_wakeup_irq;
    47. status = dev_pm_domain_attach(&client->dev, true);
    48. if (status == -EPROBE_DEFER)
    49. goto err_clear_wakeup_irq;
    50. status = driver->probe(client, i2c_match_id(driver->id_table, client)); //最终还是call的注册驱动的probe接口进行初始化!来了来了。这里的client,id_table 和具体的电池驱动中的接口对上了:static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id)。
    51. if (status)
    52. goto err_detach_pm_domain;
    53. return 0;
    54. err_detach_pm_domain:
    55. dev_pm_domain_detach(&client->dev, true);
    56. err_clear_wakeup_irq:
    57. dev_pm_clear_wake_irq(&client->dev);
    58. device_init_wakeup(&client->dev, false);
    59. return status;
    60. }

    static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id) 开始运行。到此,从具体i2c设备驱动的注册到内核中的基础代码的执行过程。最终,我们知道了,具体i2c驱动中的probe参数的来历,以后再也不会迷路了。
     

    英踹斯汀

  • 相关阅读:
    Pytorch:张量的索引操作
    全球细胞和组织培养试剂行业调研及趋势分析报告
    人工智能基础_机器学习040_Sigmoid函数详解_单位阶跃函数与对数几率函数_伯努利分布---人工智能工作笔记0080
    ENVI为遥感影像设置空间坐标系的方法
    安卓JNI怎么使用lua库呢,为何这样不行呢
    ce第一次作业
    New Concept English3 Lesson 2. Thirteen equals one【精讲学习笔记】
    Upload-labs(Pass3-4)
    直流有刷电机闭环调速基于STM32F302R8+X-NUCLEO-IHM07M1
    宝塔面板日志和缓存占用磁盘空间很大,如何清理?
  • 原文地址:https://blog.csdn.net/gu_student/article/details/134463885