Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2278711
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-05-12 15:58:02

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控制器。
阅读(1011) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~