diff --git a/usr.bin/dtc/dtc.1 b/usr.bin/dtc/dtc.1 index 97247876c754..050bb7056855 100644 --- a/usr.bin/dtc/dtc.1 +++ b/usr.bin/dtc/dtc.1 @@ -51,6 +51,7 @@ .Op Fl p Ar bytes .Op Fl V Ar blob_version .Op Fl W Ar [no-]checker_name +.Op Fl P Ar predefined_properties .Ar input_file .Sh DESCRIPTION The @@ -132,6 +133,22 @@ The ASCII representation of the FDT. .El .It Fl o Ar output_file The file to which to write the output. +.It Fl P Ar predefined_macro +Defines a macro, in the form +.Ar name=value +or +.Ar name +to be used for device tree source files that contain conditional components. +This tool supports two extensions to the standard to support conditional +compilation of device trees. +The first is an +.Ar /include/if [property]/ "file.dts" +directive that is allowed at the start of a file and which will only include +the specified file if it the specified property is passed with this flag. +The second is the +.Ar $NAME +format for property values. +These allow property value to be specified on the command line. .It Fl R Ar entries The number of empty reservation table entries to pad the table with. This is diff --git a/usr.bin/dtc/dtc.cc b/usr.bin/dtc/dtc.cc index cffb3eb3cc32..c04f01616805 100644 --- a/usr.bin/dtc/dtc.cc +++ b/usr.bin/dtc/dtc.cc @@ -100,7 +100,7 @@ main(int argc, char **argv) clock_t c0 = clock(); class device_tree tree; fdt::checking::check_manager checks; - const char *options = "hqI:O:o:V:d:R:S:p:b:fisvH:W:E:D"; + const char *options = "hqI:O:o:V:d:R:S:p:b:fisvH:W:E:DP:"; // Don't forget to update the man page if any more options are added. while ((ch = getopt(argc, argv, options)) != -1) @@ -267,6 +267,13 @@ main(int argc, char **argv) case 'p': tree.set_blob_padding(strtoll(optarg, 0, 10)); break; + case 'P': + if (!tree.parse_define(optarg)) + { + fprintf(stderr, "Invalid predefine value %s\n", + optarg); + } + break; default: fprintf(stderr, "Unknown option %c\n", ch); return EXIT_FAILURE; diff --git a/usr.bin/dtc/fdt.cc b/usr.bin/dtc/fdt.cc index 6f27c9cb0b5f..eb944fca2cc6 100644 --- a/usr.bin/dtc/fdt.cc +++ b/usr.bin/dtc/fdt.cc @@ -382,13 +382,45 @@ property::property(input_buffer &structs, input_buffer &strings) values.push_back(v); } -property::property(input_buffer &input, string k, string l) : key(k), label(l), - valid(true) +void property::parse_define(input_buffer &input, define_map *defines) +{ + input.consume('$'); + if (!defines) + { + input.parse_error("No predefined properties to match name\n"); + valid = false; + return; + } + string name = string::parse_property_name(input); + define_map::iterator found; + if ((name == string()) || + ((found = defines->find(name)) == defines->end())) + { + input.parse_error("Undefined property name\n"); + valid = false; + return; + } + values.push_back((*found).second->values[0]); +} + +property::property(input_buffer &input, + string k, + string l, + bool semicolonTerminated, + define_map *defines) : key(k), label(l), valid(true) { do { input.next_token(); switch (input[0]) { + case '$': + { + parse_define(input, defines); + if (valid) + { + break; + } + } default: input.parse_error("Invalid property value."); valid = false; @@ -412,7 +444,7 @@ property::property(input_buffer &input, string k, string l) : key(k), label(l), } input.next_token(); } while (input.consume(',')); - if (!input.consume(';')) + if (semicolonTerminated && !input.consume(';')) { input.parse_error("Expected ; at end of property"); valid = false; @@ -432,9 +464,10 @@ property::parse_dtb(input_buffer &structs, input_buffer &strings) } property* -property::parse(input_buffer &input, string key, string label) +property::parse(input_buffer &input, string key, string label, + bool semicolonTerminated, define_map *defines) { - property *p = new property(input, key, label); + property *p = new property(input, key, label, semicolonTerminated, defines); if (!p->valid) { delete p; @@ -591,7 +624,7 @@ node::node(input_buffer &structs, input_buffer &strings) : valid(true) return; } -node::node(input_buffer &input, string n, string l, string a) : +node::node(input_buffer &input, string n, string l, string a, define_map *defines) : label(l), name(n), unit_address(a), valid(true) { if (!input.consume('{')) @@ -628,7 +661,7 @@ node::node(input_buffer &input, string n, string l, string a) : if (input.consume('=')) { property *p= property::parse(input, child_name, - child_label); + child_label, true, defines); if (p == 0) { valid = false; @@ -641,7 +674,7 @@ node::node(input_buffer &input, string n, string l, string a) : else if (!is_property && input[0] == ('{')) { node *child = node::parse(input, child_name, - child_label, child_address); + child_label, child_address, defines); if (child) { children.push_back(child); @@ -693,9 +726,13 @@ node::sort() } node* -node::parse(input_buffer &input, string name, string label, string address) +node::parse(input_buffer &input, + string name, + string label, + string address, + define_map *defines) { - node *n = new node(input, name, label, address); + node *n = new node(input, name, label, address, defines); if (!n->valid) { delete n; @@ -1008,7 +1045,7 @@ device_tree::parse_roots(input_buffer &input, std::vector &roots) while (valid && input.consume('/')) { input.next_token(); - node *n = node::parse(input, string("", 1)); + node *n = node::parse(input, string("", 1), string(), string(), &defines); if (n) { roots.push_back(n); @@ -1241,6 +1278,18 @@ device_tree::parse_dts(const char *fn, FILE *depfile) input.next_token(); while(input.consume("/include/")) { + bool reallyInclude = true; + if (input.consume("if ")) + { + input.next_token(); + string name = string::parse_property_name(input); + // XXX: Error handling + if (defines.find(name) == defines.end()) + { + reallyInclude = false; + } + input.consume('/'); + } input.next_token(); if (!input.consume('"')) { @@ -1259,6 +1308,14 @@ device_tree::parse_dts(const char *fn, FILE *depfile) include_file[dir_length] = '/'; memcpy(include_file+dir_length+1, file, length); include_file[dir_length+length+1] = 0; + + input.consume(include_file+dir_length+1); + input.consume('"'); + if (!reallyInclude) + { + continue; + } + input_buffer *include_buffer = buffer_for_file(include_file); if (include_buffer == 0) @@ -1292,8 +1349,6 @@ device_tree::parse_dts(const char *fn, FILE *depfile) return; } input_buffer &include = *include_buffer; - input.consume(include_file+dir_length+1); - input.consume('"'); free((void*)include_file); if (!read_header) @@ -1361,6 +1416,33 @@ device_tree::~device_tree() delete buffers.back(); buffers.pop_back(); } + for (define_map::iterator i=defines.begin(), e=defines.end() ; + i!=e ; ++i) + { + delete i->second; + } +} + +bool device_tree::parse_define(const char *def) +{ + char *val = strchr(def, '='); + if (!val) + { + if (strlen(def) != 0) + { + string name(def); + defines[name]; + return true; + } + return false; + } + string name(def, val-def); + val++; + input_buffer in = input_buffer(val, strlen(val)); + property *p = property::parse(in, name, string(), false); + if (p) + defines[name] = p; + return p; } } // namespace fdt diff --git a/usr.bin/dtc/fdt.hh b/usr.bin/dtc/fdt.hh index b00ea48063a6..3ac10847e5fa 100644 --- a/usr.bin/dtc/fdt.hh +++ b/usr.bin/dtc/fdt.hh @@ -48,6 +48,8 @@ class string_table; namespace fdt { +class property; +typedef std::map define_map; /** * Properties may contain a number of different value, each with a different * label. This class encapsulates a single value. @@ -262,6 +264,10 @@ class property * follow their interpretation for compatibility. */ void parse_reference(input_buffer &input); + /** + * Parse a predefined macro definition for a property. + */ + void parse_define(input_buffer &input, define_map *defines); /** * Constructs a new property from two input buffers, pointing to the * struct and strings tables in the device tree blob, respectively. @@ -272,7 +278,11 @@ class property /** * Parses a new property from the input buffer. */ - property(input_buffer &input, string k, string l); + property(input_buffer &input, + string k, + string l, + bool terminated, + define_map *defines); public: /** * Creates an empty property. @@ -298,7 +308,9 @@ class property */ static property* parse(input_buffer &input, string key, - string label=string()); + string label=string(), + bool semicolonTerminated=true, + define_map *defines=0); /** * Iterator type used for accessing the values of a property. */ @@ -398,7 +410,7 @@ class node * node. The name, and optionally label and unit address, should have * already been parsed. */ - node(input_buffer &input, string n, string l, string a); + node(input_buffer &input, string n, string l, string a, define_map*); /** * Comparison function for properties, used when sorting the properties * vector. Orders the properties based on their names. @@ -476,7 +488,8 @@ class node static node* parse(input_buffer &input, string name, string label=string(), - string address=string()); + string address=string(), + define_map *defines=0); /** * Factory method for constructing a new node. Attempts to parse a * node in DTB format from the input, and returns it on success. On @@ -616,6 +629,10 @@ class device_tree * must be freed separately. */ std::vector include_paths; + /** + * Dictionary of predefined macros provided on the command line. + */ + define_map defines; /** * The default boot CPU, specified in the device tree header. */ @@ -773,6 +790,10 @@ class device_tree { blob_padding = p; } + /** + * Parses a predefined macro value. + */ + bool parse_define(const char *def); }; } // namespace fdt