Linux设备驱动之I2C架构分析【转】

发布时间:2016-12-8 10:16:03 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Linux设备驱动之I2C架构分析【转】",主要涉及到Linux设备驱动之I2C架构分析【转】方面的内容,对于Linux设备驱动之I2C架构分析【转】感兴趣的同学可以参考一下。

一、前言        I2c是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.另外,I2C是一种多主机控制总线.它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须由主机发起才可以.而 I2C 是基于multi master机制.一同总线上可允许多个master.关于I2C协议的知识,这里不再赘述.可自行下载spec阅读即可. 二、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.26.3/drivers/i2c/位置. 三、adapter注册        在 kernel中提供了两个adapter注册接口,分别为        int i2c_add_adapter(struct i2c_adapter *adapter);                                              和        int i2c_add_numbered_adapter(struct i2c_adapter *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;     mutex_init(&adap->bus_lock);     mutex_init(&adap->clist_lock);     INIT_LIST_HEAD(&adap->clients);     mutex_lock(&core_lock);     /* 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 */     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,                 i2c_do_add_adapter); out_unlock:     mutex_unlock(&core_lock);     return res; out_list:     idr_remove(&i2c_adapter_idr, adap->nr);     goto out_unlock; }         首先对adapter和adapter中内嵌的struct device结构进行必须的初始化.之后将adapter内嵌的struct device注册. 在这里注意一下adapter->dev的初始化.它的类别为i2c_adapter_class,如果没有父结点,则将其父结点设为platform_bus.         adapter->dev的名字为i2c + 总线号. 测试一下: [[email protected] i2c]$ cd /sys/class/i2c-adapter/ [[email protected] i2c-adapter]$ ls i2c-0 可以看到,在我的PC上,有一个I2C adapter,看下详细信息: [[email protected] i2c-adapter]$ tree . `-- i2c-0     |-- device -> ../../../devices/pci0000:00/0000:00:1f.3/i2c-0     |-- name     |-- subsystem -> ../../../class/i2c-adapter     `-- uevent 3 directories, 2 files 可以看到,该adapter是一个PCI设备. 继续往下看: 之后,在注释中看到,有两种类型的driver,一种是new-style drivers,另外一种是legacy drivers New-style drivers是在2.6近版的kernel加入的.它们最主要的区别是在adapter和i2c driver的匹配上. 3.1、new-style 形式的adapter注册 对于第一种,也就是new-style drivers,将相关代码再次列出如下:     if (adap->nr < __i2c_first_dynamic_bus_num)         i2c_scan_static_board_info(adap); 如果adap->nr 小于__i2c_first_dynamic_bus_num的话,就会进入到i2c_scan_static_board_info(). 结合我们之前分析的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链表. 跟踪i2c_scan_static_board_info():代码如下: 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;     device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);     client->flags = info->flags & ~I2C_CLIENT_WAKE;     client->addr = info->addr;     client->irq = info->irq;     strlcpy(client->name, info->type, sizeof(client->name));     /* a new style driver may be bound to this device when we     * return from this function, or any later moment (e.g. maybe     * hotplugging will load the driver module).  and the device     * refcount model is the standard driver model one.     */     status = i2c_attach_client(client);     if (status < 0) {         kfree(client);         client = NULL;     }     return client; }         我们又遇到了一个新的结构:struct i2c_client,不要被这个结构吓倒了,其实它就是一个嵌入struct device的I2C设备的封装.它和我们之前遇到的struct usb_device结构的作用是一样的.         首先,在clinet里保存该设备的相关消息.特别的, client->adapter指向了它所在的adapter.特别的,clinet->name为info->name.也是指定好了的.         一切初始化完成之后,便会调用i2c_attach_client( ).看这个函数的字面意思,是将clinet关联起来.到底怎么样关联呢?继续往下看: int i2c_attach_client(struct i2c_client *client) {     struct i2c_adapter *adapter = client->adapter;     int res = 0;     //初始化client内嵌的dev结构     //父结点为所在的adapter,所在bus为i2c_bus_type     client->dev.parent = &client->adapter->dev;     client->dev.bus = &i2c_bus_type;     //如果client已经指定了driver,将driver和内嵌的dev关联起来       if (client->driver)         client->dev.driver = &client->driver->driver;     //指定了driver, 但不是newstyle的     if (client->driver && !is_newstyle_driver(client->driver)) {         client->dev.release = i2c_client_release;         client->dev.uevent_suppress = 1;     } else         client->dev.release = i2c_client_dev_release;     //clinet->dev的名称     snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),         "%d-%04x", i2c_adapter_id(adapter), client->addr);     //将内嵌的dev注册     res = device_register(&client->dev);     if (res)         goto out_err;     //将clinet链到adapter->clients中     mutex_lock(&adapter->clist_lock);     list_add_tail(&client->list, &adapter->clients);     mutex_unlock(&adapter->clist_lock);     dev_dbg(&adapter->dev, "client [%s] registered with bus id %s/n",         client->name, client->dev.bus_id);     //如果adapter->cleinet_reqister存在,就调用它     if (adapter->client_register)  {         if (adapter->client_register(client)) {             dev_dbg(&adapter->dev, "client_register "                 "failed for client [%s] at 0x%02x/n",                 client->name, client->addr);         }     }     return 0; out_err:     dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "         "(%d)/n", client->name, client->addr, res);     return res; }          参考上面添加的注释,应该很容易理解这段代码了,就不加详细分析了.这个函数的名字不是i2c_attach_client()么?怎么没看到它的关系过程呢?         这是因为:在代码中设置了client->dev所在的bus为i2c_bus_type .以为只需要有bus为i2c_bus_type的driver注册,就会产生probe了.这个过程呆后面分析i2c driver的时候再来详细分析. 3.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的注册已经分析完了. 四、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() 六、其它的扩展         分析完adapter和i2c driver的注册之后,好像整个架构也差不多了,其它,扩展的东西还有很多. 我们举一个legacy形式的例子,这个例子是在kernel中随便搜索出来的: 在linux-2.6.26.3/drivers/hwmon/ad7418.c中,初始化函数为: static int __init ad7418_init(void) {     return i2c_add_driver(&ad7418_driver); } i2c_driver ad7418_driver结构如下: static struct i2c_driver ad7418_driver = {     .driver = {         .name  = "ad7418",     },     .attach_adapter = ad7418_attach_adapter,     .detach_client  = ad7418_detach_client, }; 该结构中没有probe()函数,可以断定是一个legacy形式的驱动.这类驱动注册的时候,会调用driver的attach_adapter函数.在这里也就是ad7418_attach_adapter. 这个函数代码如下: static int ad7418_attach_adapter(struct i2c_adapter *adapter) {     if (!(adapter->class & I2C_CLASS_HWMON))         return 0;     return i2c_probe(adapter, &addr_data, ad7418_detect); } 在这里我们又遇到了一个i2c-core中的函数,i2c_probe().在分析这个函数之前,先来看下addr_data是什么? #define I2C_CLIENT_MODULE_PARM(var,desc) /   static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; /   static unsigned int var##_num; /   module_param_array(var, short, &var##_num, 0); /   MODULE_PARM_DESC(var,desc) #define I2C_CLIENT_MODULE_PARM_FORCE(name)              / I2C_CLIENT_MODULE_PARM(force_##name,                    /               "List of adapter,address pairs which are "    /               "unquestionably assumed to contain a `"      /               # name "' chip") #define I2C_CLIENT_INSMOD_COMMON                    / I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan "  /               "additionally");                  / I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to "  /               "scan");                      / static const struct i2c_client_address_data addr_data = {      /     .normal_i2c = normal_i2c,                  /     .probe      = probe,                    /     .ignore    = ignore,                  /     .forces    = forces,                  / } #define I2C_CLIENT_FORCE_TEXT /     "List of adapter,address pairs to boldly assume to be present" 由此可知道,addr_data中的三个成员都是模块参数.在加载模块的时候可以用参数的方式对其赋值.三个模块参数为别为probe,ignore,force.另外需要指出的是normal_i2c不能以模块参数的方式对其赋值,只能在驱动内部静态指定. 从模块参数的模述看来, probe是指"List of adapter,address pairs to scan additionally" Ignore是指"List of adapter,address pairs not to scan " Force是指"List of adapter,address pairs to boldly assume to be present"  事实上,它们里面的数据都是成对出现的.前面一部份表示所在的总线号,ANY_I2C_BUS表示任一总线.后一部份表示设备的地址. addr_data是在 include/linux/i2c.h 中定义的或自己在自己驱动程序中定义的(注意,此处addr_data有两种定义方式)一个i2c_client_address_data结构: 若自己不定义,则用i2c.h中的默认定义。 /* i2c_client_address_data is the struct for holding default client addresses for a driver and for the parameters supplied on the command line */ struct i2c_client_address_data {     unsigned short *normal_i2c;     unsigned short *probe;     unsigned short *ignore;     unsigned short **forces; }; 根据作者自行定义设备地址与否,有两种情形: a. 采用默认定义,一般是不会work,毕竟大多数i2c-core中是不可能提前知道所接设备地址的,这样通过i2c_probe()探测肯定不可能找到,也不可能建立两者之间的联系;况且,i2c_probe()属于i2c-core中的函数,i2c-core中管理着所有注册过的设备和驱动列表,i2c_probe()中也不能随意传入地址,否则容易导致系统混乱或有潜在的风险,所以i2c-core也不允许这么做! b. 作者自行定义地址结构 典型例子如下: 若自行定义,则参考如下: /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,                        I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};/// 实际设备的地址List static unsigned short probe[2] =    {I2C_CLIENT_END, I2C_CLIENT_END}; static unsigned short ignore[2] =     {I2C_CLIENT_END, I2C_CLIENT_END}; static struct i2c_client_address_data addr_data = {     normal_i2c,     probe,     ignore, };         或者根本就不定义完整的i2c_client_address_data结构,只根据需要定义normal_i2c[],probe[],ignore[],forces[][],然后调用i2c_probe(adapter,&addr_data, &my_probe) 即可。         在my_probe()中把实际的地址赋于i2c_client,调用i2c_set_clientdata()设置i2c_client->dev->drv_data,并调用i2c_attach_client(client)向系统注册设备。       最后,i2c_probe()中探测时的地址优先级:forces[X][ X], probe[X ], normal_i2c[ X](其中忽略ignore[]中的项)。 I2c设备在实际使用中比较广泛,sensor,rtc,audio, codec,etc. 因设备复杂性不同,Linux中有些驱动中对地址的定义不在同一文件,这时多数情况都在arch中对设备作为platform_device进行初始化并注册的代码中。 现在可以来跟踪i2c_probe()的代码了.如下: int i2c_probe(struct i2c_adapter *adapter, const struct i2c_client_address_data *address_data, int (*found_proc) (struct  i2c_adapter *, int, int)) {     int i, err;     int adap_id = i2c_adapter_id(adapter);     /* Force entries are done first, and are not affected by ignore       entries */       //先扫描force里面的信息,注意它是一个二级指针.ignore里的信息对它是无效的     if (address_data->forces) {         const unsigned short * const *forces = address_data->forces;//forces为常量指针,所指向的内容不能改变。         int kind;         for (kind = 0; forces[kind]; kind++) {             for (i = 0; forces[kind] != I2C_CLIENT_END;                 i += 2) {                 if (forces[kind] == adap_id                 || forces[kind] == ANY_I2C_BUS) {                     dev_dbg(&adapter->dev, "found force "                         "parameter for adapter %d, "                         "addr 0x%02x, kind %d/n",                         adap_id, forces[kind][i + 1],                         kind);                     err = i2c_probe_address(adapter,                         forces[kind][i + 1],                         kind, found_proc);                     if (err)                         return err;                 }             }         }     }     /* Stop here if we can't use SMBUS_QUICK */     //如果adapter不支持quick.不能够遍历这个adapter上面的设备     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {         if (address_data->probe[0] == I2C_CLIENT_END         && address_data->normal_i2c[0] == I2C_CLIENT_END)             return 0;         dev_warn(&adapter->dev, "SMBus Quick command not supported, "             "can't probe for chips/n");         return -1;     }     /* Probe entries are done second, and are not affected by ignore       entries either */       //遍历probe上面的信息.ignore上的信息也对它是没有影响的      for (i = 0; address_data->probe != I2C_CLIENT_END; i += 2) {         if (address_data->probe == adap_id         || address_data->probe == ANY_I2C_BUS) {             dev_dbg(&adapter->dev, "found probe parameter for "                 "adapter %d, addr 0x%02x/n", adap_id,                 address_data->probe[i + 1]);             err = i2c_probe_address(adapter,                         address_data->probe[i + 1],                         -1, found_proc);             if (err)                 return err;         }     }     /* Normal entries are done last, unless shadowed by an ignore entry */     //最后遍历normal_i2c上面的信息.它上面的信息不能在ignore中.     for (i = 0; address_data->normal_i2c != I2C_CLIENT_END; i += 1) {         int j, ignore;         ignore = 0;         for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;             j += 2) {             if ((address_data->ignore[j] == adap_id ||                 address_data->ignore[j] == ANY_I2C_BUS)             && address_data->ignore[j + 1]                 == address_data->normal_i2c) {                 dev_dbg(&adapter->dev, "found ignore "                     "parameter for adapter %d, "                     "addr 0x%02x/n", adap_id,                     address_data->ignore[j + 1]);                 ignore = 1;                 break;             }         }         if (ignore)             continue;         dev_dbg(&adapter->dev, "found normal entry for adapter %d, "             "addr 0x%02x/n", adap_id,             address_data->normal_i2c);         err = i2c_probe_address(adapter, address_data->normal_i2c,                     -1, found_proc);         if (err)             return err;     }     return 0; }          这段代码很简单,结合代码上面添加的注释应该很好理解.如果匹配成功,则会调用i2c_probe_address ().这个函数代码如下: static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,                 int (*found_proc) (struct i2c_adapter *, int, int)) {     int err;     /* Make sure the address is valid */     //地址小于0x03或者大于0x77都是不合法的     if (addr < 0x03 || addr > 0x77) {         dev_warn(&adapter->dev, "Invalid probe address 0x%02x/n",             addr);         return -EINVAL;     }     /* Skip if already in use */     //adapter上已经有这个设备了     if (i2c_check_addr(adapter, addr))         return 0;     /* Make sure there is something at this address, unless forced */     //如果kind小于0.检查adapter上是否有这个设备     if (kind < 0) {         if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,                   I2C_SMBUS_QUICK, NULL) < 0)             return 0;         /* prevent 24RF08 corruption */         if ((addr & ~0x0f) == 0x50)             i2c_smbus_xfer(adapter, addr, 0, 0, 0,                       I2C_SMBUS_QUICK, NULL);     }     /* Finally call the custom detection function */     //调用回调函数     err = found_proc(adapter, addr, kind);     /* -ENODEV can be returned if there is a chip at the given address       but it isn't supported by this chip driver. We catch it here as       this isn't an error. */     if (err == -ENODEV)         err = 0;     if (err)         dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)/n",             addr, err);     return err; }         首先,对传入的参数进行一系列的合法性检查.另外,如果该adapter上已经有了这个地址的设备了.也会返回失败.所有adapter下面的设备都是以 adapter->dev为父结点的.因此只需要遍历adapter->dev下面的子设备就可以得到当前地址是不是被占用了. 如果kind < 0.还得要adapter检查该总线是否有这个地址的设备.方法是向这个地址发送一个Read的Quick请求.如果该地址有应答,则说明这个地址上有这个设备.另外还有一种情况是在24RF08设备的特例. 如果adapter上确实有这个设备,就会调用驱动调用时的回调函数. 在上面涉及到了IIC的传输方式,有疑问的可以参考intel ICH5手册的有关smbus部份. 跟踪i2c_smbus_xfer().代码如下: s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,                   char read_write, u8 command, int size,                   union i2c_smbus_data * data) {     s32 res;     flags &= I2C_M_TEN | I2C_CLIENT_PEC;     if (adapter->algo->smbus_xfer) {         mutex_lock(&adapter->bus_lock);         res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,                                         command,size,data);         mutex_unlock(&adapter->bus_lock);     } else         res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,                                           command,size,data);     return res; } 如果adapter有smbus_xfer()函数,则直接调用它发送,否则,也就是在adapter不支持smbus协议的情况下,调用i2c_smbus_xfer_emulated()继续处理. 跟进i2c_smbus_xfer_emulated().代码如下: static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,                                   unsigned short flags,                                   char read_write, u8 command, int size,                                   union i2c_smbus_data * data) {     /* So we need to generate a series of msgs. In the case of writing, we       need to use only one message; when reading, we need two. We initialize       most things with sane defaults, to keep the code below somewhat       simpler. */     //写操作只会进行一次交互,而读操作,有时会有两次操作.     //因为有时候读操作要先写command,再从总线上读数据     //在这里为了代码的简洁.使用了两个缓存区,将两种情况统一起来.     unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];     unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];     //一般来说,读操作要交互两次.例外的情况我们在下面会接着分析     int num = read_write == I2C_SMBUS_READ?2:1;     //与设备交互的数据,一般在msg[0]存放写入设备的信息,在msb[1]里存放接收到的     //信息.不过也有例外的     //msg[2]的初始化,默认发送缓存区占一个字节,无接收缓存     struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },                               { addr, flags | I2C_M_RD, 0, msgbuf1 }                             };     int i;     u8 partial_pec = 0;     //将要发送的信息copy到发送缓存区的第一字节     msgbuf0[0] = command;     switch(size) {         //quick类型的,其它并不传输有效数据,只是将地址写到总线上,等待应答即可         //所以将发送缓存区长度置为0 .再根据读/写操作,调整msg[0]的标志位         //这类传输只需要一次总线交互     case I2C_SMBUS_QUICK:         msg[0].len = 0;         /* Special case: The read/write field is used as data */         msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;         num = 1;         break;     case I2C_SMBUS_BYTE:         //BYTE类型指一次写和读只有一个字节.这种情况下,读和写都只会交互一次         //这种类型的读有例外,它读取出来的数据不是放在msg[1]中的,而是存放在msg[0]         if (read_write == I2C_SMBUS_READ) {             /* Special case: only a read! */             msg[0].flags = I2C_M_RD | flags;             num = 1;         }         break;     case I2C_SMBUS_BYTE_DATA:         //Byte_Data是指命令+数据的传输形式.在这种情况下,写只需要一次交互,读却要两次         //第一次将command写到总线上,第二次要转换方向.要将设备地址和read标志写入总线.         //应回答之后再进行read操作         //写操作占两字节,分别是command+data.读操作的有效数据只有一个字节         //交互次数用初始化值就可以了         if (read_write == I2C_SMBUS_READ)             msg[1].len = 1;         else {             msg[0].len = 2;             msgbuf0[1] = data->byte;         }         break;     case I2C_SMBUS_WORD_DATA:         //Word_Data是指命令+双字节的形式.这种情况跟Byte_Data的情况类似         //两者相比只是交互的数据大小不同         if (read_write == I2C_SMBUS_READ)             msg[1].len = 2;         else {             msg[0].len=3;             msgbuf0[1] = data->word & 0xff;             msgbuf0[2] = data->word >> 8;         }         break;     case I2C_SMBUS_PROC_CALL:         //Proc_Call的方式与write 的Word_Data相似,只不过写完Word_Data之后,要等待它的应答         //应该它需要交互两次,一次写一次读         num = 2; /* Special case */         read_write = I2C_SMBUS_READ;         msg[0].len = 3;         msg[1].len = 2;         msgbuf0[1] = data->word & 0xff;         msgbuf0[2] = data->word >> 8;         break;     case I2C_SMBUS_BLOCK_DATA:         //Block_Data:指command+N段数据的情况.         //如果是读操作,它首先要写command到总线,然后再读N段数据.要写的command已经         //放在msg[0]了.现在只需要将msg[1]的标志置I2C_M_RECV_LEN位,msg[1]有效长度为1字节.因为         //adapter驱动会处理好的.现在现在还不知道要传多少段数据.         //对于写的情况:msg[1]照例不需要.将要写的数据全部都放到msb[0]中.相应的也要更新         //msg[0]中的缓存区长度         if (read_write == I2C_SMBUS_READ) {             msg[1].flags |= I2C_M_RECV_LEN;             msg[1].len = 1; /* block length will be added by                       the underlying bus driver */         } else {             //data->block[0]表示后面有多少段数据.总长度要加2是因为command+count+N段数据             msg[0].len = data->block[0] + 2;             if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {                 dev_err(&adapter->dev, "smbus_access called with "                       "invalid block write size (%d)/n",                       data->block[0]);                 return -1;             }             for (i = 1; i < msg[0].len; i++)                 msgbuf0 = data->block[i-1];         }         break;     case I2C_SMBUS_BLOCK_PROC_CALL:         //Proc_Call:表示写完Block_Data之后,要等它的应答消息它和Block_Data相比,只是多了一部份应答而已         num = 2; /* Another special case */         read_write = I2C_SMBUS_READ;         if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {             dev_err(&adapter->dev, "%s called with invalid "                 "block proc call size (%d)/n", __func__,                 data->block[0]);             return -1;         }         msg[0].len = data->block[0] + 2;         for (i = 1; i < msg[0].len; i++)             msgbuf0 = data->block[i-1];         msg[1].flags |= I2C_M_RECV_LEN;         msg[1].len = 1; /* block length will be added by                   the underlying bus driver */         break;     case I2C_SMBUS_I2C_BLOCK_DATA:         //I2c Block_Data与Block_Data相似,只不过read的时候,数据长度是预先定义好了的.另外         //与Block_Data相比,中间不需要传输Count字段.(Count表示数据段数目)         if (read_write == I2C_SMBUS_READ) {             msg[1].len = data->block[0];         } else {             msg[0].len = data->block[0] + 1;             if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {                 dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "                       "invalid block write size (%d)/n",                       data->block[0]);                 return -1;             }             for (i = 1; i <= data->block[0]; i++)                 msgbuf0 = data->block;         }         break;     default:         dev_err(&adapter->dev, "smbus_access called with invalid size (%d)/n",               size);         return -1;     }     //如果启用了PEC.Quick和I2c Block_Data是不支持PEC的     i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK                       && size != I2C_SMBUS_I2C_BLOCK_DATA);     if (i) {         /* Compute PEC if first message is a write */         //如果第一个操作是写操作         if (!(msg[0].flags & I2C_M_RD)) {             //如果只是写操作             if (num == 1) /* Write only */                 //如果只有写操作,写缓存区要扩充一个字节,用来存放计算出来的PEC                 i2c_smbus_add_pec(&msg[0]);             else /* Write followed by read */                 //如果后面还有读操作,先计算前面写部份的PEC(注意这种情况下不需要                 //扩充写缓存区,因为不需要发送PEC.只会接收到PEC)                 partial_pec = i2c_smbus_msg_pec(0, &msg[0]);         }         /* Ask for PEC if last message is a read */         //如果最后一次是读消息.还要接收到来自slave的PEC.所以接收缓存区要扩充一个字节         if (msg[num-1].flags & I2C_M_RD)             msg[num-1].len++;     }     if (i2c_transfer(adapter, msg, num) < 0)         return -1;     /* Check PEC if last message is a read */     //操作完了之后,如果最后一个操作是PEC的读操作.检验后面的PEC是否正确     if (i && (msg[num-1].flags & I2C_M_RD)) {         if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)             return -1;     }     //操作完了,现在可以将数据放到data部份返回了.     if (read_write == I2C_SMBUS_READ)         switch(size) {             case I2C_SMBUS_BYTE:                 data->byte = msgbuf0[0];                 break;             case I2C_SMBUS_BYTE_DATA:                 data->byte = msgbuf1[0];                 break;             case I2C_SMBUS_WORD_DATA:             case I2C_SMBUS_PROC_CALL:                 data->word = msgbuf1[0] | (msgbuf1[1] << 8);                 break;             case I2C_SMBUS_I2C_BLOCK_DATA:                 for (i = 0; i < data->block[0]; i++)                     data->block[i+1] = msgbuf1;                 break;             case I2C_SMBUS_BLOCK_DATA:             case I2C_SMBUS_BLOCK_PROC_CALL:                 for (i = 0; i < msgbuf1[0] + 1; i++)                     data->block = msgbuf1;                 break;         }     return 0; } 在这个函数添上了很详细的注释,配和intel的datasheet,应该很容易看懂.在上面的交互过程中,调用了子函数i2c_transfer().它的代码如下所示: int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) {     int ret;     if (adap->algo->master_xfer) { #ifdef DEBUG         for (ret = 0; ret < num; ret++) {             dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "                 "len=%d%s/n", ret, (msgs[ret].flags & I2C_M_RD)                 ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,                 (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");         } #endif         if (in_atomic() || irqs_disabled()) {             ret = mutex_trylock(&adap->bus_lock);             if (!ret)                 /* I2C activity is ongoing. */                 return -EAGAIN;         } else {             mutex_lock_nested(&adap->bus_lock, adap->level);         }         ret = adap->algo->master_xfer(adap,msgs,num);         mutex_unlock(&adap->bus_lock);         return ret;     } else {         dev_dbg(&adap->dev, "I2C level transfers not supported/n");         return -ENOSYS;     } } 因为在这里的同步用的是mutex.首先判断判断是否充许睡眠,如果不允许,尝试获锁.如果获锁失败,则返回,这样的操作是避免进入睡眠,我们在后面也可以看到,实际的传输工作交给了adap->algo->master_xfer()完成. 在这里,我们终于把i2c_probe_address()的执行分析完了,经过这个分析,我们也知道了数据是怎么样传输的.我们接着 i2c_probe()往下看.如果i2c_probe_address()成功.说明总线上确实有这样的设备.那么就会调用驱动中的回调函数.在 ad7148的驱动中,如下所示: return i2c_probe(adapter, &addr_data, ad7418_detect); 也就是说,要调用的回调函数是ad7418_detect().这个函数中我们只分析和i2c框架相关的部份.代码片段如下所示: static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) {     struct i2c_client *client;     ……     …… client->addr = address;     client->adapter = adapter;     client->driver = &ad7418_driver;     i2c_set_clientdata(client, data);     ……     …… if ((err = i2c_attach_client(client)))         goto exit_free;     ……     …… } 结合上面关于new-style形式的驱动分析.发现这里走的是同一个套路,即初始化了client.然后调用 i2c_attach_client().后面的流程就跟上面分析的一样了.只不过,不相同的是,这里clinet已经指定了驱动为 ad7418_driver.应该在注册clinet->dev之后,就不会走bus->match和bus->probe的流程了. 七: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注册后,就会它的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, }; 7.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()操作到此就完成了. 7.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已经关联到这个地址的设备,就会检查失败. 7.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 设备. 八:小结 在本节中,分析了i2c的框架设计.这个框架大体上沿用了Linux的设备驱动框架,不过之中又做了很多变通.在之后的分析中,会分别举一个adapter和i2c device的例子来详细描述一下有关i2c driver的设计.  本文来自:http://blog.csdn.net/hongjiujing/article/details/4098547

上一篇:Spring事务托管配置及session控制
下一篇:

相关文章

相关评论