Linux设备和驱动的匹配过程

时间:2021-11-04 06:19:52

一、bus_type结构体及涉及的函数:
(1)bus_type结构体
struct bus_type {
const char*name;
const char*dev_name;
struct device*dev_root;
struct bus_attribute*bus_attrs;
struct device_attribute*dev_attrs;
struct driver_attribute*drv_attrs;

int (*match)(struct device *dev, struct device_driver *drv);//总线用来匹配设备和驱动的函数
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);

const struct dev_pm_ops *pm;

struct iommu_ops *iommu_ops;

struct subsys_private *p;
struct lock_class_key lock_key;
};

(2)涉及的函数

kernel/linux-3.10/drivers/base/core.c:
device_create()、device_register()、device_add()

kernel/linux-3.10/drivers/base/driver.c:
driver_register()

kernel/linux-3.10/drivers/base/busc:
bus_add_driver()、bus_add_device()、bus_probe_device()

kernel/linux-3.10/drivers/base/dd.c:
device_attach()、__device_attach()、driver_attach()、__driver_attach()

kernel/linux-3.10/drivers/base/base.h:
driver_match_device()、driver_probe_device()

二、注册过程:

Linux设备驱动注册过程如下所示:

xxxx_driver_register()/xxxx_register_driver()--->driver_register()---> bus_add_driver()--->driver_attach()--->__driver_attach()
如:platform_driver_register()、spi_register_driver()、i2c_register_driver()


Linux设备添加过程如下所示:

device_create()/xxxx_device_register()/xxxx_new_device()--->device_register()/xxxx_device_add()/xxxx_add_device()
--->device_add()--->bus_add_device()--->bus_probe_device()---> device_attach()---> __device_attach()
(1)可以直接使用device_create()创建设备,其最终会调用device_register()函数创建设备。
(2)platform_device_register()--->platform_device_add()。
(3)spi_new_device()--->spi_add_device()。 (4)i2c_new_device()--->device_register()。
从设备和驱动的注册过程可以看到两者处理的过程是非常类似,下面分别从最后的函数展开进行深入探索。

三、驱动匹配设备过程
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;

if (!driver_match_device(drv, dev))
return 0;

if (dev->parent) /* Needed for USB */
device_lock(dev->parent);

device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);

if (dev->parent)
device_unlock(dev->parent);

return 0;
}
从上述函数可以看到在driver注册时调用函数driver_match_device进行driver和device的匹配,在匹配之后执行driver的probe函数进行初始化等操作。我们主要看一下driver和device的匹配过程,不再详细研究probe过程。

static inline int driver_match_device(struct device_driver *drv, struct device *dev)
{
return drv->bus->match ?drv->bus->match(dev, drv) : 1;
}

可以看到,会调用相应总线的match函数来匹配driver和device。一般总线的调用过程如下所示,具体可参考每个总线的match函数。

static int xxxx_match(struct device *dev,struct device_driver *drv)
{
struct xxxx_device *xxxdev = to_xxxx_device(dev);
struct xxxx_driver *xxxdrv =to_xxxx_driver(drv);

/* Attempt an OF style match first */
if((of_driver_match_device(dev, drv))
return 1;

/* Then ACPI style match */
if((acpi_driver_match_device(dev, drv))
return 1;

/* Then try to match against the id table*/
if((xxxdrv->id_table)
return xxxx_match_id(xxxdrv->id_table,xxxdev) != NULL;

/* fall-back to driver name match */
return (strcmp([xxxdev/dev]->[name/modalias], drv->name)== 0);
}
可以看到基本上有四种方式,第一种是调用of_driver_match_device()函数;第二种方式是是ACPI系统专用的;第三种通过driver的id_table;第四种比较简单,是通过设备的名称或别名和驱动的名称进行匹配的。

下面详细看一下前第一种和第三种匹配方式:

(1)、of_driver_match_device()

该函数的调用过程如下:
static inline int of_driver_match_device(struct device *dev, const structdevice_driver *drv)
{
returnof_match_device(drv->of_match_table, dev) != NULL;
}

const struct of_device_id *of_match_device(const struct of_device_id *matches, conststruct 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, conststruct device_node *node)
{
const struct of_device_id *match;
unsigned long flags;

raw_spin_lock_irqsave(&devtree_lock,flags);
match = __of_match_node(matches, node);
raw_spin_unlock_irqrestore(&devtree_lock,flags);

return match;
}

static 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;
}
可以发现最终匹配会调用__of_match_node,该函数通过of_device_id的名称、类型和兼容性和设备节点的名称、类型和兼容性进行匹配,其中兼容性具有最高优先级,如果兼容性不匹配,即使前两者匹配,最终结果还是不匹配。另外,of_device_id中一般只有兼容性一项。
在进行兼容性匹配时会调用__of_device_is_compatible(),该函数最终会调用strcasecmp函数,比较兼容性字符串是否一致,一致则匹配。调用过程如下:

static int__of_device_is_compatible(const struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;

cp = __of_get_property(device,"compatible", &cplen);

if (cp == NULL)
return0;

while (cplen > 0) {
if (of_compat_cmp(cp, compat,strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}

return 0;
}

#defineof_compat_cmp(s1, s2, l) strcasecmp((s1), (s2))

(2)、id_table

一般是调用xxxx_match_id函数比较id_table的名称和设备相关属性的名称来进行匹配。xxxx_match_id的一般形式如下,具体可以参考各个总线的函数。
static const struct xxxx_device_id *xxxx_match_id(const struct xxxx_device_id *id,const struct _xxxx *xxxx)
{
while (id->name[0]) {
if (strcmp(xxxx->name, id->name) == 0)
return id;
id++;
}

return NULL;
}

我们可以看一下i2c总线和SPI总线的xxxx_match_id函数,如下所示:
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, conststruct i2c_client *client)
{
while (id->name[0]) {
if (strcmp(client->name, id->name) == 0)
return id;
id++;
}

return NULL;
}
可以看到I2C总线使用i2c_client的名称和id_table的名称来进行匹配。
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, conststruct spi_device *sdev)
{
while (id->name[0]) {
if (!strcmp(sdev->modalias, id->name))
return id;
id++;
}

return NULL;
}

可以看到SPI总线使用SPI设备的别名和id_table的名称来进行匹配。其它总线的匹配方式请自行查看,再此不再赘述。

四、设备匹配驱动过程

static int__device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
if (!driver_match_device(drv, dev))
return 0;
return driver_probe_device(drv, dev);
}

staticinline int driver_match_device(struct device_driver *drv, struct device *dev)
{
return drv->bus->match ?drv->bus->match(dev, drv) : 1;
}
从上述函数可以看到device注册时也是调用函数driver_match_device来进行driver和device的匹配,在匹配之后执行driver的probe函数进行初始化等操作。

由此可见无论是设备还是驱动注册,都是调用总线的match函数进行匹配。在设备和驱动匹配之后,会调用driver_probe_device()函数,调用驱动的probe函数进行初始化工作。

五、常见总线的match函数:

(1)platform_bus:
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);

/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;

/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;

/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;

/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);//比较平台设备的名称和驱动名称进行匹配
}

(2)spi_bus:
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device*spi = to_spi_device(dev);
const struct spi_driver*sdrv = to_spi_driver(drv);

/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;

/* Then try ACPI */
if (acpi_driver_match_device(dev, drv))
return 1;

if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);

return strcmp(spi->modalias, drv->name) == 0;//通过比较spi_device的别名和驱动的名称进行匹配
}

(3)i2c_bus:

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;
}