platform_device的生成过程

来源:互联网 发布:涤纶网络丝织带 编辑:程序博客网 时间:2024/04/26 05:28
kernel在引入dts前后,platform_device的生成方式是不同的。在引入设备树之前,platform_device变量是静态定义的。而引入设备树之后,kernel通过解析设备节点的信息生成platform_device。一、引入dts之前 add a platform-level deviceint platform_device_register(struct platform_device *pdev){        device_initialize(&pdev->dev);        arch_setup_pdev_archdata(pdev);        return platform_device_add(pdev);}  add a platform device to device hierarchy This is part 2 of platform_device_register(), though may be called separately _iff_ pdev was allocated by platform_device_alloc().int platform_device_add(struct platform_device *pdev){        int i, ret;        if (!pdev)                return -EINVAL;        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:                /*                 * 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; 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;}该函数最终会调用device_add添加设备二、引入设备树之后引入设备树之后,主要是通过解析设备树节点生成platform_device。kernel中有两个阶段会生成platform_device:第一阶段是在kernel初始化解析设备树时,kernel会为所有包含compatible属性名的第一级node创建platform_device。如果第一级node的compatible属性值为“simple-bus”、“simple-mfd”或者"arm,amba-bus",kernel会继续为当前node的包含compatible属性的节点创建platform_device。一般SOC直接子设备节点对应的platform_device会被生成,而间接子节点对应的platform_device不会生成。第二阶段是生成第一阶段中未满足match要求的间接子节点对应的platform_device。通常是在父节点设备驱动的probe函数中遍历子节点生成对应的platform_device。(1)第一阶段通过调用of_platform_populate解析设备树//Populate platform_devices from device tree dataint 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;        for_each_child_of_node(root, child) {                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;}kernel中有个of_platform_bus_probe函数,该函数和of_platform_populate有点类似,在新的board中最好使用of_platform_populate来代替of_platform_bus_probe函数。Create a device for a node and its children.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){        const struct of_dev_auxdata *auxdata;        struct device_node *child;        struct platform_device *dev;        const char *bus_id = NULL;        void *platform_data = NULL;        int rc = 0;        /* Make sure it has a compatible property */        if (strict && (!of_get_property(bus, "compatible", NULL))) {                pr_debug("%s() - skipping %s, no compatible prop\n",                         __func__, bus->full_name);                return 0;        }        auxdata = of_dev_lookup(lookup, bus);        if (auxdata) {                bus_id = auxdata->name;                platform_data = auxdata->platform_data;        }        if (of_device_is_compatible(bus, "arm,primecell")) {                /*                 * Don't return an error here to keep compatibility with older                 * device tree files.                 */                of_amba_device_create(bus, bus_id, platform_data, parent);                return 0;        }        dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);        if (!dev || !of_match_node(matches, bus))                return 0;        for_each_child_of_node(bus, child) {                pr_debug("   create child: %s\n", child->full_name);                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;}Alloc, initialize and register an of_devicestatic struct platform_device *of_platform_device_create_pdata(                                        struct device_node *np,                                        const char *bus_id,                                        void *platform_data,                                        struct device *parent){        struct platform_device *dev;        if (!of_device_is_available(np) ||            of_node_test_and_set_flag(np, OF_POPULATED))                return NULL;        dev = of_device_alloc(np, bus_id, parent);        if (!dev)                goto err_clear_flag;        dev->dev.bus = &platform_bus_type;        dev->dev.platform_data = platform_data;        of_dma_configure(&dev->dev, dev->dev.of_node);        of_msi_configure(&dev->dev, dev->dev.of_node);        if (of_device_add(dev) != 0) {                of_dma_deconfigure(&dev->dev);                platform_device_put(dev);                goto err_clear_flag;        }        return dev;err_clear_flag:        of_node_clear_flag(np, OF_POPULATED);        return NULL;}of_platform_device_create_pdata函数真正完成了创建platform_device的工作。调用它的函数主要是做一些准备工作,如查找设备节点、检查兼容性等。int of_device_add(struct platform_device *ofdev){        BUG_ON(ofdev->dev.of_node == NULL);        /* name and id have to be set so that the platform bus doesn't get         * confused on matching */        ofdev->name = dev_name(&ofdev->dev);        ofdev->id = -1;        /*         * If this device has not binding numa node in devicetree, that is         * of_node_to_nid returns NUMA_NO_NODE. device_add will assume that this         * device is on the same node as the parent.         */        set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));        return device_add(&ofdev->dev);}(2)第二阶段在父设备节点的驱动probe函数中调用of_platform_device_create生成子设备节点对应的platforma_device。 struct platform_device *of_platform_device_create(struct device_node *np,                                             const char *bus_id,                                             struct device *parent){        return of_platform_device_create_pdata(np, bus_id, NULL, parent);}上述函数实际上调用of_platform_device_create_pdata完成生成platforma_device的工作的。



原创粉丝点击