其他分享
首页 > 其他分享> > u-boot device_bind_common函数

u-boot device_bind_common函数

作者:互联网

static int device_bind_common(struct udevice *parent, const struct driver *drv,
                  const char *name, void *plat,
                  ulong driver_data, ofnode node,
                  uint of_plat_size, struct udevice **devp)
{
    struct udevice *dev;
    struct uclass *uc;
    int size, ret = 0;
    bool auto_seq = true;
    void *ptr;

    if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
        return -ENOSYS;

    if (devp)
        *devp = NULL;
    if (!name)
        return -EINVAL;

    ret = uclass_get(drv->id, &uc);
    if (ret) {
        debug("Missing uclass for driver %s\n", drv->name);
        return ret;
    }

    dev = calloc(1, sizeof(struct udevice));
    if (!dev)
        return -ENOMEM;

    INIT_LIST_HEAD(&dev->sibling_node);
    INIT_LIST_HEAD(&dev->child_head);
    INIT_LIST_HEAD(&dev->uclass_node);
#ifdef CONFIG_DEVRES
    INIT_LIST_HEAD(&dev->devres_head);
#endif
    dev_set_plat(dev, plat);
    dev->driver_data = driver_data;
    dev->name = name;
    dev_set_ofnode(dev, node);
    dev->parent = parent;
    dev->driver = drv;
    dev->uclass = uc;

    dev->seq_ = -1;
    if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
        (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
        /*
         * Some devices, such as a SPI bus, I2C bus and serial ports
         * are numbered using aliases.
         */
        if (CONFIG_IS_ENABLED(OF_CONTROL) &&
            !CONFIG_IS_ENABLED(OF_PLATDATA)) {
            if (uc->uc_drv->name && ofnode_valid(node)) {
                if (!dev_read_alias_seq(dev, &dev->seq_)) {
                    auto_seq = false;
                    log_debug("   - seq=%d\n", dev->seq_);
                    }
            }
        }
    }
    if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
        dev->seq_ = uclass_find_next_free_seq(uc);

    /* Check if we need to allocate plat */
    if (drv->plat_auto) {
        bool alloc = !plat;

        /*
         * For of-platdata, we try use the existing data, but if
         * plat_auto is larger, we must allocate a new space
         */
        if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
            if (of_plat_size)
                dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
            if (of_plat_size < drv->plat_auto)
                alloc = true;
        }
        if (alloc) {
            dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
            ptr = calloc(1, drv->plat_auto);
            if (!ptr) {
                ret = -ENOMEM;
                goto fail_alloc1;
            }

            /*
             * For of-platdata, copy the old plat into the new
             * space
             */
            if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
                memcpy(ptr, plat, of_plat_size);
            dev_set_plat(dev, ptr);
        }
    }

    size = uc->uc_drv->per_device_plat_auto;
    if (size) {
        dev_or_flags(dev, DM_FLAG_ALLOC_UCLASS_PDATA);
        ptr = calloc(1, size);
        if (!ptr) {
            ret = -ENOMEM;
            goto fail_alloc2;
        }
        dev_set_uclass_plat(dev, ptr);
    }

    if (parent) {
        size = parent->driver->per_child_plat_auto;
        if (!size)
            size = parent->uclass->uc_drv->per_child_plat_auto;
        if (size) {
            dev_or_flags(dev, DM_FLAG_ALLOC_PARENT_PDATA);
            ptr = calloc(1, size);
            if (!ptr) {
                ret = -ENOMEM;
                goto fail_alloc3;
            }
            dev_set_parent_plat(dev, ptr);
        }
        /* put dev into parent's successor list */
        list_add_tail(&dev->sibling_node, &parent->child_head);
    }

    ret = uclass_bind_device(dev);
    if (ret)
        goto fail_uclass_bind;

    /* if we fail to bind we remove device from successors and free it */
    if (drv->bind) {
        ret = drv->bind(dev);
        if (ret)
            goto fail_bind;
    }
    if (parent && parent->driver->child_post_bind) {
        ret = parent->driver->child_post_bind(dev);
        if (ret)
            goto fail_child_post_bind;
    }
    if (uc->uc_drv->post_bind) {
        ret = uc->uc_drv->post_bind(dev);
        if (ret)
            goto fail_uclass_post_bind;
    }

    if (parent)
        pr_debug("Bound device %s to %s\n", dev->name, parent->name);
    if (devp)
        *devp = dev;

    dev_or_flags(dev, DM_FLAG_BOUND);

    return 0;

fail_uclass_post_bind:
    /* There is no child unbind() method, so no clean-up required */
fail_child_post_bind:
    if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
        if (drv->unbind && drv->unbind(dev)) {
            dm_warn("unbind() method failed on dev '%s' on error path\n",
                dev->name);
        }
    }

fail_bind:
    if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
        if (uclass_unbind_device(dev)) {
            dm_warn("Failed to unbind dev '%s' on error path\n",
                dev->name);
        }
    }
fail_uclass_bind:
    if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
        list_del(&dev->sibling_node);
        if (dev_get_flags(dev) & DM_FLAG_ALLOC_PARENT_PDATA) {
            free(dev_get_parent_plat(dev));
            dev_set_parent_plat(dev, NULL);
        }
    }
fail_alloc3:
    if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
        if (dev_get_flags(dev) & DM_FLAG_ALLOC_UCLASS_PDATA) {
            free(dev_get_uclass_plat(dev));
            dev_set_uclass_plat(dev, NULL);
        }
    }
fail_alloc2:
    if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
        if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
            free(dev_get_plat(dev));
            dev_set_plat(dev, NULL);
        }
    }
fail_alloc1:
    devres_release_all(dev);

    free(dev);

    return ret;
}

 

 

 

A:生成 udevice。

B:绑定 udevice 和 driver。

C:把设备挂到 uclass 的dev_head 链表下。

D:调用设备驱动的 bind 接口。

 

标签:bind,boot,uclass,dev,drv,device,plat,uc
来源: https://www.cnblogs.com/liujunhuasd/p/15887425.html