Exemple #1
0
/**
 * add_changeset_node() - add @node (and children) to overlay changeset
 * @ovcs:		overlay changeset
 * @target_node:	where to place @node in live tree
 * @node:		node from within overlay device tree fragment
 *
 * If @node does not already exist in @target_node, add changeset entry
 * to add @node in @target_node.
 *
 * If @node already exists in @target_node, and the existing node has
 * a phandle, the overlay node is not allowed to have a phandle.
 *
 * If @node has child nodes, add the children recursively via
 * build_changeset_next_level().
 *
 * NOTE_1: A live devicetree created from a flattened device tree (FDT) will
 *       not contain the full path in node->full_name.  Thus an overlay
 *       created from an FDT also will not contain the full path in
 *       node->full_name.  However, a live devicetree created from Open
 *       Firmware may have the full path in node->full_name.
 *
 *       add_changeset_node() follows the FDT convention and does not include
 *       the full path in node->full_name.  Even though it expects the overlay
 *       to not contain the full path, it uses kbasename() to remove the
 *       full path should it exist.  It also uses kbasename() in comparisons
 *       to nodes in the live devicetree so that it can apply an overlay to
 *       a live devicetree created from Open Firmware.
 *
 * NOTE_2: Multiple mods of created nodes not supported.
 *       If more than one fragment contains a node that does not already exist
 *       in the live tree, then for each fragment of_changeset_attach_node()
 *       will add a changeset entry to add the node.  When the changeset is
 *       applied, __of_attach_node() will attach the node twice (once for
 *       each fragment).  At this point the device tree will be corrupted.
 *
 *       TODO: add integrity check to ensure that multiple fragments do not
 *             create the same node.
 *
 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
 * invalid @overlay.
 */
static int add_changeset_node(struct overlay_changeset *ovcs,
		struct device_node *target_node, struct device_node *node)
{
	const char *node_kbasename;
	struct device_node *tchild;
	int ret = 0;

	node_kbasename = kbasename(node->full_name);

	for_each_child_of_node(target_node, tchild)
		if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
			break;

	if (!tchild) {
		tchild = __of_node_dup(node, node_kbasename);
		if (!tchild)
			return -ENOMEM;

		tchild->parent = target_node;

		ret = of_changeset_attach_node(&ovcs->cset, tchild);
		if (ret)
			return ret;

		return build_changeset_next_level(ovcs, tchild, node);
	}

	if (node->phandle && tchild->phandle)
		ret = -EINVAL;
	else
		ret = build_changeset_next_level(ovcs, tchild, node);
	of_node_put(tchild);

	return ret;
}
Exemple #2
0
static int of_overlay_apply_single_device_node(struct of_overlay *ov,
		struct device_node *target, struct device_node *child)
{
	const char *cname;
	struct device_node *tchild;
	int ret = 0;

	cname = kbasename(child->full_name);
	if (cname == NULL)
		return -ENOMEM;

	/* NOTE: Multiple mods of created nodes not supported */
	tchild = of_get_child_by_name(target, cname);
	if (tchild != NULL) {
		/* apply overlay recursively */
		ret = of_overlay_apply_one(ov, tchild, child);
		of_node_put(tchild);
	} else {
		/* create empty tree as a target */
		tchild = __of_node_dup(child, "%s/%s", target->full_name, cname);
		if (!tchild)
			return -ENOMEM;

		/* point to parent */
		tchild->parent = target;

		ret = of_changeset_attach_node(&ov->cset, tchild);
		if (ret)
			return ret;

		ret = of_overlay_apply_one(ov, tchild, child);
		if (ret)
			return ret;
	}

	return ret;
}