驱动和设备匹配过程常用数据结构:
struct of_device_id{
charname[32];
char type[32];
char compatible[128];
#ifdef __KERNEL__
void*data;
#else
kernel_ulong_t data;
#endif
};
struct platform_device_id {
char name[PLATFORM_NAME_SIZE];
kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t))));
};
向系统添加平台驱动或添加设备时会调用平台总线platform_bus_type中的platform_match函数来匹配平台驱动和平台设备。
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);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* 首先尝试通过驱动里定义了of_device_id项,则通过这一项来比对;**/
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* 如果在平台驱动中定义了id_table项,则通过对比id_table来判断*/
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* 通过对比平台设备名字和平台驱动名字来判断*/
return (strcmp(pdev->name, drv->name) == 0);
}
由platform_match可以看出,驱动和设备是否匹配可以通过三种方式来进行判断,首先是通过of_device_id结构:
static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
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;
}
如果driver中定义了of_device_id,则通过driver中的of_device_id和device中的device_node内容进行匹配判断,匹配工作由of_match_node来完成,该函数会遍历of_device_id列表,查找是否有成员与device_node相匹配,具体由matches的name,type和compatioble来进行对比,如果找到则返回相应的表项,否则返回null.如果没有定义of_device_id,device_node或不能找到对应的匹配项,则通过第二种方式platform_device_id来进行对比匹配,通过platform_match_id来完成:
static const struct platform_device_id *platform_match_id( const struct platform_device_id *id, struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
platform_match_id函数遍历platfrom_device_id列表,通过比对平台设备与id的name来确定是否有匹配项,如果找到匹配的,则返回对应的id项,否则返回null。如果没有定义platform_device_id或没有找到匹配项,则通过第三种方式进行匹配,第三种方式通过比对平台设备和平台驱动的名字,如果相等,则匹配成功,否则失败。