歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> I2C子系統之 adapter driver注冊——I2C_dev_init()

I2C子系統之 adapter driver注冊——I2C_dev_init()

日期:2017/3/1 10:12:43   编辑:Linux編程

i2c的操作在內核中是當做字符設備來操作的,相關初始化在由i2c_dev_init函數來初始化。

並且i2c adapter的驅動通過i2cdev_driver這個通用驅動的attach方法來實現注冊的。

下面具體分析整個過程。

  1. static int __init i2c_dev_init(void)
  2. {
  3. 。。。 。。。
  4. res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
  5. if (res)
  6. goto out;
  7. i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
  8. if (IS_ERR(i2c_dev_class)) {
  9. res = PTR_ERR(i2c_dev_class);
  10. goto out_unreg_chrdev;
  11. }
  12. res = i2c_add_driver(&i2cdev_driver);
  13. 。。。 。。。
  14. }

函數首先調用register_chardev函數向內核注冊主備號為I2C_MAJOR、操作集為i2cdev_fops的字符設備。

register_chrdev函數最終會向系統注冊主設備為I2C_MAJOR,此設備號為0~255的設備。這表示系統最多可以容納256個i2c adapter,adapter的字符操作方法i2cdev_fops如下:

  1. static const struct file_operations i2cdev_fops = {
  2. .owner = THIS_MODULE,
  3. .llseek = no_llseek,
  4. .read = i2cdev_read,
  5. .write = i2cdev_write,
  6. .unlocked_ioctl = i2cdev_ioctl,
  7. .open = i2cdev_open,
  8. .release = i2cdev_release,
  9. };

當read()、write()、open()、close()、ioctl()等系統調用發生時就會調用到這些函數。

但是i2cdev_fops其實是通用的的操作,應為不同的adapter對應的操作方法肯定有區別所以這裡的fops只是具體adapter操作方法的一層外殼,具體稍後分析。

字符設備注冊完畢後通過class_create()函數初始化一個類i2c_dev_class,這個類稍後需要使用,用於在/dev/i2c-0下自動創建設備,後面分析。

類初始化完畢後,然後調用函數i2c_add_driver函數注冊i2c driver。這裡所說的i2c其實對應的是系統中所有的i2c類設備。

通過i2c driver中的attach_adapter方法來實現將adapter和對應的驅動綁定。

  1. static struct i2c_driver i2cdev_driver = {
  2. .driver = {
  3. .name = "dev_driver",
  4. },
  5. .attach_adapter = i2cdev_attach_adapter,
  6. .detach_adapter = i2cdev_detach_adapter,
  7. };
此處注意attach_adapter這個方法,/dev目錄下的設備創建是在通過執行此函數實現的。

下面具體分析i2c_add_driver注冊i2cdev_driver的過程

2.i2c_add_driver

i2c_add_driver函數只是對i2c_register_driver做了簡單的封裝,下面直接分析i2c_register_driver

  1. int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
  2. {
  3. int res;
  4. /* Can't register until after driver model init */
  5. if (unlikely(WARN_ON(!i2c_bus_type.p))){
  6. printk("Can't register until after driver model init\n");
  7. return -EAGAIN;
  8. }
  9. /* add the driver to the list of i2c drivers in the driver core */
  10. driver->driver.owner = owner;
  11. driver->driver.bus = &i2c_bus_type;
  12. /* When registration returns, the driver core
  13. * will have called probe() for all matching-but-unbound devices.
  14. */
  15. res = driver_register(&driver->driver);
  16. if (res)
  17. return res;
  18. pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
  19. INIT_LIST_HEAD(&driver->clients);
  20. /* Walk the adapters that are already present */
  21. mutex_lock(&core_lock);
  22. bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
  23. mutex_unlock(&core_lock);
  24. return 0;
  25. }

函數通過

  1. driver->driver.bus = &i2c_bus_type;
可見此驅動通過函數driver_register()之後 同樣會被注冊到了i2c總線上。

值得一提的是此處i2cdev_driver中的attach_adapter的執行機會很大,通過bus_for_each_dev()函數

  1. bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
會嘗試和i2c總線上所有的dev進行一次匹配,只要獲取的dev為adapter時,就可執行後續操作。

此處的bus_for_each_dev函數主要功能就是循環查詢一遍i2c總線上所有的dev,包括adapter device和client device。

然後依次將dev和driver作為__process_new_driver的參數並執行__process_new_driver函數,但是只有adapter device

才會執行後續的操作,否則返回繼續輪詢i2c總線上的dev。

  1. static int __process_new_driver(struct device *dev, void *data)
  2. {
  3. if (dev->type != &i2c_adapter_type)
  4. return 0;
  5. return i2c_do_add_adapter(data, to_i2c_adapter(dev));
  6. }
可以發現__process_new_driver函數首先判斷的是dev的類型,假如是adapter類型才會繼續執行後面的代碼,假如不是則立即返回繼續摘取下個dev然後循環執行__process_new_driver。因為對我們來說,我們只需要注冊adapter的驅動就可以了,i2c的所有操作是通過主機來完成的,從機只是被動接受。由於之前已經通過i2cadd_numbered_adapter()注冊過adapter到總線i2c_bus_type,所以此處有機會執行後面的i2c_do_add_adapter函數。
  1. static int i2c_do_add_adapter(struct i2c_driver *driver,
  2. struct i2c_adapter *adap)
  3. {
  4. /* Detect supported devices on that bus, and instantiate them */
  5. i2c_detect(adap, driver);
  6. /* Let legacy drivers scan this bus for matching devices */
  7. if (driver->attach_adapter) {
  8. /* We ignore the return code; if it fails, too bad */
  9. driver->attach_adapter(adap);
  10. }
  11. return 0;
  12. }
可以發現在i2c_do_add_adapter函數主要執行的是i2c_dectect和driver->attach_adapter。

由於此處驅動並未初始化driver->detect,所以i2c_detect函數未執行有效操作就會退出。

接著通過傳統方式執行driver->attach_adapter方法。

  1. tatic int i2cdev_attach_adapter(struct i2c_adapter *adap)
  2. {
  3. struct i2c_dev *i2c_dev;
  4. int res;
  5. i2c_dev = get_free_i2c_dev(adap);
  6. if (IS_ERR(i2c_dev))
  7. return PTR_ERR(i2c_dev);
  8. /* register this i2c device with the driver core */
  9. i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
  10. MKDEV(I2C_MAJOR, adap->nr), NULL,
  11. "i2c-%d", adap->nr);
  12. if (IS_ERR(i2c_dev->dev)) {
  13. res = PTR_ERR(i2c_dev->dev);
  14. goto error;
  15. }
  16. res = device_create_file(i2c_dev->dev, &dev_attr_name);
  17. if (res)
  18. goto error_destroy;
  19. pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
  20. adap->name, adap->nr);
  21. return 0;
  22. error_destroy:
  23. device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
  24. error:
  25. return_i2c_dev(i2c_dev);
  26. return res;
  27. }

可見attach_adapter函數的作用就是調用device_create()函數 通過之前class_create的類信息在/dev下自動創建設備文件。

並且此設備的設備號是由固定的主設備號I2C_MAJOR 和 從設備號組成的,從設備號取的就是adapter的nr,此處為0。

並且可以推斷出系統最多可以容納0~255 總共256個i2c adapter。

到此i2c部分的初始化就完成了,可以通過read write來操作設備了。

補充:上面說的新方法好像在驅動裡面就會detect client,然後把所有檢測到的client放到一條鏈表裡。

相關閱讀:

I2C子系統之at24c02讀寫測試 http://www.linuxidc.com/Linux/2012-08/68256.htm
I2C子系統之ioctl() http://www.linuxidc.com/Linux/2012-08/68257.htm
I2C子系統之at24c02簡介 http://www.linuxidc.com/Linux/2012-08/68258.htm
I2C子系統之總結 http://www.linuxidc.com/Linux/2012-08/68259.htm
I2C子系統之內核中I2C子系統的結構 http://www.linuxidc.com/Linux/2012-08/68260.htm
I2C子系統之I2C bus初始化——I2C_init() http://www.linuxidc.com/Linux/2012-08/68261.htm
I2C子系統之platfor_device初始化——smdk2440_machine_init() http://www.linuxidc.com/Linux/2012-08/68262.htm
I2C子系統之platform_driver初始化——I2C_adap_s3c_init() http://www.linuxidc.com/Linux/2012-08/68263.htm
I2C子系統之I2C總線時鐘頻率設置 http://www.linuxidc.com/Linux/2012-08/68264.htm
I2C子系統之adapter device和client device注冊——I2C_add_number_adapter() http://www.linuxidc.com/Linux/2012-08/68265.htm
I2C子系統之__I2C_first_dynamic_bus_num變量的相關分析 http://www.linuxidc.com/Linux/2012-08/68266.htm
I2C子系統之 adapter driver注冊——I2C_dev_init() http://www.linuxidc.com/Linux/2012-08/68267.htm
I2C子系統之write() http://www.linuxidc.com/Linux/2012-08/68268.htm

Copyright © Linux教程網 All Rights Reserved