Chinaunix首页 | 论坛 | 博客
  • 博客访问: 35988
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 12
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-09 08:56
文章分类
文章存档

2014年(8)

我的朋友

分类: LINUX

2014-01-09 09:34:39

原文地址:I2C设备驱动注册 作者:apple_guet

四、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()
阅读(1537) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~