Chinaunix首页 | 论坛 | 博客
  • 博客访问: 180899
  • 博文数量: 43
  • 博客积分: 1428
  • 博客等级: 上尉
  • 技术积分: 410
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-02 09:33
文章分类

全部博文(43)

文章存档

2014年(3)

2013年(3)

2011年(1)

2010年(36)

分类: LINUX

2010-09-06 09:10:31

1#    I2C架构概述
在linux中,I2C驱动架构如下所示:

 
如上图所示,每一条I2C对应一个adapter.在kernel中,每一个adapter提供了一个描述的结构(struct i2c_adapter),也定义了adapter支持的操作(struct i2c_adapter).再通过i2c core层将i2c设备与i2c adapter关联起来.
这个图只是提供了一个大概的框架.在下面的代码分析中,从下至上的来分析这个框架图.以下的代码分析是基于linux 2.6.26.分析的代码基本位于: linux-2.6.34/drivers/i2c/位置.

2:adapter注册
在kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号.这个总线号的PCI中的总线号不同.它和硬件无关,只是软件上便于区分而已.
对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败.
分别来看一下这两个函数的代码:
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_lock);
    /* "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_lock);
 
    if (res < 0) {
        if (res == -EAGAIN)
            goto retry;
        return res;
    }
 
    adapter->nr = id;
    return i2c_register_adapter(adapter);
}

在这里涉及到一个idr结构.idr结构本来是为了配合page cache中的radix tree而设计的.在这里我们只需要知道,它是一种高效的搜索树,且这个树预先存放了一些内存.避免在内存不够的时候出现问题.所在,在往idr中插入结构的时候,首先要调用idr_pre_get()为它预留足够的空闲内存,然后再调用idr_get_new_above()将结构插入idr中,该函数以参数的形式返回一个id.以后凭这个id就可以在idr中找到相对应的结构了.对这个数据结构操作不太理解的可以查阅本站<< linux文件系统之文件的读写>>中有关radix tree的分析.
注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)的参数的含义,它是将adapter结构插入到i2c_adapter_idr中,存放位置的id必须要大于或者等于__i2c_first_dynamic_bus_num,
然后将对应的id号存放在adapter->nr中.调用i2c_register_adapter(adapter)对这个adapter进行进一步注册.
 
看一下另外一人注册函数: i2c_add_numbered_adapter( ),如下所示:
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
    int id;
    int status;
 
    if (adap->nr & ~MAX_ID_MASK)
        return -EINVAL;
 
retry:
    if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
        return -ENOMEM;
 
    mutex_lock(&core_lock);
    /* "above" here means "above or equal to", sigh;
     * we need the "equal to" result to force the result
     */
    status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
    if (status == 0 && id != adap->nr) {
        status = -EBUSY;
        idr_remove(&i2c_adapter_idr, id);
    }
    mutex_unlock(&core_lock);
    if (status == -EAGAIN)
        goto retry;
 
    if (status == 0)
        status = i2c_register_adapter(adap);
    return status;
}
对比一下就知道差别了,在这里它已经指定好了adapter->nr了.如果分配的id不和指定的相等,便返回错误.
 
过一步跟踪i2c_register_adapter().代码如下:
static int i2c_register_adapter(struct i2c_adapter *adap)
{
     int res = 0, dummy;
     /* Can't register until after driver model init */
     if (unlikely(WARN_ON(!i2c_bus_type.p))) {
      res = -EAGAIN;
      goto out_list;
     }
     rt_mutex_init(&adap->bus_lock);
     INIT_LIST_HEAD(&adap->userspace_clients);
     /* Set default timeout to 1 second if not already set */
     if (adap->timeout == 0)
          adap->timeout = HZ;
     dev_set_name(&adap->dev, "i2c-%d", adap->nr);
     adap->dev.bus = &i2c_bus_type;
     adap->dev.type = &i2c_adapter_type;
     res = device_register(&adap->dev);
     if (res)
          goto out_list;
     dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
    #ifdef CONFIG_I2C_COMPAT
     res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, adap->dev.parent);
     if (res)
          dev_warn(&adap->dev, "Failed to create compatibility class link\n");
    #endif
     /* create pre-declared device nodes for new-style drivers  */
     if (adap->nr < __i2c_first_dynamic_bus_num)
          i2c_scan_static_board_info(adap);
     /* Notify drivers */
     mutex_lock(&core_lock);
     /* let legacy drivers scan this bus for matching devices */
     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
     mutex_unlock(&core_lock);
     return 0;
    out_list:
         mutex_lock(&core_lock);
         idr_remove(&i2c_adapter_idr, adap->nr);
         mutex_unlock(&core_lock);
        return res;
 }
首先对adapter内嵌的struct device注册. 在这里注意一下adapter->dev的初始化.它的类别为i2c_adapter_class,如果没有父结点,则将其父结点设为platform_bus.adapter->dev的名字为i2c + 总线号. adapter是一个PCI设备.
在注释中看到,有两种类型的driver,一种是new-style drivers,另外一种是legacy drivers. New-style drivers是在2.6近版的kernel加入的.它们最主要的区别是在adapter和i2c driver的匹配上.
 
2.1: new-style 形式的adapter注册
对于第一种,也就是new-style drivers,将相关代码再次列出如下:
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);
adapter的两种注册分式: i2c_add_adapter()所分得的总线号肯会不会小于__i2c_first_dynamic_bus_num.只有i2c_add_numbered_adapter()才有可能满足: (adap->nr < __i2c_first_dynamic_bus_num)
而且必须要调用i2c_register_board_info()将板子上的I2C设备信息预先注册时,才会更改__i2c_first_dynamic_bus_num的值.在x86上没有使用i2c_register_board_info()的.因此,x86平台上的分析可以忽略掉new-style driver的方式.不过,还是详细分析这种情况下.
首先看一下i2c_register_board_info(),如下:
int __init
i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
{
    int status;
    mutex_lock(&__i2c_board_lock);
    /* dynamic bus numbers will be assigned after the last static one */
    if (busnum >= __i2c_first_dynamic_bus_num)
        __i2c_first_dynamic_bus_num = busnum + 1;
 
    for (status = 0; len; len--, info++) {
        struct i2c_devinfo  *devinfo;
        devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
        if (!devinfo) {
            pr_debug("i2c-core: can't register boardinfo!\n");
            status = -ENOMEM;
            break;
        }
        devinfo->busnum = busnum;
        devinfo->board_info = *info;
        list_add_tail(&devinfo->list, &__i2c_board_list);
    }
    mutex_unlock(&__i2c_board_lock);
    return status;
}
这个函数比较简单, struct i2c_board_info用来表示I2C设备的一些情况,比如所在的总线.名称,地址,中断号等.最后,这些信息会被存放到__i2c_board_list链表.
 
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo  *devinfo;
    mutex_lock(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr  && !i2c_new_device(adapter, &devinfo->board_info))
            printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",i2c_adapter_id(adapter), devinfo->board_info.addr);
    }
    mutex_unlock(&__i2c_board_lock);
}
该函数遍历挂在__i2c_board_list链表上面的i2c设备的信息,也就是我们在启动的时候指出的i2c设备的信息.
如果指定设备是位于adapter所在的I2C总线上,那么,就调用i2c_new_device().代码如下:
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
     struct i2c_client *client;
     int   status;
     client = kzalloc(sizeof *client, GFP_KERNEL);
     if (!client)
          return NULL;
     client->adapter = adap;
     client->dev.platform_data = info->platform_data;
     if (info->archdata)
          client->dev.archdata = *info->archdata;
     client->flags = info->flags;
     client->addr = info->addr;
     client->irq = info->irq;
     strlcpy(client->name, info->type, sizeof(client->name));
     /* Check for address business */
     status = i2c_check_addr(adap, client->addr);
     if (status)
          goto out_err;
     client->dev.parent = &client->adapter->dev;
     client->dev.bus = &i2c_bus_type;
     client->dev.type = &i2c_client_type;
     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr);
     status = device_register(&client->dev);
     if (status)
          goto out_err;
     dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev));
     return client;
out_err:
     dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
  "(%d)\n", client->name, client->addr, status);
     kfree(client);
     return NULL;
}
首先,在clinet里保存该设备的相关消息.特别的, client->adapter指向了它所在的adapter.
特别的,clinet->name为info->name.也是指定好了的.

2.2: legacy形式的adapter注册
Legacy形式的adapter注册代码片段如下:
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 i2c_do_add_adapter);
这段代码遍历挂在i2c_bus_type上的驱动,然后对每一个驱动和adapter调用i2c_do_add_adapter().
代码如下:
static int i2c_do_add_adapter(struct device_driver *d, void *data)
{
    struct i2c_driver *driver = to_i2c_driver(d);
    struct i2c_adapter *adap = data;
    if (driver->attach_adapter) {
        /* We ignore the return code; if it fails, too bad */
        driver->attach_adapter(adap);
    }
    return 0;
}
该函数很简单,就是调用driver的attach_adapter()接口. 到此为止,adapter的注册已经分析完了.
 
3: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 */
    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_lock);
 
    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;
        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().
 
4: i2c_bus_type的相关操作
I2c_bus_type的操作主要存在于new-style形式的驱动中.接下来分析一下对应的probe过程:
4.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[]中的名称匹配即为成功.
 
4.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->drive= 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() .
 
5:i2c dev节点操作
现在来分析上面架构图中的i2c-dev.c中的部份.这个部份为用户空间提供了操作adapter的接口.这部份代码其实对应就晃一个模块.它的初始化函数为:
module_init(i2c_dev_init);
i2c_dev_init()代码如下:
static int __init i2c_dev_init(void)
{
    int res;
    printk(KERN_INFO "i2c /dev entries driver\n");
    res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
    if (res)
        goto out;
    i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
    if (IS_ERR(i2c_dev_class))
        goto out_unreg_chrdev;
    res = i2c_add_driver(&i2cdev_driver);
    if (res)
        goto out_unreg_class;
    return 0;
out_unreg_class:
    class_destroy(i2c_dev_class);
out_unreg_chrdev:
    unregister_chrdev(I2C_MAJOR, "i2c");
out:
    printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
    return res;
}
首先为主册了一个主设备号为I2C_MAJOR(89),操作集为i2cdev_fops的字符设备.然后注册了一个名为”i2c-dev”的class.之后再注册了一个i2c的driver.如下所示:
res = i2c_add_driver(&i2cdev_driver);
    if (res)
        goto out_unreg_class;
i2cdev_driver定义如下:
static struct i2c_driver i2cdev_driver = {
    .driver = {
        .name   = "dev_driver",
    },
    .id     = I2C_DRIVERID_I2CDEV,
    .attach_adapter = i2cdev_attach_adapter,
    .detach_adapter = i2cdev_detach_adapter,
    .detach_client  = i2cdev_detach_client,
};
也就是说,当它注册或者有新的adapter注册后,就会调用 i2cdev_attach_adapter()函数.该函数代码如下:
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
    struct i2c_dev *i2c_dev;
    int res;
    i2c_dev = get_free_i2c_dev(adap);
    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,
                     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;
}
这个函数也很简单,首先调用get_free_i2c_dev()分配并初始化了一个struct i2c_dev结构,使i2c_dev->adap指向操作的adapter.之后,该i2c_dev会被链入链表i2c_dev_list中.再分别以I2C_MAJOR, adap->nr为主次设备号创建了一个device.如果此时系统配置了udev或者是hotplug,那么就么在/dev下自动创建相关的设备节点了.
刚才我们说过,所有主设备号为I2C_MAJOR的设备节点的操作函数是i2cdev_fops.它的定义如下所示:
static const struct file_operations i2cdev_fops = {
    .owner      = THIS_MODULE,
    .llseek     = no_llseek,
    .read       = i2cdev_read,
    .write      = i2cdev_write,
    .ioctl      = i2cdev_ioctl,
    .open       = i2cdev_open,
    .release    = i2cdev_release,
};
 
5.1:i2c dev的open操作
Open操作对应的函数为i2cdev_open().代码如下:
 
 static int i2cdev_open(struct inode *inode, struct file *file)
{
    unsigned int minor = iminor(inode);
    struct i2c_client *client;
    struct i2c_adapter *adap;
    struct i2c_dev *i2c_dev;
 
    //以次设备号从i2c_dev_list链表中取得i2c_dev
    i2c_dev = i2c_dev_get_by_minor(minor);
    if (!i2c_dev)
        return -ENODEV;
 
    //以apapter的总线号从i2c_adapter_idr中找到adapter
    adap = i2c_get_adapter(i2c_dev->adap->nr);
    if (!adap)
        return -ENODEV;
 
    /* This creates an anonymous i2c_client, which may later be
     * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
     *
     * This client is ** NEVER REGISTERED ** with the driver model
     * or I2C core code!!  It just holds private copies of addressing
     * information and maybe a PEC flag.
     */
     //分配并初始化一个i2c_client结构
    client = kzalloc(sizeof(*client), GFP_KERNEL);
    if (!client) {
        i2c_put_adapter(adap);
        return -ENOMEM;
    }
    snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
    client->driver = &i2cdev_driver;
 
    //clinet->adapter指向操作的adapter
    client->adapter = adap;
    //关联到file
    file->private_data = client;
 
    return 0;
}
注意这里分配并初始化了一个struct i2c_client结构.但是没有注册这个clinet.此外,这个函数中还有一个比较奇怪的操作.不是在前面已经将i2c_dev->adap指向要操作的adapter么?为什么还要以adapter->nr为关键字从i2c_adapter_idr去找这个操作的adapter呢?注意了,调用i2c_get_adapter()从总线号nr找到操作的adapter的时候,还会增加module的引用计数.这样可以防止模块意外被释放掉.也许有人会有这样的疑问,那 i2c_dev->adap->nr操作,如果i2c_dev->adap被释放掉的话,不是一样会引起系统崩溃么?这里因为,在i2cdev_attach_adapter()间接的增加了一次adapter的一次引用计数.如下:
tatic int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
......
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
                     MKDEV(I2C_MAJOR, adap->nr),
                     "i2c-%d", adap->nr);
......
}
看到了么,i2c_dev内嵌的device是以adap->dev为父结点,在device_create()中会增次adap->dev的一次引用计数.
好了,open()操作到此就完成了.
 
5.2:read操作
Read操作对应的操作函数如下示:
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
                            loff_t *offset)
{
    char *tmp;
    int ret;
    struct i2c_client *client = (struct i2c_client *)file->private_data;
    if (count > 8192)
        count = 8192;
    tmp = kmalloc(count,GFP_KERNEL);
    if (tmp==NULL)
        return -ENOMEM;
    pr_debug("i2c-dev: i2c-%d reading %zd bytes.\n",
        iminor(file->f_path.dentry->d_inode), count);
    ret = i2c_master_recv(client,tmp,count);
    if (ret >= 0)
        ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
    kfree(tmp);
    return ret;
}
首先从file结构中取得struct i2c_clinet.然后在kernel同分配相同长度的缓存区,随之调用i2c_master_recv()从设备中读取数据.再将读取出来的数据copy到用户空间中.
I2c_master_recv()代码如下:
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
{
    struct i2c_adapter *adap=client->adapter;
    struct i2c_msg msg;
    int ret;
 
    msg.addr = client->addr;
    msg.flags = client->flags & I2C_M_TEN;
    msg.flags |= I2C_M_RD;
    msg.len = count;
    msg.buf = buf;
    ret = i2c_transfer(adap, &msg, 1);
    /* If everything went ok (i.e. 1 msg transmitted), return #bytes
       transmitted, else error code. */
    return (ret == 1) ? count : ret;
}
看完前面的代码之后,这个函数应该很简单了,就是为读操作初始化了一个i2c_msg.然后调用i2c_tanster().代码中的client->flags & I2C_M_TEN表示adapter是否采用10位寻址的方式.在这里就不再详细分析了.
另外,有人可能看出了一个问题.这里clinet->addr是从哪来的呢?对,在read之前应该还要有一步操作来设置clinet->addr的值.这个过程是ioctl的操作.ioctl可以设置PEC标志,重试次数,超时时间,和发送接收数据等,我们在这里只看一下clinet->addr的设置.代码片段如下示:
static int i2cdev_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
{
    ......
    ......
    switch ( cmd ) {
    case I2C_SLAVE:
    case I2C_SLAVE_FORCE:
        /* NOTE:  devices set up to work with "new style" drivers
         * can't use I2C_SLAVE, even when the device node is not
         * bound to a driver.  Only I2C_SLAVE_FORCE will work.
         *
         * Setting the PEC flag here won't affect kernel drivers,
         * which will be using the i2c_client node registered with
         * the driver model core.  Likewise, when that client has
         * the PEC flag already set, the i2c-dev driver won't see
         * (or use) this setting.
         */
        if ((arg > 0x3ff) ||
            (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
            return -EINVAL;
        if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
            return -EBUSY;
        /* REVISIT: address could become busy later */
        client->addr = arg;
        return 0;
    ......
    ......
}
由此可见,调用I2C_SLAVE或者I2C_SLAVE_FORCE的Ioctl就会设置clinet->addr.另外,注释中也说得很清楚了.如果是I2C_SLAVE的话,还会调用其所长i2cdev_check_addr().进行地址检查,如果adapter已经关联到这个地址的设备,就会检查失败.
 
5.2:write操作
Write操作如下所示:
static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t count,
                             loff_t *offset)
{
    int ret;
    char *tmp;
    struct i2c_client *client = (struct i2c_client *)file->private_data;
 
    if (count > 8192)
        count = 8192;
 
    tmp = kmalloc(count,GFP_KERNEL);
    if (tmp==NULL)
        return -ENOMEM;
    if (copy_from_user(tmp,buf,count)) {
        kfree(tmp);
        return -EFAULT;
    }
 
    pr_debug("i2c-dev: i2c-%d writing %zd bytes.\n",
        iminor(file->f_path.dentry->d_inode), count);
 
    ret = i2c_master_send(client,tmp,count);
    kfree(tmp);
    return ret;
}
该操作比较简单,就是将用户空间的数据发送到i2c 设备. 
阅读(1258) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-09-08 10:04:35

Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com