i2c驱动之难点释疑 .

来源:互联网 发布:淘宝上买到假酒怎么办 编辑:程序博客网 时间:2024/05/16 08:47
一、关于匹配
i2c_client->dev和i2c_driver->driver的总线类型都是i2c_bus_type。
 i2c_adapter->dev的总线类型并不是i2c_bus_type。
在注册后设备与驱动匹配,是i2c_client->dev和i2c_driver->driver的匹配。
i2c_client的建立都是依赖于 "new style" driversi2c_driver->driver携带的地址信息。

i2c_adapter->dev与i2c_driver->driver并没有匹配关系,而是
i2c_adapter->class与i2c_driver->class的匹配,它们支持的设备类型的匹配。

 

二、两类i2c_driver的区别

"new style" driver: 
     is_newstyle_driver(d)     ((d)->probe || (d)->remove || (d)->detect)
 "legacy"driver:
     driver->detach_adapter || driver->detach_client


  这两类驱动的区别就是他们所拥有的函数不一样。
  不能出现这两类驱动的混合体,即兼有这两类驱动的标志函数的驱动。

"new style" driver是携带地址信息,并将这些地址转换成具体的设备client注册

到内核,这些设备client的name在该驱动的id_table中。

函数driver->detect便是填充结构体i2c_board_info,用i2c_board_info去初始化

client,驱动id_table中的name就是i2c_board_info->type带入client的。

该驱动与设备就是根据这个name相匹配的,匹配后调用函数probe执行一些初始化或是设备探测。

当然该驱动也是可以不携带地址信息的,而是注册后与内核中已存在的client匹配执行probe()。

 "legacy"driver是不携带地址信息的,它的主要任务是调用函数driver->detach_adapter为新加入

的适配器,或是与之匹配的适配器创建一个可依附的设备节点,或者是做其他初始化工作。

 

 

三、两个重要函数的区别

当一个新的驱动加入内核时,会在类型为i2c_adapter_class的适配器中找与之匹配的,

并将驱动支持的设备插入适配器。

class_for_each_device(&i2c_adapter_class, NULL, driver,
         __attach_adapter);

当一个新的适配器加入内核时,会在总线类型为i2c_bus_type的驱动中找与之匹配的,

并将驱动支持的设备插入新加入的这个适配器。
bus_for_each_drv(&i2c_bus_type, NULL, adap,
     i2c_do_add_adapter);

函数class_for_each_device和bus_for_each_drv调用了两个相似的函数,

__attach_adapter和i2c_do_add_adapter。
 这两函数的对比如下:
 前者是在新的驱动加入内核时调用函数class_for_each_device时调用的函数。
 函数class_for_each_device是在类i2c_adapter_class中找一个适配器设备
 与新驱动匹配。该函数变化的是设备不变的是加入的新的驱动(void *data)
 
 后者是在新的适配器加入内核时调用函数 bus_for_each_drv时调用的函数。
 函数bus_for_each_drv是在总线类型为i2c_bus_type的驱动中找到一个驱动
 与新加入的适配器匹配。该函数变化的是驱动,不变的是新加入的适配器(void *data)。
 
 相同点都是执行函数i2c_detect和函数driver->attach_adapter。
 其实在bus_for_each_drv和class_for_each_device并不执行匹配的操作。
 只是简单的取出所有的驱动或是适配器,执行函数i2c_detect和attach_adapter。
 真正的匹配是在函数i2c_detect和attach_adapter中进行的。
 函数i2c_detect中会去判断驱动支持的设备类和适配器所支持的设备类是否匹配。
 函数driver->attach_adapter中会判断adapter->nr是不是自己需要处理的
 适配器,或者是是不是该适配器已被处理过了。
 当然函数i2c_detect和函数driver->attach_adapter是绝不会同时执行的。
 因为函数i2c_detect的执行需要用到函数driver->detect而该函数是"new style" drivers

的标志函数。而函数driver->attach_adapter是 "legacy" drivers的标志函数。i2c_driver中是

没有兼有这两种驱动的混合体驱动的。

 

四、 不同驱动一般不会对同一个适配器两次执行函数attach_adapter

每一个函数driver->attach_adapter的操作都跟adapter->nr有关,在这些函数
中都会对adapter->nr进行判断,所以driver->attach_adapter并不是,一个驱动
的函数attach_adapter对每一个适配器都会成功执行。


比如在驱动i2cdev_driver中函数attach_adapter的执行会创建一个设备节点,
但是对同一个适配器两次执行函数attach_adapter就不会产生两个设备节点,
因为产生设备节点的次设备号是由adapter->nr来决定的。内核是不会允许
对同一个设备号注册两次的。

 

五、关于地址管理结构体i2c_client_address_data

i2c.h中初始化了一个默认的结构体addr_data :

static const struct i2c_client_address_data addr_data = {  \
 .normal_i2c = normal_i2c,     \
 .probe  = probe,     \
 .ignore  = ignore,     \
 .forces  = forces,     \
}

这个结构体与地址探测函数

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)

紧密相关。

forces:

它存储的地址有如下特点:
跳过适配器支持的设备类和驱动支持的设备类匹配判断
 if (!(adapter->class & driver->class))
  goto exit_free;
也就是说即使不匹配,这些设备地址只要满足某些条件也要将其插入适配器。

probe:

probe支持的设备地址不受ignore(忽略某些地址)的影响.

normal_i2c:

normal_i2c[i]中的地址就要受到ignore的影响.

驱动中所支持的地址一般都存于address_data->normal_i2c中。