summaryrefslogtreecommitdiff
path: root/livetree.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2010-02-25 09:58:29 -0700
committerJon Loeliger <jdl@jdl.com>2010-02-25 11:46:01 -0600
commit83da1b2a4ee272ac97647a82fc652d9b4b1505ee (patch)
tree37673dc8cf18212c20b497b4e030b0370d240ad5 /livetree.c
parent716418849a0ed4cc7689d4b82a73597a8726de92 (diff)
downloaddtc-83da1b2a4ee272ac97647a82fc652d9b4b1505ee.tar.gz
Allow device tree to be modified by additonal device tree sections
This patch allows the following construct: / { property-a = "old"; property-b = "does not change"; }; / { property-a = "changed"; property-c = "new"; node-a { }; }; Where the later device tree overrides the properties found in the earlier tree. This is useful for laying down a template device tree in an include file and modifying it for a specific board without having to clone the entire tree. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'livetree.c')
-rw-r--r--livetree.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/livetree.c b/livetree.c
index f612b72..13c5f10 100644
--- a/livetree.c
+++ b/livetree.c
@@ -26,8 +26,14 @@
void add_label(struct label **labels, char *label)
{
- struct label *new = xmalloc(sizeof(*new));
+ struct label *new;
+ /* Make sure the label isn't already there */
+ for_each_label(*labels, new)
+ if (streq(new->label, label))
+ return;
+
+ new = xmalloc(sizeof(*new));
new->label = label;
new->next = *labels;
*labels = new;
@@ -94,6 +100,73 @@ struct node *name_node(struct node *node, char *name)
return node;
}
+struct node *merge_nodes(struct node *old_node, struct node *new_node)
+{
+ struct property *new_prop, *old_prop;
+ struct node *new_child, *old_child;
+ struct label *l;
+
+ /* Add new node labels to old node */
+ for_each_label(new_node->labels, l)
+ add_label(&old_node->labels, l->label);
+
+ /* Move properties from the new node to the old node. If there
+ * is a collision, replace the old value with the new */
+ while (new_node->proplist) {
+ /* Pop the property off the list */
+ new_prop = new_node->proplist;
+ new_node->proplist = new_prop->next;
+ new_prop->next = NULL;
+
+ /* Look for a collision, set new value if there is */
+ for_each_property(old_node, old_prop) {
+ if (streq(old_prop->name, new_prop->name)) {
+ /* Add new labels to old property */
+ for_each_label(new_prop->labels, l)
+ add_label(&old_prop->labels, l->label);
+
+ old_prop->val = new_prop->val;
+ free(new_prop);
+ new_prop = NULL;
+ break;
+ }
+ }
+
+ /* if no collision occurred, add property to the old node. */
+ if (new_prop)
+ add_property(old_node, new_prop);
+ }
+
+ /* Move the override child nodes into the primary node. If
+ * there is a collision, then merge the nodes. */
+ while (new_node->children) {
+ /* Pop the child node off the list */
+ new_child = new_node->children;
+ new_node->children = new_child->next_sibling;
+ new_child->parent = NULL;
+ new_child->next_sibling = NULL;
+
+ /* Search for a collision. Merge if there is */
+ for_each_child(old_node, old_child) {
+ if (streq(old_child->name, new_child->name)) {
+ merge_nodes(old_child, new_child);
+ new_child = NULL;
+ break;
+ }
+ }
+
+ /* if no collision occured, add child to the old node. */
+ if (new_child)
+ add_child(old_node, new_child);
+ }
+
+ /* The new node contents are now merged into the old node. Free
+ * the new node. */
+ free(new_node);
+
+ return old_node;
+}
+
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);