LINUX裝置驅動i2c架構分析(二)
來源:互聯網
上載者:User
四:i2c driver註冊在分析i2c driver的時候,有必要先分析一下i2c架構的初始化代碼如下:static int __init i2c_init(void){ int retval; retval = bus_register(&i2c_bus_type); if (retval) return retval; retval = class_register(&i2c_adapter_class); if (retval) goto bus_err; retval = i2c_add_driver(&dummy_driver); if (retval) goto class_err; return 0; class_err: class_unregister(&i2c_adapter_class);bus_err: bus_unregister(&i2c_bus_type); return retval;} subsys_initcall(i2c_init); 很明顯,i2c_init()會在系統初始化的時候被調用.在i2c_init中,先註冊了i2c_bus_type的bus,i2c_adapter_class的class.然後再調用i2c_add_driver()註冊了一個i2c driver. I2c_bus_type結構如下:static struct bus_type i2c_bus_type = { .name = "i2c", .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, .uevent = i2c_device_uevent, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .suspend = i2c_device_suspend, .resume = i2c_device_resume,}; 這個結構先放在這裡吧,以後還會用到裡面的資訊的.從上面的初始化函數裡也看到了,註冊i2c driver的介面為i2c_add_driver().代碼如下:static inline int i2c_add_driver(struct i2c_driver *driver){ return i2c_register_driver(THIS_MODULE, driver);}繼續跟蹤:int i2c_register_driver(struct module *owner, struct i2c_driver *driver){ int res; /* new style driver methods can't mix with legacy ones */ //如果是一個newstyle的driver.但又定義了attach_adapter/detach_adapter.非法 if (is_newstyle_driver(driver)) { if (driver->attach_adapter || driver->detach_adapter || driver->detach_client) { printk(KERN_WARNING "i2c-core: driver [%s] is confused/n", driver->driver.name); return -EINVAL; } } /* add the driver to the list of i2c drivers in the driver core */ //關聯到i2c_bus_types driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; /* for new style drivers, when registration returns the driver core * will have called probe() for all matching-but-unbound devices. */ //註冊內嵌的driver res = driver_register(&driver->driver); if (res) return res; mutex_lock(&core_lock); pr_debug("i2c-core: driver [%s] registered/n", driver->driver.name); /* legacy drivers scan i2c busses directly */ //遍曆所有的adapter,對其都調用driver->attach_adapter if (driver->attach_adapter) { struct i2c_adapter *adapter; down(&i2c_adapter_class.sem); list_for_each_entry(adapter, &i2c_adapter_class.devices, dev.node) { driver->attach_adapter(adapter); } up(&i2c_adapter_class.sem); } mutex_unlock(&core_lock); return 0;} 這裡也有兩種形式的區分,對於第一種,只需要將內嵌的driver註冊就可以了,對於legacy的情況,對每一個adapter都調用driver->attach_adapter().現在,我們可以將adapter和i2c driver關聯起來考慮一下了:1:如果是news style形式的,在註冊adapter的時候,將它上面的i2c 裝置轉換成了struct client.struct client->dev->bus又指定了和i2c driver同一個bus.因為,它們可以發生probe.2:如果是legacy形式,就直接找到對應的對象,調用driver->attach_adapter().五: i2c_bus_type的相關操作I2c_bus_type的操作主要存在於new-style形式的驅動中.接下來分析一下對應的probe過程:5.1:match過程分析Match對應的操作函數為i2c_device_match().代碼如下static int i2c_device_match(struct device *dev, struct device_driver *drv){ struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(drv); /* make legacy i2c drivers bypass driver model probing entirely; * such drivers scan each i2c adapter/bus themselves. */ if (!is_newstyle_driver(driver)) return 0; /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0;}如果該驅動不是一個new-style形式的.或者driver沒有定義匹配的id_table.都會匹配失敗.繼續跟蹤進i2c_match_id():static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client){ while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; id++; } return NULL;}由此可見.如果client的名字和driver->id_table[]中的名稱匹配即為成功. 5.2:probe過程分析Probe對應的函數為: i2c_device_probe()static int i2c_device_probe(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(dev->driver); const struct i2c_device_id *id; int status; if (!driver->probe) return -ENODEV; client->driver = driver; dev_dbg(dev, "probe/n"); if (driver->id_table) id = i2c_match_id(driver->id_table, client); else id = NULL; status = driver->probe(client, id); if (status) client->driver = NULL; return status;}這個函數也很簡單,就是將probe流程回溯到i2c driver的probe()