linux通过platform_match()匹配platform总线上的device和driver
\kernel\msm-4.9\drivers\base\platform.c定义了platform_match()的实现,先来看定义
/**
* platform_match - bind platform device to platform driver.
* @dev: device.
* @drv: driver.
*
* Platform device IDs are assumed to be encoded like this:
* "<name><instance>", where <name> is a short description of the type of
* device, like "pci" or "floppy", and <instance> is the enumerated
* instance of the device, like '0' or '42'. Driver IDs are simply
* "<name>". So, extract the <name> from the platform_device structure,
* and compare it against the name of the driver. Return whether they match
* or not.
*/
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);
/* Attempt an OF style match first */
//第1种匹配方式,OF类型匹配,设备树采用的匹配方式
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
//第2种匹配方式,ACPI匹配
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
//第3种匹配方式,id_table匹配
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
//第4种匹配方式,直接比较驱动和设备的name字段
return (strcmp(pdev->name, drv->name) == 0);
}
可以看到,platform_match可以使用四种匹配方式
第1种:OF类型匹配,设备树采用的匹配方式
kernel\msm-4.9\include\linux\of_device.h\of_driver_match_device()定义如下:
/**
* of_driver_match_device - Tell if a driver's of_match_table matches a device.
* @drv: the device_driver structure to test
* @dev: the device structure to match against
*/
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;
}
调用of_match_device(drv->of_match_table, dev)来实现匹配,此函数在kernel\msm-4.9\drivers\of\device.c种定义
/**
* of_match_device - Tell if a struct device matches an of_device_id list
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
* Used by a driver to check whether an platform_device present in the
* system is in its list of supported devices.
*/
const 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);
}
EXPORT_SYMBOL(of_match_device);
这里调用of_match_node(),此函数在kernel\msm-4.9\drivers\of\base.c中定义
/**
* of_match_node - Tell if a device_node has a matching of_match structure
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
* Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct 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;
}
EXPORT_SYMBOL(of_match_node);
调用__of_match_node(),此函数在kernel\msm-4.9\drivers\of\base.c中定义
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
const struct of_device_id *best_match = NULL;
int score, best_score = 0;
if (!matches)
return NULL;
//name,type,compatible需要有一个非NULL。
for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
score = __of_device_is_compatible(node, matches->compatible,
matches->type, matches->name);
if (score > best_score) {
best_match = matches;
best_score = score;
}
}
return best_match;
}
调用 __of_device_is_compatible(node, matches->compatible, matches->type, matches->name),此函数在kernel\msm-4.9\drivers\of\base.c中定义
/**
* __of_device_is_compatible() - Check if the node matches given constraints
* @device: pointer to node
* @compat: required compatible string, NULL or "" for any match
* @type: required device_type value, NULL or "" for any match
* @name: required node name, NULL or "" for any match
*
* Checks if the given @compat, @type and @name strings match the
* properties of the given @device. A constraints can be skipped by
* passing NULL or an empty string as the constraint.
*
* Returns 0 for no match, and a positive integer on match. The return
* value is a relative score with larger values indicating better
* matches. The score is weighted for the most specific compatible value
* to get the highest score. Matching type is next, followed by matching
* name. Practically speaking, this results in the following priority
* order for matches:
*
* 1. specific compatible && type && name
* 2. specific compatible && type
* 3. specific compatible && name
* 4. specific compatible
* 5. general compatible && type && name
* 6. general compatible && type
* 7. general compatible && name
* 8. general compatible
* 9. type && name
* 10. type
* 11. name
*/
static int __of_device_is_compatible(const struct device_node *device,
const char *compat, const char *type, const char *name)
{
struct property *prop;
const char *cp;
int index = 0, score = 0;
/* Compatible match has highest priority */
if (compat && compat[0]) {
prop = __of_find_property(device, "compatible", NULL);
for (cp = of_prop_next_string(prop, NULL); cp;
cp = of_prop_next_string(prop, cp), index++) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
score = INT_MAX/2 - (index << 2);
break;
}
}
if (!score)
return 0;
}
/* Matching type is better than matching name */
if (type && type[0]) {
if (!device->type || of_node_cmp(type, device->type))
return 0;
score += 2;
}
/* Matching name is a bit better than not */
if (name && name[0]) {
if (!device->name || of_node_cmp(name, device->name))
return 0;
score++;
}
return score;
}
先判断设备节点compatible属性的值和驱动中of_match_table的compatible成员是否相等
下面是设备节点的compatible属性:
gpio_control {
compatible = "gpio-control";
...
}
下面是驱动中of_match_table的compatible成员
static const struct of_device_id gpio_control_of_match[] = {
{ .compatible = "gpio-control", },
{ },
};
static struct platform_driver gpio_control_device_driver = {
.probe = gpio_control_probe,
.remove = gpio_control_remove,
.driver = {
.name = "gpio-control",
.owner = THIS_MODULE,
.pm = &gpio_control_pm_ops,
.of_match_table = of_match_ptr(gpio_control_of_match),
}
};
后面判断type和name。
第2种:ACPI匹配
kernel\msm-4.9\drivers\acpi\bus.c定义了acpi_driver_match_device()的实现
第3种:id_table匹配
kernel\msm-4.9\drivers\base\platform.c定义了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;
}
判断id_table->name和设备节点名称是否相同
第4种:直接比较驱动和设备的name字段
还没有评论,来说两句吧...