linux内核总线驱动模型-platform篇

tech2024-08-04  52

linux从2.6开始就加入了一套新的驱动管理和注册机制平台总线,是一条虚拟的总线,设备用platform_device表示,驱动用platform_driver进行注册。于传统的总线/设备/驱动程序机制相比,平台由内核进行统一管理,在驱动中使用资源,提高了代码的安全性和可移植性。

下面来看看内核时怎么注册platform总线的过程:

struct device platform_bus = { .init_name = "platform", }; struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; int __init platform_bus_init(void) { int error; early_platform_cleanup(); error = device_register(&platform_bus); if (error) return error; error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); of_platform_register_reconfig_notifier(); return error; }

由传统的机制,也不难总结出平台的开发流程为,其过程和总线的注册过程差不多,驱动和设备匹配后,调用平台的匹配函数。

定义一个platform_device,并注册定义一个platform_driver,并注册

平台设备定义如下:

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

注册过程如下:

int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev);//dev初始化 arch_setup_pdev_archdata(pdev); return platform_device_add(pdev);//dev加入到链表中 } int platform_device_add(struct platform_device *pdev) { int i, ret; if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; //设置父设备为platform_bus pdev->dev.bus = &platform_bus_type; //设置总线为platform_bus_type switch (pdev->id) { default: dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); break; case PLATFORM_DEVID_NONE: dev_set_name(&pdev->dev, "%s", pdev->name); break; case PLATFORM_DEVID_AUTO: /* * Automatically allocated device ID. We mark it as such so * that we remember it must be freed, and we append a suffix * to avoid namespace collision with explicit IDs. */ ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); if (ret < 0) goto err_out; pdev->id = ret; pdev->id_auto = true; dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); break; } /*完成资源的初始化*/ for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) r->name = dev_name(&pdev->dev); p = r->parent; if (!p) { if (resource_type(r) == IORESOURCE_MEM) p = &iomem_resource; else if (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; } if (p && insert_resource(p, r)) { dev_err(&pdev->dev, "failed to claim resource %d\n", i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); if (ret == 0) return ret; }

其上最后也是调用device_add的,其主要是将设备加入到总线总线中,并由device_attach完成设备与驱动之间的匹配,这个过程在设备中已经有详细的分析过程中,再看看驱动的注册过程。

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

可见,它包含了设备操作的功能函数,同时包含了device_driver结构。内核提供的platform_driver结构注册函数为:

#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE) int __platform_driver_register(struct platform_driver *drv, struct module *owner) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type;//驱动的总线设置为platform总线 if (drv->probe) drv->driver.probe = platform_drv_probe; if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); }

其注册功能中比较重要的还是调用了driver_register,添加到平台总线链表,完成设备与驱动之间的匹配过程,其主要的过程在总线设备驱动模型的驱动文章已经有过分析。

下面看看驱动和设备的匹配过程,主要是调用bus的match函数来完成匹配。

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 */ 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 */ 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); }

由以上的分析可以看出,platform是一条虚拟的总线,本身还是基于的总线设备驱动模型的。

最新回复(0)