linux通过platform_match()匹配platform总线上的device和driver

悠悠 2023-01-13 01:53 191阅读 0赞

\kernel\msm-4.9\drivers\base\platform.c定义了platform_match()的实现,先来看定义

  1. /**
  2. * platform_match - bind platform device to platform driver.
  3. * @dev: device.
  4. * @drv: driver.
  5. *
  6. * Platform device IDs are assumed to be encoded like this:
  7. * "<name><instance>", where <name> is a short description of the type of
  8. * device, like "pci" or "floppy", and <instance> is the enumerated
  9. * instance of the device, like '0' or '42'. Driver IDs are simply
  10. * "<name>". So, extract the <name> from the platform_device structure,
  11. * and compare it against the name of the driver. Return whether they match
  12. * or not.
  13. */
  14. static int platform_match(struct device *dev, struct device_driver *drv)
  15. {
  16. struct platform_device *pdev = to_platform_device(dev);
  17. struct platform_driver *pdrv = to_platform_driver(drv);
  18. /* When driver_override is set, only bind to the matching driver */
  19. if (pdev->driver_override)
  20. return !strcmp(pdev->driver_override, drv->name);
  21. /* Attempt an OF style match first */
  22. //第1种匹配方式,OF类型匹配,设备树采用的匹配方式
  23. if (of_driver_match_device(dev, drv))
  24. return 1;
  25. /* Then try ACPI style match */
  26. //第2种匹配方式,ACPI匹配
  27. if (acpi_driver_match_device(dev, drv))
  28. return 1;
  29. /* Then try to match against the id table */
  30. //第3种匹配方式,id_table匹配
  31. if (pdrv->id_table)
  32. return platform_match_id(pdrv->id_table, pdev) != NULL;
  33. /* fall-back to driver name match */
  34. //第4种匹配方式,直接比较驱动和设备的name字段
  35. return (strcmp(pdev->name, drv->name) == 0);
  36. }

可以看到,platform_match可以使用四种匹配方式

第1种:OF类型匹配,设备树采用的匹配方式

kernel\msm-4.9\include\linux\of_device.h\of_driver_match_device()定义如下:

  1. /**
  2. * of_driver_match_device - Tell if a driver's of_match_table matches a device.
  3. * @drv: the device_driver structure to test
  4. * @dev: the device structure to match against
  5. */
  6. static inline int of_driver_match_device(struct device *dev,
  7. const struct device_driver *drv)
  8. {
  9. return of_match_device(drv->of_match_table, dev) != NULL;
  10. }

调用of_match_device(drv->of_match_table, dev)来实现匹配,此函数在kernel\msm-4.9\drivers\of\device.c种定义

  1. /**
  2. * of_match_device - Tell if a struct device matches an of_device_id list
  3. * @ids: array of of device match structures to search in
  4. * @dev: the of device structure to match against
  5. *
  6. * Used by a driver to check whether an platform_device present in the
  7. * system is in its list of supported devices.
  8. */
  9. const struct of_device_id *of_match_device(const struct of_device_id *matches,
  10. const struct device *dev)
  11. {
  12. if ((!matches) || (!dev->of_node))
  13. return NULL;
  14. return of_match_node(matches, dev->of_node);
  15. }
  16. EXPORT_SYMBOL(of_match_device);

这里调用of_match_node(),此函数在kernel\msm-4.9\drivers\of\base.c中定义

  1. /**
  2. * of_match_node - Tell if a device_node has a matching of_match structure
  3. * @matches: array of of device match structures to search in
  4. * @node: the of device structure to match against
  5. *
  6. * Low level utility function used by device matching.
  7. */
  8. const struct of_device_id *of_match_node(const struct of_device_id *matches,
  9. const struct device_node *node)
  10. {
  11. const struct of_device_id *match;
  12. unsigned long flags;
  13. raw_spin_lock_irqsave(&devtree_lock, flags);
  14. match = __of_match_node(matches, node);
  15. raw_spin_unlock_irqrestore(&devtree_lock, flags);
  16. return match;
  17. }
  18. EXPORT_SYMBOL(of_match_node);

调用__of_match_node(),此函数在kernel\msm-4.9\drivers\of\base.c中定义

  1. static
  2. const struct of_device_id *__of_match_node(const struct of_device_id *matches,
  3. const struct device_node *node)
  4. {
  5. const struct of_device_id *best_match = NULL;
  6. int score, best_score = 0;
  7. if (!matches)
  8. return NULL;
  9. //name,type,compatible需要有一个非NULL。
  10. for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
  11. score = __of_device_is_compatible(node, matches->compatible,
  12. matches->type, matches->name);
  13. if (score > best_score) {
  14. best_match = matches;
  15. best_score = score;
  16. }
  17. }
  18. return best_match;
  19. }

调用 __of_device_is_compatible(node, matches->compatible, matches->type, matches->name),此函数在kernel\msm-4.9\drivers\of\base.c中定义

  1. /**
  2. * __of_device_is_compatible() - Check if the node matches given constraints
  3. * @device: pointer to node
  4. * @compat: required compatible string, NULL or "" for any match
  5. * @type: required device_type value, NULL or "" for any match
  6. * @name: required node name, NULL or "" for any match
  7. *
  8. * Checks if the given @compat, @type and @name strings match the
  9. * properties of the given @device. A constraints can be skipped by
  10. * passing NULL or an empty string as the constraint.
  11. *
  12. * Returns 0 for no match, and a positive integer on match. The return
  13. * value is a relative score with larger values indicating better
  14. * matches. The score is weighted for the most specific compatible value
  15. * to get the highest score. Matching type is next, followed by matching
  16. * name. Practically speaking, this results in the following priority
  17. * order for matches:
  18. *
  19. * 1. specific compatible && type && name
  20. * 2. specific compatible && type
  21. * 3. specific compatible && name
  22. * 4. specific compatible
  23. * 5. general compatible && type && name
  24. * 6. general compatible && type
  25. * 7. general compatible && name
  26. * 8. general compatible
  27. * 9. type && name
  28. * 10. type
  29. * 11. name
  30. */
  31. static int __of_device_is_compatible(const struct device_node *device,
  32. const char *compat, const char *type, const char *name)
  33. {
  34. struct property *prop;
  35. const char *cp;
  36. int index = 0, score = 0;
  37. /* Compatible match has highest priority */
  38. if (compat && compat[0]) {
  39. prop = __of_find_property(device, "compatible", NULL);
  40. for (cp = of_prop_next_string(prop, NULL); cp;
  41. cp = of_prop_next_string(prop, cp), index++) {
  42. if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
  43. score = INT_MAX/2 - (index << 2);
  44. break;
  45. }
  46. }
  47. if (!score)
  48. return 0;
  49. }
  50. /* Matching type is better than matching name */
  51. if (type && type[0]) {
  52. if (!device->type || of_node_cmp(type, device->type))
  53. return 0;
  54. score += 2;
  55. }
  56. /* Matching name is a bit better than not */
  57. if (name && name[0]) {
  58. if (!device->name || of_node_cmp(name, device->name))
  59. return 0;
  60. score++;
  61. }
  62. return score;
  63. }

先判断设备节点compatible属性的值和驱动中of_match_table的compatible成员是否相等

下面是设备节点的compatible属性:

  1. gpio_control {
  2. compatible = "gpio-control";
  3. ...
  4. }

下面是驱动中of_match_table的compatible成员

  1. static const struct of_device_id gpio_control_of_match[] = {
  2. { .compatible = "gpio-control", },
  3. { },
  4. };
  5. static struct platform_driver gpio_control_device_driver = {
  6. .probe = gpio_control_probe,
  7. .remove = gpio_control_remove,
  8. .driver = {
  9. .name = "gpio-control",
  10. .owner = THIS_MODULE,
  11. .pm = &gpio_control_pm_ops,
  12. .of_match_table = of_match_ptr(gpio_control_of_match),
  13. }
  14. };

后面判断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的实现()

  1. static const struct platform_device_id *platform_match_id(
  2. const struct platform_device_id *id,
  3. struct platform_device *pdev)
  4. {
  5. while (id->name[0]) {
  6. if (strcmp(pdev->name, id->name) == 0) {
  7. pdev->id_entry = id;
  8. return id;
  9. }
  10. id++;
  11. }
  12. return NULL;
  13. }

判断id_table->name和设备节点名称是否相同

第4种:直接比较驱动和设备的name字段

发表评论

表情:
评论列表 (有 0 条评论,191人围观)

还没有评论,来说两句吧...

相关阅读