From mboxrd@z Thu Jan 1 00:00:00 1970 From: Grant Likely Subject: [RFC] Allow device tree to be modified by additonal device tree sections Date: Tue, 23 Feb 2010 12:28:13 -0700 Message-ID: <20100223192659.11939.42521.stgit@angua> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: devicetree-discuss-bounces+gldd-devicetree-discuss=m.gmane.org-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org Errors-To: devicetree-discuss-bounces+gldd-devicetree-discuss=m.gmane.org-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org To: david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org, jdl-CYoMK+44s/E@public.gmane.org, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org List-Id: devicetree@vger.kernel.org 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 --- 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 %type devicetree +%type devicetrees %type nodedef %type subnode %type 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 : "" ); + 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"; + }; +};