歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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

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.   
  8.     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");  
  9.     if (IS_ERR(i2c_dev_class)) {  
  10.         res = PTR_ERR(i2c_dev_class);  
  11.         goto out_unreg_chrdev;  
  12.     }  
  13.   
  14.     res = i2c_add_driver(&i2cdev_driver);  
  15.         。。。 。。。  
  16. }  

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

函數通過

  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.   
  7.     /* Let legacy drivers scan this bus for matching devices */  
  8.     if (driver->attach_adapter) {  
  9.         /* We ignore the return code; if it fails, too bad */  
  10.         driver->attach_adapter(adap);  
  11.     }  
  12.     return 0;  
  13. }  
可以發現在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.   
  6.     i2c_dev = get_free_i2c_dev(adap);  
  7.     if (IS_ERR(i2c_dev))  
  8.         return PTR_ERR(i2c_dev);  
  9.   
  10.     /* register this i2c device with the driver core */  
  11.     i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,  
  12.                      MKDEV(I2C_MAJOR, adap->nr), NULL,  
  13.                      "i2c-%d", adap->nr);  
  14.     if (IS_ERR(i2c_dev->dev)) {  
  15.         res = PTR_ERR(i2c_dev->dev);  
  16.         goto error;  
  17.     }  
  18.     res = device_create_file(i2c_dev->dev, &dev_attr_name);  
  19.     if (res)  
  20.         goto error_destroy;  
  21.   
  22.     pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",  
  23.          adap->name, adap->nr);  
  24.     return 0;  
  25. error_destroy:  
  26.     device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));  
  27. error:  
  28.     return_i2c_dev(i2c_dev);  
  29.     return res;  
  30. }  

可見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