[RFC] Allow device tree to be modified by additonal device tree sections

Grant Likely grant.likely at secretlab.ca
Wed Feb 24 06:28:13 EST 2010


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 at secretlab.ca>
---

I haven't extensively tested this patch yet, and I haven't figured out yet
how to properly write the test cases, but I want to get this out there to
make sure I'm taking the right approach.

Cheers,
g.

 dtc-parser.y                   |   14 ++++++++-
 dtc.h                          |    1 +
 livetree.c                     |   63 ++++++++++++++++++++++++++++++++++++++++
 tests/redefine-nodes-test1.dts |    8 +++++
 tests/redefine-nodes-test2.dts |    9 ++++++
 tests/redefine-nodes-test3.dts |    9 ++++++
 tests/redefine-nodes-test4.dts |   11 +++++++
 tests/redefine-nodes-test5.dts |    9 ++++++
 tests/redefine-nodes-test6.dts |   11 +++++++
 tests/redefine-nodes-test7.dts |   13 ++++++++
 10 files changed, 147 insertions(+), 1 deletions(-)
 create mode 100644 tests/redefine-nodes-test1.dts
 create mode 100644 tests/redefine-nodes-test2.dts
 create mode 100644 tests/redefine-nodes-test3.dts
 create mode 100644 tests/redefine-nodes-test4.dts
 create mode 100644 tests/redefine-nodes-test5.dts
 create mode 100644 tests/redefine-nodes-test6.dts
 create mode 100644 tests/redefine-nodes-test7.dts

diff --git a/dtc-parser.y b/dtc-parser.y
index bd9e097..8f5c4a3 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -75,6 +75,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 %type <proplist> proplist
 
 %type <node> devicetree
+%type <node> devicetrees
 %type <node> nodedef
 %type <node> subnode
 %type <nodelist> subnodes
@@ -83,7 +84,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
 %%
 
 sourcefile:
-	  DT_V1 ';' memreserves devicetree
+	  DT_V1 ';' memreserves devicetrees
 		{
 			the_boot_info = build_boot_info($3, $4,
 							guess_boot_cpuid($4));
@@ -115,6 +116,17 @@ addr:
 		}
 	  ;
 
+devicetrees:
+	  /* empty */
+		{
+			$$ = NULL;
+		}
+	| devicetree devicetrees
+		{
+			$$ = merge_nodes($1, $2);
+		}
+	;
+
 devicetree:
 	  '/' nodedef
 		{
diff --git a/dtc.h b/dtc.h
index 5367198..815494a 100644
--- a/dtc.h
+++ b/dtc.h
@@ -164,6 +164,7 @@ struct property *reverse_properties(struct property *first);
 struct node *build_node(struct property *proplist, struct node *children);
 struct node *name_node(struct node *node, char *name, char *label);
 struct node *chain_node(struct node *first, struct node *list);
+struct node *merge_nodes(struct node *old_node, struct node *new_node);
 
 void add_property(struct node *node, struct property *prop);
 void add_child(struct node *parent, struct node *child);
diff --git a/livetree.c b/livetree.c
index aa0edf1..0691599 100644
--- a/livetree.c
+++ b/livetree.c
@@ -89,6 +89,69 @@ struct node *name_node(struct node *node, char *name, char * label)
 	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;
+
+	printf("Merge node, old_node:%s new_node:%s\n", old_node->name,
+		new_node ? new_node->name : "<NULL>" );
+	if (!new_node)
+		return old_node;
+
+	/* Move the override properties into the old node.  If there
+	 * is a collision, replace the old definition 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 (strcmp(old_prop->name, new_prop->name) == 0) {
+				old_prop->val = new_prop->val;
+				free(new_prop);
+				new_prop = NULL;
+				break;
+			}
+		}
+
+		/* Assuming no collision, add the 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 (strcmp(old_child->name, new_child->name) == 0) {
+				merge_nodes(old_child, new_child);
+				new_child = NULL;
+				break;
+			}
+		}
+
+		/* Assuming no collision, add the 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);
diff --git a/tests/redefine-nodes-test1.dts b/tests/redefine-nodes-test1.dts
new file mode 100644
index 0000000..a9ccaa2
--- /dev/null
+++ b/tests/redefine-nodes-test1.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/ {
+};
+
+/ {
+	prop = "new";
+};
diff --git a/tests/redefine-nodes-test2.dts b/tests/redefine-nodes-test2.dts
new file mode 100644
index 0000000..9e0b55e
--- /dev/null
+++ b/tests/redefine-nodes-test2.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+	prop = "old";
+};
+
+/ {
+	prop = "new";
+};
diff --git a/tests/redefine-nodes-test3.dts b/tests/redefine-nodes-test3.dts
new file mode 100644
index 0000000..cb135f3
--- /dev/null
+++ b/tests/redefine-nodes-test3.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+	prop1 = "old";
+};
+
+/ {
+	prop2 = "new";
+};
diff --git a/tests/redefine-nodes-test4.dts b/tests/redefine-nodes-test4.dts
new file mode 100644
index 0000000..a331c62
--- /dev/null
+++ b/tests/redefine-nodes-test4.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+	prop1 = "olda";
+	prop2 = "oldb";
+	prop3 = "oldc";
+};
+
+/ {
+	prop2 = "new";
+};
diff --git a/tests/redefine-nodes-test5.dts b/tests/redefine-nodes-test5.dts
new file mode 100644
index 0000000..b12de06
--- /dev/null
+++ b/tests/redefine-nodes-test5.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+/ {
+};
+
+/ {
+	subnode {
+	};
+};
diff --git a/tests/redefine-nodes-test6.dts b/tests/redefine-nodes-test6.dts
new file mode 100644
index 0000000..de05b49
--- /dev/null
+++ b/tests/redefine-nodes-test6.dts
@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+	subnode {
+	};
+};
+
+/ {
+	subnode {
+	};
+};
diff --git a/tests/redefine-nodes-test7.dts b/tests/redefine-nodes-test7.dts
new file mode 100644
index 0000000..7b9ab92
--- /dev/null
+++ b/tests/redefine-nodes-test7.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+	subnode {
+		prop1 = "val1";
+	};
+};
+
+/ {
+	subnode {
+		prop2 = "val2";
+	};
+};



More information about the devicetree-discuss mailing list