zoukankan      html  css  js  c++  java
  • 《设备树 — platform_device和platform_driver如何让匹配(五)》

      4.x的内核都是已经支持设备树的,所以platform bus也是做了一些调整。

      主要是在匹配函数里面的支持设备树。

    struct bus_type platform_bus_type = {
    	.name		= "platform",
    	.dev_groups	= platform_dev_groups,
    	.match		= platform_match,
    	.uevent		= platform_uevent,
    	.dma_configure	= platform_dma_configure,
    	.pm		= &platform_dev_pm_ops,
    };
    

      

    /**
     * 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 */
        /* 针对特殊情况,dev中的driver_override被设置,则只匹配和driver_override名字相同的驱动程序 */
    	if (pdev->driver_override)
    		return !strcmp(pdev->driver_override, drv->name);
     
    	/* 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 */
        /* 有驱动中有id_table,则dev中的名字和任何一个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);
    }
    

      这里可以看到匹配的优先级如下:

    1. 设备里的driver_override被设置,优先级最高。
    2. 驱动里的of_match_table,和平台设备的compatible比较。
    3. 高级配置和电源管理之类的匹配。
    4. platform_driver里的id_table里的所有名字和设备名字匹配。
    5. 最后再是设备名字和驱动名字比较。

      当然除了第一个之外,其它的只要没匹配到,后面的几个匹配还会继续执行的。

    设备树匹配方式

    /**
     * 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 - 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);
    }
     
     
     
    /**
     * 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;
    }
     
    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;
     
        //根据匹配的分数,选择最高分的是最佳匹配
    	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() - 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 */
        /* compatible 匹配有限即最高,匹配到了,则给的分数相对较高 */
    	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,类型匹配会加2分 */
    	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,最后在确认名字匹配加1分 */
    	if (name && name[0]) {
    		if (!device->name || of_node_cmp(name, device->name))
    			return 0;
    		score++;
    	}
     
    	return score;
    }

      看这句 prop = __of_find_property(device, "compatible", NULL);
      可以发先追溯到底,是利用"compatible"来匹配的,即设备树加载之后,内核会自动把设备树节点转换成 platform_device这种格式,同时把名字放到of_node这个地方。

      id_tabel是根据id_table表中的每一个和设备名字进行匹配,这样一个驱动可以支持多个名称的设备。

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

      

    举例:

      1.ti的omap8250驱动可以支持好多个型号的芯片,其它芯片只要这个的驱动基础上做很小的改动就可通用。

      其中的改动点,使用of_device_id 的date表示的。

    /*
     * Struct used for matching a device
     */
    struct of_device_id {
    	char	name[32];
    	char	type[32];
    	char	compatible[128];
    	const void *data;
    };
     
     
     
    static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE;
    static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
    static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;
     
     
    static const struct of_device_id omap8250_dt_ids[] = {
    	{ .compatible = "ti,am654-uart" },
    	{ .compatible = "ti,omap2-uart" },
    	{ .compatible = "ti,omap3-uart" },
    	{ .compatible = "ti,omap4-uart", .data = &omap4_habit, },
    	{ .compatible = "ti,am3352-uart", .data = &am3352_habit, },
    	{ .compatible = "ti,am4372-uart", .data = &am3352_habit, },
    	{ .compatible = "ti,dra742-uart", .data = &dra742_habit, },
    	{},
    };
     
     
    static struct platform_driver omap8250_platform_driver = {
    	.driver = {
    		.name		= "omap8250",
    		.pm		= &omap8250_dev_pm_ops,
    		.of_match_table = omap8250_dt_ids,
    	},
    	.probe			= omap8250_probe,
    	.remove			= omap8250_remove,
    };
    

      

    2.ad5380有好多中类型,芯片使用完全兼容。可能就是版本差异。驱动可以完全兼容。

    static const struct spi_device_id ad5380_spi_ids[] = {
    	{ "ad5380-3", ID_AD5380_3 },
    	{ "ad5380-5", ID_AD5380_5 },
    	{ "ad5381-3", ID_AD5381_3 },
    	{ "ad5381-5", ID_AD5381_5 },
    	{ "ad5382-3", ID_AD5382_3 },
    	{ "ad5382-5", ID_AD5382_5 },
    	{ "ad5383-3", ID_AD5383_3 },
    	{ "ad5383-5", ID_AD5383_5 },
    	{ "ad5384-3", ID_AD5380_3 },
    	{ "ad5384-5", ID_AD5380_5 },
    	{ "ad5390-3", ID_AD5390_3 },
    	{ "ad5390-5", ID_AD5390_5 },
    	{ "ad5391-3", ID_AD5391_3 },
    	{ "ad5391-5", ID_AD5391_5 },
    	{ "ad5392-3", ID_AD5392_3 },
    	{ "ad5392-5", ID_AD5392_5 },
    	{ }
    };
    MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
     
    static struct spi_driver ad5380_spi_driver = {
    	.driver = {
    		   .name = "ad5380",
    	},
    	.probe = ad5380_spi_probe,
    	.remove = ad5380_spi_remove,
    	.id_table = ad5380_spi_ids,
    };
    

      最后总结一下有了设备树前后,设备驱动怎么写

      有了设备树这样在dts中编写

    samsung-beep{
             compatible = "samsung,beep";
             reg = <0x114000a0 0x4 0x139D0000 0x14>;
    };
    

      a -- samsung-beep 为节点名,符合咱们前面提到的节点命名规范;

          我们通过名字可以知道,该节点描述的设备是beep, 设备名是samsung-beep;

      b -- compatible = "samsung,beep"; compatible 属性, 即一个字符串;

          前面提到,所有新的compatible值都应使用制造商的前缀,这里是samsung

      c -- reg = <0x114000a0 0x4 0x139D0000 0x14>;

           reg属性来将地址信息编码进设备树,表示该设备的地址范围;这里是我们用到的寄存器及偏移量;

    之前在mach-xxx.c中编写

    static struct  resource beep_resource[] =
    {
        [0] = {
            .start = 0x114000a0,
            .end = 0x114000a0+0x4,
            .flags = IORESOURCE_MEM,
        },
        [1] = {
            .start = 0x139D0000,
            .end = 0x139D0000+0x14,
            .flags = IORESOURCE_MEM,
        },
    };
    static struct platform_device hello_device=
    {
        .name = "beep",
        .id = -1,
        .dev.release = hello_release,
        .num_resources = ARRAY_SIZE(beep_resource ),
        .resource = beep_resource,
    };
    

      


     

  • 相关阅读:
    JAVA 网格布局管理器
    JAVA 流式布局管理器
    JAVA 边界布局管理器
    JAVA 图形界面 JFrame容器
    MySQL联合查询语法内联、左联、右联、全联
    ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL
    ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL
    MVC过滤器详解
    Dapper的基本使用
    JQuery fullcalender文档
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/12877244.html
Copyright © 2011-2022 走看看