i2c驱动之难点释疑

来源:互联网 发布:java项目开发硬件环境 编辑:程序博客网 时间:2024/05/17 02:37

一、关于匹配

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中。


0 0