
1. 结构体定义
struct platform_device { const char *name; /* 设备名称,用于设备和驱动匹配 */ int id; /* 设备实例编号,用于区分多个同名设备 */ bool id_auto; /* 自动分配设备ID标志 */struct device dev; u32 num_resources; /* 资源数量 */struct resource *resource; /* 资源数组 */ conststruct platform_device_id *id_entry; char *driver_override; /* 强制匹配的驱动名称 */ /* MFD cell pointer */struct mfd_cell *mfd_cell; /* arch specific additions */struct pdev_archdata archdata;};
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; conststruct platform_device_id *id_table; /* 设备ID匹配表 */ bool prevent_deferred_probe; /* 阻止延迟探测标志 */};
2. 总线
platform_bus_init注册一个platform总线,可以看到在函数内部注册了一个名叫platform的device ,目的在于让总线本身也纳入统一的device模型体系,成为sysfs中一个有父节点、可挂属性、可绑定驱动的对象。总线bus并不是device,而很多机制(sysfs、driver 绑定、电源管理、属性文件)都要求必须挂在某个device下面,所以需要为platform总线专门创建一个承载它的 device,即platform_bus。
struct device platform_bus = { .init_name = "platform",};int __init platform_bus_init(void){ /* 清理由早期early平台机制创建的临时platformz资源 */ early_platform_cleanup(); /* 注册名为platform的device */ device_register(&platform_bus); /* 注册总线 */ bus_register(&platform_bus_type); /* 注册一个 notifier,用于在设备树发生运行期变”时,同步创建或销毁 platform 设备 */ of_platform_register_reconfig_notifier();}
注册总线时传入的参数为platform_bus_type,它定义的总线的行为
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, /*为每一个device自动创建一组sysfs属性文件 */ .match = platform_match, /* dev和drv的匹配方式 */ .uevent = platform_uevent, /* 生成uevent时,补充/定制该设备的环境变量内容 */ .pm = &platform_dev_pm_ops, /* 电源管理 */};
关于platform总线的match函数实现如下,优先级最高的是强制匹配,举个例子echo "vfio-platform" > /sys/bus/platform/devices/xxx/driver_override 。
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); /* 强制匹配 */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name); /* 设备树匹配 */ if (of_driver_match_device(dev, drv)) return 1; /* ACPI匹配 */ if (acpi_driver_match_device(dev, drv)) return 1; /* ID表匹配 */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* 名称匹配 */ return (strcmp(pdev->name, drv->name) == 0);}
3. 设备
关于platform设备的定义有两种方式,设备树定义和内核代码定义。
3.1 设备树定义
uart0: serial@ff1a0000 { compatible = "rockchip,rk3568-uart"; reg = <0x0 0xff1a0000 0x0 0x1000>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&cru SCLK_UART0>; status = "okay";};
- •
compatible:用于和platform_driver匹配 - •
status = "okay":否则不会创建device
系统启动阶段会调用of_platform_default_populate_init(),进而调用 of_platform_default_populate(NULL, ...),最终进入of_platform_populate() 对 "/" 的子节点做递归处理。
/** * of_platform_default_populate_init * ├── of_platform_default_populate * └── of_platform_populate*/int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent){struct device_node *child; int rc = 0; /* 获取遍历的起点节点 */ root = root ? of_node_get(root) : of_find_node_by_path("/"); if (!root) return -EINVAL; /* 遍历root的一级子节点 */ for_each_child_of_node(root, child) { /* 从设备树节点创建platform设备,并递归处理子节点 */ rc = of_platform_bus_create(child, matches, lookup, parent, true); if (rc) { of_node_put(child); break; } } of_node_set_flag(root, OF_POPULATED_BUS); of_node_put(root); return rc;}static int of_platform_bus_create(struct device_node *bus, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent, bool strict){ conststruct of_dev_auxdata *auxdata;struct device_node *child;struct platform_device *dev; const char *bus_id = NULL; void *platform_data = NULL; int rc = 0; /* 确保有compatible属性 */ if (strict && (!of_get_property(bus, "compatible", NULL))) { return 0; } /* 避免重复创建 */ if (of_node_check_flag(bus, OF_POPULATED_BUS)) { return 0; } auxdata = of_dev_lookup(lookup, bus); if (auxdata) { bus_id = auxdata->name; platform_data = auxdata->platform_data; } /* AMBA设备 */ if (of_device_is_compatible(bus, "arm,primecell")) { of_amba_device_create(bus, bus_id, platform_data, parent); return 0; } /* 创建platform设备 */ dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); if (!dev || !of_match_node(matches, bus)) return 0; /* 对每个子节点递归调用of_platform_bus_create */ for_each_child_of_node(bus, child) { rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); if (rc) { of_node_put(child); break; } } /* 设置总线已填充 */ of_node_set_flag(bus, OF_POPULATED_BUS); return rc;}
对每个要创建的节点of_platform_device_create_pdata()调用of_device_alloc() ,该函数从设备树节点分配并初始化一个platform_device,解析资源,并设置设备的基本属性。
/** * of_platform_device_create_pdata * ├── of_device_alloc:该函数仅分配和初始化,不注册设备 * └── of_device_add:注册为设备模型中的struct device*/struct platform_device *of_device_alloc(struct device_node *np, const char *bus_id, struct device *parent){struct platform_device *dev; int rc, i, num_reg = 0, num_irq;struct resource *res, temp_res; dev = platform_device_alloc("", PLATFORM_DEVID_NONE); if (!dev) return NULL; /* 统计资源数量 */ while (of_address_to_resource(np, num_reg, &temp_res) == 0) num_reg++; num_irq = of_irq_count(np); /* 分配并填充资源表 */ if (num_irq || num_reg) { res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL); if (!res) { platform_device_put(dev); return NULL; } dev->num_resources = num_reg + num_irq; dev->resource = res; for (i = 0; i < num_reg; i++, res++) { rc = of_address_to_resource(np, i, res); WARN_ON(rc); } if (of_irq_to_resource_table(np, res, num_irq) != num_irq) pr_debug("not all legacy IRQ resources mapped for %s\n", np->name); } /* 设置设备树节点和父设备 */ dev->dev.of_node = of_node_get(np); dev->dev.fwnode = &np->fwnode; dev->dev.parent = parent ? : &platform_bus; if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); return dev;}
完成 device_add() 后,该 DT 节点对应的设备会出现在/sys/bus/platform/devices/<device-name>/
,其of_node指向原始DT节点。
3.2 内核代码定义
静态定义
staticstruct resource demo_resources[] = { { .start = 0xff1a0000, .end = 0xff1a0fff, .flags = IORESOURCE_MEM, }, { .start = 32, .end = 32, .flags = IORESOURCE_IRQ, },};staticstruct platform_device demo_pdev = { .name = "demo-uart", .id = -1, .num_resources = ARRAY_SIZE(demo_resources), .resource = demo_resources,};platform_device_register(&demo_pdev);
静态注册platform device时会调用platform_device_register函数
/** * platform_device_register * ├── device_initialize: 完成struct device的基础设施初始化 * ├── arch_setup_pdev_archdata: 补齐与体系结构相关的pdev->archdata/DMA等信息 * └── platform_device_add: 注册到设备模型*/int platform_device_add(struct platform_device *pdev){ int i, ret; if (!pdev) return -EINVAL; /* 若parent为空,则默认挂载到platform_bus */ if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &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: 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)) { ret = -EBUSY; goto failed; } } /* 加入设备模型 */ ret = device_add(&pdev->dev); if (ret == 0) return ret; failed: if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } while (--i >= 0) {struct resource *r = &pdev->resource[i]; if (r->parent) release_resource(r); } err_out: return ret;}
动态分配
struct platform_device *pdev;pdev = platform_device_alloc("demo-uart", -1);platform_device_add_resources(pdev, demo_resources, ARRAY_SIZE(demo_resources));platform_device_add(pdev);
4. 驱动
驱动注册的函数是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; drv->driver.probe = platform_drv_probe; drv->driver.remove = platform_drv_remove; drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver);}