3.6内核对设备树的处理——platform_device跟platform_driver的匹配

本节说明platform_device怎么跟platform_driver匹配。

首先,有一个平台总线platform_bus_type,总线上分别挂着平台设备platform_device平台驱动platform_driver

平台总线platform_bus_type

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,    // platform_device和platform_driver的匹配函数
	.uevent		= platform_uevent,
	.dma_configure	= platform_dma_configure,
	.pm		= &platform_dev_pm_ops,
};

所谓平台设备platform_device平台驱动platform_driver,就是一个又一个platform_device和platform_driver结构体;

依次分析platform_deviceplatform_driver结构体。

platform_device结构体

platform_device结构体如下。

struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;
	u32		num_resources;
	struct resource	*resource;

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

platform_device主要有3个成员与匹配相关:

  1. platform_device->driver_override;
  2. platform_device.dev->of_node(主要是of_node里面包含的节点的compatible属性);
  3. platform_device.name;

为了方便描述,这3个成员分别用①,②,③来指代。

platform_driver结构体

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};

struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];
	kernel_ulong_t driver_data;
};
struct device_driver {
	const char		*name;
    ...

	const struct of_device_id	*of_match_table;
    ...
};

struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

类似的,platform_driver也有3个成员与匹配相关:

  1. platform_driver.driver->name;
  2. platform_driver.driver->of_match_table;
  3. platform_driver->id_table;

为了方便描述,这3个成员分别用A,B,C来指代。

platform_match

platform_deviceplatform_driver的匹配,是通过平台总线platform_bus_typematch成员实现的

match成员是一个函数指针,指向platform_match函数,这个函数就是专门用来匹配platform_deviceplatform_driver的。

重点分析一下platform_match函数。

第一,比较的是①和A(platform_device->driver_override PK platform_driver.driver->name)。

第二,比较的是②和B(platform_device.dev->of_node的compatible PK platform_driver.driver->of_match_table)。

函数调用如下,最终比较的是platform_device.dev->of_node的compatible属性platform_driver.driver->of_match_table

platform_match(struct device *dev, struct device_driver *drv)
    of_driver_match_device(dev, drv)
        of_driver_match_device(dev, drv)
            of_match_device(drv->of_match_table, dev)
                of_match_node(drv->of_match_table->of_match_table, dev)

除了匹配compatible属性之外,节点type和name属性也可以参与比较,只是优先级较低。

第三,比较的是③和C(platform_driver->id_table PK platform_device.name)。

第四,比较的是③和A(platform_device.name PK platform_driver.driver->name)。

总结(匹配优先级)

最后,匹配的优先级总结如下:

  1. 比较 platform_dev.driver_override 和 platform_driver.drv->name;
  2. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table;
  3. 比较 platform_dev.name 和 platform_driver.id_table;
  4. 比较 platform_dev.name 和 platform_driver.drv->name;

有一个匹配成功,即表示匹配成功,会调用platform_driver->probe函数。

有一个示例如下,关于该示例不做更多说明。

注册 platform_driver 的过程

主要分为以下4步:

  1. 将platform_driver放入platform_bus_type的driver链表中;
  2. 对于platform_bus_type下的每一个device,调用__driver_attach;
  3. 调用 platform_bus_type.match,判断dev和drv是否匹配成功;
  4. 如果匹配成功,最终会调用drv的probe函数;
platform_driver_register
    __platform_driver_register
        drv->driver.probe = platform_drv_probe;
        driver_register
            bus_add_driver
                klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);    // 把 platform_driver 放入 platform_bus_type 的driver链表中
                driver_attach
                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  // 对于plarform_bus_type下的每一个设备, 调用__driver_attach
                        __driver_attach
                            ret = driver_match_device(drv, dev);  // 判断dev和drv是否匹配成功
                                        return drv->bus->match ? drv->bus->match(dev, drv) : 1;  // 调用 platform_bus_type.match
                            driver_probe_device(drv, dev);
                                        really_probe
                                            drv->probe  // platform_drv_probe
                                                platform_drv_probe
                                                    struct platform_driver *drv = to_platform_driver(_dev->driver);
                                                    drv->probe

注册 platform_device 的过程

与注册 platform_driver 类似,也可以分为以下几步:

  1. 将 platform_device 放入platform_bus_type的device链表中;
  2. 对于platform_bus_type下的每一个driver,调用__device_attach_driver;
  3. 调用 platform_bus_type.match,判断dev和drv是否匹配成功;
  4. 如果匹配成功,最终会调用drv的probe函数;
platform_device_register
    platform_device_add
        device_add
            bus_add_device
                klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); // 把 platform_device 放入 platform_bus_type的device链表中
            bus_probe_device(dev);
                device_initial_probe
                    __device_attach
                        ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); // // 对于plarform_bus_type下的每一个driver, 调用 __device_attach_driver
                                    __device_attach_driver
                                        ret = driver_match_device(drv, dev);
                                                    return drv->bus->match ? drv->bus->match(dev, drv) : 1;  // 调用platform_bus_type.match
                                        driver_probe_device
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值