linux中i2c驱动的匹配方式
内核中匹配方式有3种:
OF style match
ACPI style match
i2c id table
先直接上代码: linux 3.10.y分支:
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
1.OF style match
这是所有驱动通用的匹配方式:对应的是驱动和器件需要做,如下器件结构体的匹配. 最常见的是:compatible部分字符.
这在dts, dsti中最常见.
struct of_device_id
{
char name[32];
char type[32];
char compatible[128];
const void *data;
};
算法中,只要name或type,或compatible任一个匹配,就算匹配.
对应的driver需要有of_device_id, deice需要有of_node才能用这种方式.
匹配算法原代码如下面
struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev)
{
if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node)
{
if (!matches)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= node->name && !strcmp(matches->name, node->name);
if (matches->type[0])
match &= node->type && !strcmp(matches->type, node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(node, matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
对于ACPI主要是用于电源管理的,需要有acpi对应的id,
struct acpi_device_id {
__u8 id[ACPI_ID_LEN];
kernel_ulong_t driver_data;
};
这个平时用得少,略过.
再看一下i2c专有的: id_table方式:
这种式方式:需要驱动有:id_table,
struct i2c_device_id {
char name[I2C_NAME_SIZE];
kernel_ulong_t driver_data; /* Data private to the driver */
};
匹配方式如下: 只需要匹配name 就行. id表中的driver_data,只是一个参数,不参与匹配,只是在驱动运行时会使用.
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;
}