dtc(1): Update to upstream 006664a

Highlights:

- Passing "-" to -o will now cause output to go to stdout
- Path-based syntactic sugar for overlays is now accepted. This looks like:

/dts-v1/;
/plugin/;

&{/soc} {
    sid: eeprom@1c14000 {
        compatible = "allwinner,sun8i-h3-sid";
        reg = <0x1c14000 0x400>;
        status = "okay";
    };
};

MFC after:	3 days
This commit is contained in:
Kyle Evans 2018-04-13 18:04:51 +00:00
parent 55efba01c6
commit e69f393430
4 changed files with 107 additions and 19 deletions

View File

@ -30,7 +30,7 @@
.\"
.\" $FreeBSD$
.\"/
.Dd January 17, 2018
.Dd April 7, 2018
.Dt DTC 1
.Os
.Sh NAME
@ -275,7 +275,7 @@ tree when the overlay is applied.
.Pp
Much simpler syntactic sugar was later invented to simplify generating overlays.
Instead of creating targetted fragments manually, one can instead create a root
node that targets a label in the base node using the
node that targets a label in the base FDT using the
.Va &label
syntax supported in conventional DTS.
This will indicate that a fragment should be generated for the node, with the
@ -284,6 +284,19 @@ given
being the target, and the properties and child nodes will be used as the
__overlay__.
.Pp
Additionally, a path-based version of this syntactic sugar is supported.
A root node may target a path in the base FDT using a name of the form
.Va &{/path} .
A fragment will be generated for the node as it is in the
.Va &label
case, except the
.Va target-path
property will be set to
.Va /path
and no
.Va target
will be set.
.Pp
Both conventional overlays and the later-added syntactic sugar are supported.
.Pp
Overlay blobs can be applied at boot time by setting

View File

@ -171,11 +171,14 @@ main(int argc, char **argv)
case 'o':
{
outfile_name = optarg;
outfile = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (outfile == -1)
if (strcmp(outfile_name, "-") != 0)
{
perror("Unable to open output file");
return EXIT_FAILURE;
outfile = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (outfile == -1)
{
perror("Unable to open output file");
return EXIT_FAILURE;
}
}
break;
}

View File

@ -727,14 +727,32 @@ node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
return n;
}
void
node::visit(std::function<void(node&)> fn)
node::visit_behavior
node::visit(std::function<visit_behavior(node&, node*)> fn, node *parent)
{
fn(*this);
for (auto &&c : children)
visit_behavior behavior;
behavior = fn(*this, parent);
if (behavior == VISIT_BREAK)
{
c->visit(fn);
return VISIT_BREAK;
}
else if (behavior != VISIT_CONTINUE)
{
for (auto &&c : children)
{
behavior = c->visit(fn, this);
// Any status other than VISIT_RECURSE stops our execution and
// bubbles up to our caller. The caller may then either continue
// visiting nodes that are siblings to this one or completely halt
// visiting.
if (behavior != VISIT_RECURSE)
{
return behavior;
}
}
}
// Continue recursion by default
return VISIT_RECURSE;
}
node::node(input_buffer &structs, input_buffer &strings) : valid(true)
@ -1319,7 +1337,7 @@ device_tree::resolve_cross_references(uint32_t &phandle)
phandle_set.insert({&i.val, i});
}
std::vector<std::reference_wrapper<fixup>> sorted_phandles;
root->visit([&](node &n) {
root->visit([&](node &n, node *parent) {
for (auto &p : n.properties())
{
for (auto &v : *p)
@ -1331,7 +1349,9 @@ device_tree::resolve_cross_references(uint32_t &phandle)
}
}
}
});
// Allow recursion
return node::VISIT_RECURSE;
}, nullptr);
assert(sorted_phandles.size() == fixups.size());
for (auto &i : sorted_phandles)
@ -1471,9 +1491,24 @@ device_tree::parse_file(text_input_buffer &input,
else if (input.consume('&'))
{
input.next_token();
string name = input.parse_node_name();
string name;
bool name_is_path_reference = false;
// This is to deal with names intended as path references, e.g. &{/path}.
// While it may make sense in a non-plugin context, we don't support such
// usage at this time.
if (input.consume('{') && is_plugin)
{
name = input.parse_to('}');
input.consume('}');
name_is_path_reference = true;
}
else
{
name = input.parse_node_name();
}
input.next_token();
n = node::parse(input, std::move(name), string_set(), string(), &defines);
n->name_is_path_reference = name_is_path_reference;
}
else
{
@ -1702,11 +1737,21 @@ device_tree::create_fragment_wrapper(node_ptr &node, int &fragnum)
node_ptr newroot = node::create_special_node("", symbols);
node_ptr wrapper = node::create_special_node("__overlay__", symbols);
// Generate the fragment with target = <&name>
// Generate the fragment with $propname = <&name>
property_value v;
std::string propname;
v.string_data = node->name;
v.type = property_value::PHANDLE;
auto prop = std::make_shared<property>(std::string("target"));
if (!node->name_is_path_reference)
{
propname = "target";
v.type = property_value::PHANDLE;
}
else
{
propname = "target-path";
v.type = property_value::STRING;
}
auto prop = std::make_shared<property>(std::string(propname));
prop->add_value(v);
symbols.push_back(prop);

View File

@ -408,6 +408,10 @@ class node
* The name of the node.
*/
std::string name;
/**
* The name of the node is a path reference.
*/
bool name_is_path_reference = false;
/**
* The unit address of the node, which is optionally written after the
* name followed by an at symbol.
@ -421,6 +425,25 @@ class node
* Iterator type for child nodes.
*/
typedef std::vector<node_ptr>::iterator child_iterator;
/**
* Recursion behavior to be observed for visiting
*/
enum visit_behavior
{
/**
* Recurse as normal through the rest of the tree.
*/
VISIT_RECURSE,
/**
* Continue recursing through the device tree, but do not
* recurse through this branch of the tree any further.
*/
VISIT_CONTINUE,
/**
* Immediately halt the visit. No further nodes will be visited.
*/
VISIT_BREAK
};
private:
/**
* Adaptor to use children in range-based for loops.
@ -635,9 +658,13 @@ class node
*/
void write_dts(FILE *file, int indent);
/**
* Recursively visit this node and then its children.
* Recursively visit this node and then its children based on the
* callable's return value. The callable may return VISIT_BREAK
* immediately halt all recursion and end the visit, VISIT_CONTINUE to
* not recurse into the current node's children, or VISIT_RECURSE to recurse
* through children as expected. parent will be passed to the callable.
*/
void visit(std::function<void(node&)>);
visit_behavior visit(std::function<visit_behavior(node&, node*)>, node *parent);
};
/**