i2c匯流排上,適配器、設備驅動註冊


1、匯流排適配器註冊:
1)drivers/i2c/i2c-core.c
int i2c_add_adapter(struct i2c_adapter *adapter)
{
        int     id, res = 0;

retry:
        if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
                return -ENOMEM;

        mutex_lock(&core_lists);
        /* "above" here means "above or equal to", sigh */
        res = idr_get_new_above(&i2c_adapter_idr, adapter,
                                __i2c_first_dynamic_bus_num, &id);
        mutex_unlock(&core_lists);

        if (res < 0) {
                if (res == -EAGAIN)
                        goto retry;
                return res;
        }

        adapter->nr = id;            //
使用動態的匯流排號來標識匯流排適配器。
        return i2c_register_adapter(adapter);
}
EXPORT_SYMBOL(i2c_add_adapter);

2)drivers/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
        int res = 0;
        struct list_head   *item;
        struct i2c_driver  *driver;

        mutex_init(&adap->bus_lock);        //
初始化匯流排訪問控制變數(匯流排上資料傳輸時使用)
        mutex_init(&adap->clist_lock);        //
初始化用戶端訪問控制變數(操作用戶端結構時使用)
        INIT_LIST_HEAD(&adap->clients);        //
初始化用戶端鏈表頭

        mutex_lock(&core_lists);
        list_add_tail(&adap->list, &adapters);    //
添加到匯流排適配器鏈表中

        /* Add the adapter to the driver core.
         * If the parent pointer is not set up,
         * we add this adapter to the host bus.
         */
        if (adap->dev.parent == NULL) {       
                adap->dev.parent = &platform_bus;
                pr_debug("I2C adapter driver [%s] forgot to specify "
                         "physical device\n", adap->name);
        }
        sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
        adap->dev.release = &i2c_adapter_dev_release;
        adap->dev.class = &i2c_adapter_class;
        res = device_register(&adap->dev);    //
註冊設備
        if (res)
                goto out_list;

        dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

        /* create pre-declared device nodes for new-style drivers */
        if (adap->nr < __i2c_first_dynamic_bus_num)
                i2c_scan_static_board_info(adap);

        /* let legacy drivers scan this bus for matching devices */
        list_for_each(item,&drivers) {        //
搜索匯流排上的所有設備驅動,通過調用其attach_adapter介面函數,查找匹配的設備。
                driver = list_entry(item, struct i2c_driver, list);
                if (driver->attach_adapter)
                        /* We ignore the return code; if it fails, too bad */
                        driver->attach_adapter(adap);
        }

out_unlock:
        mutex_unlock(&core_lists);
        return res;

out_list:
        list_del(&adap->list);
        idr_remove(&i2c_adapter_idr, adap->nr);
        goto out_unlock;
}

2
、設備驅動註冊(i2c-dev.c為例)
1)include/linux/i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
        return i2c_register_driver(THIS_MODULE, driver);
}

2)drivers/i2c/i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
        int res;

        /* new style driver methods can't mix with legacy ones */
        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 */
        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.
         */
        res = driver_register(&driver->driver);    //
註冊驅動
        if (res)
                return res;

        mutex_lock(&core_lists);

        list_add_tail(&driver->list,&drivers);    //
添加到設備驅動鏈表中
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

        /* legacy drivers scan i2c busses directly */
        if (driver->attach_adapter) {
                struct i2c_adapter *adapter;

                list_for_each_entry(adapter, &adapters, list) {    //
讓設備驅動搜索匹配的適配器(通過調用其attach_adapter介面)
                        driver->attach_adapter(adapter);
                }
        }

        mutex_unlock(&core_lists);
        return 0;
}
EXPORT_SYMBOL(i2c_register_driver);

3)drivers/i2c/i2c-dev.c
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
        struct i2c_dev *i2c_dev;
        int res;

        i2c_dev = get_free_i2c_dev(adap);    //
創建並初始化i2c_dev結構
        if (IS_ERR(i2c_dev))
                return PTR_ERR(i2c_dev);

        /* register this i2c device with the driver core */
        i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,        //
注意,這裏使用的次設備號為adap->nr,便於以後獲取adap結構。
                                     MKDEV(I2C_MAJOR, adap->nr),
                                     "i2c-%d", adap->nr);
        if (IS_ERR(i2c_dev->dev)) {
                res = PTR_ERR(i2c_dev->dev);
                goto error;
        }
        res = device_create_file(i2c_dev->dev, &dev_attr_name);        //
創建設備檔
        if (res)
                goto error_destroy;

        pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
                 adap->name, adap->nr);
        return 0;
error_destroy:
        device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
        return_i2c_dev(i2c_dev);
        return res;
}

總結:
   
一個適配器對應一個i2c控制器。

全站熱搜

立你斯 發表在 痞客邦 留言(0) 人氣()