本节说明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_device和platform_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个成员与匹配相关:
- platform_device->driver_override;
- platform_device.dev->of_node(主要是of_node里面包含的节点的compatible属性);
- 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个成员与匹配相关:
- platform_driver.driver->name;
- platform_driver.driver->of_match_table;
- platform_driver->id_table;
为了方便描述,这3个成员分别用A,B,C来指代。
platform_match
platform_device和platform_driver的匹配,是通过平台总线platform_bus_type的match成员实现的。
match成员是一个函数指针,指向platform_match函数,这个函数就是专门用来匹配platform_device和platform_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)。
总结(匹配优先级)
最后,匹配的优先级总结如下:
- 比较 platform_dev.driver_override 和 platform_driver.drv->name;
- 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table;
- 比较 platform_dev.name 和 platform_driver.id_table;
- 比较 platform_dev.name 和 platform_driver.drv->name;
有一个匹配成功,即表示匹配成功,会调用platform_driver->probe函数。
有一个示例如下,关于该示例不做更多说明。
注册 platform_driver 的过程
主要分为以下4步:
- 将platform_driver放入platform_bus_type的driver链表中;
- 对于platform_bus_type下的每一个device,调用__driver_attach;
- 调用 platform_bus_type.match,判断dev和drv是否匹配成功;
- 如果匹配成功,最终会调用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 类似,也可以分为以下几步:
- 将 platform_device 放入platform_bus_type的device链表中;
- 对于platform_bus_type下的每一个driver,调用__device_attach_driver;
- 调用 platform_bus_type.match,判断dev和drv是否匹配成功;
- 如果匹配成功,最终会调用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