* [PATCH RFC 1/5] dtc: Add helpers for various message levels
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2014-02-20 18:06 ` Tomasz Figa
[not found] ` <1392919611-10746-2-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-02-20 18:06 ` [PATCH RFC 2/5] dtc: livetree: Add more tree parsing helpers Tomasz Figa
` (5 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: Tomasz Figa @ 2014-02-20 18:06 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
Tomasz Figa
This patch adds three helper macros to print errors, warnings and
informational messages using standard format.
Signed-off-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
dtc.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/dtc.h b/dtc.h
index 20de073..e95bed7 100644
--- a/dtc.h
+++ b/dtc.h
@@ -43,6 +43,9 @@
#define debug(fmt,args...)
#endif
+#define pr_err(...) fprintf (stderr, "ERROR: " __VA_ARGS__)
+#define pr_warn(...) fprintf (stderr, "WARNING: " __VA_ARGS__)
+#define pr_info(...) fprintf (stderr, "INFO: " __VA_ARGS__)
#define DEFAULT_FDT_VERSION 17
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH RFC 2/5] dtc: livetree: Add more tree parsing helpers
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-02-20 18:06 ` [PATCH RFC 1/5] dtc: Add helpers for various message levels Tomasz Figa
@ 2014-02-20 18:06 ` Tomasz Figa
[not found] ` <1392919611-10746-3-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-02-20 18:06 ` [PATCH RFC 3/5] Implement DT schema checker using hybrid approach Tomasz Figa
` (4 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: Tomasz Figa @ 2014-02-20 18:06 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
Tomasz Figa
This patch extends the set of parsing helpers available in dtc with
string and phandle parsing.
Signed-off-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
dtc.h | 28 ++++++++
livetree.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 258 insertions(+)
diff --git a/dtc.h b/dtc.h
index e95bed7..9ce9d12 100644
--- a/dtc.h
+++ b/dtc.h
@@ -163,6 +163,13 @@ struct node {
struct label *labels;
};
+#define MAX_PHANDLE_ARGS 16
+struct of_phandle_args {
+ struct node *np;
+ int args_count;
+ uint32_t args[MAX_PHANDLE_ARGS];
+};
+
#define for_each_label_withdel(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)
@@ -184,6 +191,11 @@ struct node {
for_each_child_withdel(n, c) \
if (!(c)->deleted)
+#define for_each_propval_string(p, s) \
+ for (s = propval_next_string(p, NULL); \
+ s; \
+ s = propval_next_string(p, s))
+
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
@@ -208,6 +220,22 @@ void delete_node(struct node *node);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
+int propval_string_count(struct node *np, struct property *prop);
+const char *propval_next_string(struct property *prop, const char *cur);
+int propval_match_string(struct property *prop, const char *string);
+struct node *propval_parse_phandle(struct node *root,
+ struct property *prop, int index);
+int propval_parse_phandle_with_args(struct node *root,
+ struct property *prop,
+ const char *cells_name, int index,
+ struct of_phandle_args *out_args);
+int propval_parse_phandle_with_fixed_args(struct node *root,
+ struct property *prop, int cell_count,
+ int index,
+ struct of_phandle_args *out_args);
+int propval_count_phandle_with_args(struct node *root,
+ struct property *prop,
+ const char *cells_name);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
diff --git a/livetree.c b/livetree.c
index b61465f..015ed06 100644
--- a/livetree.c
+++ b/livetree.c
@@ -377,6 +377,230 @@ cell_t propval_cell(struct property *prop)
return fdt32_to_cpu(*((cell_t *)prop->val.val));
}
+int propval_string_count(struct node *np, struct property *prop)
+{
+ int i = 0;
+ size_t l = 0, total = 0;
+ const char *p;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->val.val)
+ return -ENODATA;
+ if (strnlen(prop->val.val, prop->val.len) >= prop->val.len)
+ return -EILSEQ;
+
+ p = prop->val.val;
+
+ for (i = 0; total < prop->val.len; total += l, p += l, i++)
+ l = strlen(p) + 1;
+
+ return i;
+}
+
+const char *propval_next_string(struct property *prop, const char *cur)
+{
+ const char *curv = cur;
+
+ if (!prop)
+ return NULL;
+
+ if (!cur)
+ return prop->val.val;
+
+ curv += strlen(cur) + 1;
+ if (curv >= prop->val.val + prop->val.len)
+ return NULL;
+
+ return curv;
+}
+
+int propval_match_string(struct property *prop, const char *string)
+{
+ size_t l;
+ int i;
+ const char *p, *end;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->val.val)
+ return -ENODATA;
+
+ p = prop->val.val;
+ end = p + prop->val.len;
+
+ for (i = 0; p < end; i++, p += l) {
+ l = strlen(p) + 1;
+ if (p + l > end)
+ return -EILSEQ;
+ if (strcmp(string, p) == 0)
+ return i; /* Found it; return index */
+ }
+ return -ENODATA;
+}
+
+static int parse_phandle_with_args(struct node *root,
+ struct property *prop,
+ const char *cells_name,
+ int cell_count, int index,
+ struct of_phandle_args *out_args)
+{
+ const cell_t *list, *list_end;
+ int rc = 0, size, cur_index = 0;
+ uint32_t count = 0;
+ struct node *node = NULL;
+ cell_t phandle;
+
+ /* Retrieve the phandle list property */
+ size = prop->val.len;
+ list = (const cell_t *)prop->val.val;
+ if (!list)
+ return -ENOENT;
+ list_end = list + size / sizeof(*list);
+
+ /* Loop over the phandles until all the requested entry is found */
+ while (list < list_end) {
+ rc = -EINVAL;
+ count = 0;
+
+ /*
+ * If phandle is 0, then it is an empty entry with no
+ * arguments. Skip forward to the next entry.
+ */
+ phandle = fdt32_to_cpu(*list++);
+ if (phandle) {
+ /*
+ * Find the provider node and parse the #*-cells
+ * property to determine the argument length.
+ *
+ * This is not needed if the cell count is hard-coded
+ * (i.e. cells_name not set, but cell_count is set),
+ * except when we're going to return the found node
+ * below.
+ */
+ if (cells_name || cur_index == index) {
+ node = get_node_by_phandle(root, phandle);
+ if (!node) {
+ pr_err("could not find phandle %u\n",
+ phandle);
+ goto err;
+ }
+ }
+
+ if (cells_name) {
+ struct property *cells_prop;
+
+ cells_prop = get_property(node, cells_name);
+ if (!cells_prop) {
+ pr_err("could not get %s for %s\n",
+ cells_name,
+ node->fullpath);
+ goto err;
+ }
+
+ count = propval_cell(cells_prop);
+ } else {
+ count = cell_count;
+ }
+
+ /*
+ * Make sure that the arguments actually fit in the
+ * remaining property data length
+ */
+ if (list + count > list_end) {
+ pr_err("arguments longer than property\n");
+ goto err;
+ }
+ }
+
+ /*
+ * All of the error cases above bail out of the loop, so at
+ * this point, the parsing is successful. If the requested
+ * index matches, then fill the out_args structure and return,
+ * or return -ENOENT for an empty entry.
+ */
+ rc = -ENOENT;
+ if (cur_index == index) {
+ if (!phandle)
+ goto err;
+
+ if (out_args) {
+ int i;
+ if (count > MAX_PHANDLE_ARGS) {
+ pr_warn("argument count higher than MAX_PHANDLE_ARGS\n");
+ count = MAX_PHANDLE_ARGS;
+ }
+ out_args->np = node;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++)
+ out_args->args[i] = fdt32_to_cpu(*list++);
+ }
+
+ /* Found it! return success */
+ return 0;
+ }
+
+ node = NULL;
+ list += count;
+ cur_index++;
+ }
+
+ /*
+ * Unlock node before returning result; will be one of:
+ * -ENOENT : index is for empty phandle
+ * -EINVAL : parsing error on data
+ * [1..n] : Number of phandle (count mode; when index = -1)
+ */
+ rc = index < 0 ? cur_index : -ENOENT;
+ err:
+ return rc;
+}
+
+struct node *propval_parse_phandle(struct node *root,
+ struct property *prop, int index)
+{
+ struct of_phandle_args args;
+
+ if (index < 0)
+ return NULL;
+
+ if (parse_phandle_with_args(root, prop, NULL, 0,
+ index, &args))
+ return NULL;
+
+ return args.np;
+}
+
+int propval_parse_phandle_with_args(struct node *root,
+ struct property *prop,
+ const char *cells_name, int index,
+ struct of_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+ return parse_phandle_with_args(root, prop, cells_name, 0,
+ index, out_args);
+}
+
+int propval_parse_phandle_with_fixed_args(struct node *root,
+ struct property *prop, int cell_count,
+ int index,
+ struct of_phandle_args *out_args)
+{
+ if (index < 0)
+ return -EINVAL;
+ return parse_phandle_with_args(root, prop, NULL, cell_count,
+ index, out_args);
+}
+
+int propval_count_phandle_with_args(struct node *root,
+ struct property *prop,
+ const char *cells_name)
+{
+ return parse_phandle_with_args(root, prop, cells_name, 0, -1,
+ NULL);
+}
+
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node)
{
@@ -456,6 +680,12 @@ struct node *get_node_by_path(struct node *tree, const char *path)
while (path[0] == '/')
path++;
+ if (!(*path)) {
+ if (tree->deleted)
+ return NULL;
+ return tree;
+ }
+
p = strchr(path, '/');
for_each_child(tree, child) {
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH RFC 3/5] Implement DT schema checker using hybrid approach
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-02-20 18:06 ` [PATCH RFC 1/5] dtc: Add helpers for various message levels Tomasz Figa
2014-02-20 18:06 ` [PATCH RFC 2/5] dtc: livetree: Add more tree parsing helpers Tomasz Figa
@ 2014-02-20 18:06 ` Tomasz Figa
[not found] ` <1392919611-10746-4-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-02-20 18:06 ` [PATCH RFC 4/5] Add sample C-based generic bindings Tomasz Figa
` (3 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: Tomasz Figa @ 2014-02-20 18:06 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
Tomasz Figa
This patch adds a proof of concept framework to implement schema checker
using a combined C and DTSS based approach.
Complex and generic bindings can be implemented directly in C and then
instantiated from simple device-specific bindings using DTS-like DTSS
language.
This is based on Stephen Warren's C based DT schema checker proof of
concept patch.
[original C based DT schema checker proof of concept]
Signed-off-by: Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
[further development into hybrid solution]
Signed-off-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
Makefile | 2 +-
Makefile.dtc | 5 +-
checks.c | 15 +++
dtc.c | 17 ++-
dtc.h | 26 +++++
dtss-lexer.l | 291 +++++++++++++++++++++++++++++++++++++++++++++++
dtss-parser.y | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
schemas/schema.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++
schemas/schema.h | 89 +++++++++++++++
srcpos.h | 2 +
treesource.c | 22 ++++
11 files changed, 1117 insertions(+), 4 deletions(-)
create mode 100644 dtss-lexer.l
create mode 100644 dtss-parser.y
create mode 100644 schemas/schema.c
create mode 100644 schemas/schema.h
diff --git a/Makefile b/Makefile
index 86f5ab3..0625fb8 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ EXTRAVERSION =
LOCAL_VERSION =
CONFIG_LOCALVERSION =
-CPPFLAGS = -I libfdt -I .
+CPPFLAGS = -I libfdt -I . -I schemas
WARNINGS = -Werror -Wall -Wpointer-arith -Wcast-qual -Wnested-externs \
-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wshadow
CFLAGS = -g -Os -fPIC -Werror $(WARNINGS)
diff --git a/Makefile.dtc b/Makefile.dtc
index bece49b..bf19564 100644
--- a/Makefile.dtc
+++ b/Makefile.dtc
@@ -12,7 +12,8 @@ DTC_SRCS = \
livetree.c \
srcpos.c \
treesource.c \
- util.c
+ util.c \
+ schemas/schema.c
-DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
+DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c dtss-lexer.lex.c dtss-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
diff --git a/checks.c b/checks.c
index 47eda65..7c85fcf 100644
--- a/checks.c
+++ b/checks.c
@@ -19,6 +19,7 @@
*/
#include "dtc.h"
+#include "schemas/schema.h"
#ifdef TRACE_CHECKS
#define TRACE(c, ...) \
@@ -651,6 +652,18 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
}
TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+/*
+ * Schema checks
+ */
+
+static void check_schema(struct check *c, struct node *dt,
+ struct node *node)
+{
+ if (schema_check_node(dt, node))
+ FAIL(c, "Schema check failed for %s", node->fullpath);
+}
+NODE_ERROR(schema, NULL);
+
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,
@@ -669,6 +682,8 @@ static struct check *check_table[] = {
&avoid_default_addr_size,
&obsolete_chosen_interrupt_controller,
+ &schema,
+
&always_fail,
};
diff --git a/dtc.c b/dtc.c
index d36ccdc..1a5913b 100644
--- a/dtc.c
+++ b/dtc.c
@@ -20,6 +20,7 @@
#include "dtc.h"
#include "srcpos.h"
+#include "schemas/schema.h"
/*
* Command line options
@@ -49,7 +50,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
/* Usage related data. */
static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:x:hv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@@ -67,6 +68,7 @@ static struct option const usage_long_opts[] = {
{"phandle", a_argument, NULL, 'H'},
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
+ {"schema", a_argument, NULL, 'x'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@@ -97,6 +99,7 @@ static const char * const usage_opts_help[] = {
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
+ "\n\tUse schema file"
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@@ -105,10 +108,12 @@ static const char * const usage_opts_help[] = {
int main(int argc, char *argv[])
{
struct boot_info *bi;
+ struct boot_info *bi_schema;
const char *inform = "dts";
const char *outform = "dts";
const char *outname = "-";
const char *depname = NULL;
+ const char *schema = NULL;
bool force = false, sort = false;
const char *arg;
int opt;
@@ -185,6 +190,10 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;
+ case 'x':
+ schema = optarg;
+ break;
+
case 'h':
usage(NULL);
default:
@@ -220,6 +229,12 @@ int main(int argc, char *argv[])
else
die("Unknown input format \"%s\"\n", inform);
+ if (schema) {
+ bi_schema = schema_from_source(schema);
+ //dt_to_source(stdout, bi_schema);
+ build_schema_list(bi_schema);
+ }
+
if (depfile) {
fputc('\n', depfile);
fclose(depfile);
diff --git a/dtc.h b/dtc.h
index 9ce9d12..19d2d24 100644
--- a/dtc.h
+++ b/dtc.h
@@ -135,21 +135,43 @@ struct label {
struct label *next;
};
+enum {
+ PROPERTY_DATA,
+ PROPERTY_USE,
+ PROPERTY_REQUIRE,
+ PROPERTY_MATCH,
+};
+
+#define PROPERTY_FLAG_OPTIONAL (1 << 0)
+
struct property {
bool deleted;
char *name;
struct data val;
+ unsigned int type;
+ unsigned int flags;
struct property *next;
struct label *labels;
};
+enum {
+ NODE_DATA,
+ NODE_USE,
+ NODE_REQUIRE,
+};
+
+#define NODE_FLAG_OPTIONAL (1 << 0)
+#define NODE_FLAG_INCOMPLETE (1 << 1)
+
struct node {
bool deleted;
char *name;
struct property *proplist;
struct node *children;
+ int type;
+ unsigned int flags;
struct node *parent;
struct node *next_sibling;
@@ -297,4 +319,8 @@ struct boot_info *dt_from_source(const char *f);
struct boot_info *dt_from_fs(const char *dirname);
+/* Schema source */
+
+struct boot_info *schema_from_source(const char *fname);
+
#endif /* _DTC_H */
diff --git a/dtss-lexer.l b/dtss-lexer.l
new file mode 100644
index 0000000..aee41f6
--- /dev/null
+++ b/dtss-lexer.l
@@ -0,0 +1,291 @@
+/*
+ * (C) Copyright David Gibson <dwg-8fk3Idey6ehBDgjK7y7TUQ@public.gmane.org>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+%option noyywrap nounput noinput never-interactive prefix="dtss_yy"
+
+%x INCLUDE
+%x BYTESTRING
+%x PROPNODENAME
+%s V1
+
+PROPNODECHAR [a-zA-Z0-9,._+*$#?^@-]
+PATHCHAR ({PROPNODECHAR}|[/])
+LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+CHAR_LITERAL '([^']|\\')*'
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
+
+%{
+#include "dtc.h"
+#include "srcpos.h"
+
+#define DTSS_YYLTYPE struct srcpos
+
+#include "dtss-parser.tab.h"
+
+DTSS_YYLTYPE dtss_yylloc;
+extern bool treesource_error;
+
+/* CAUTION: this will stop working if we ever use dtss_yyless() or dtss_yyunput() */
+#define YY_USER_ACTION \
+ { \
+ srcpos_update(&dtss_yylloc, dtss_yytext, dtss_yyleng); \
+ }
+
+/* #define LEXDEBUG 1 */
+
+#ifdef LEXDEBUG
+#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+#else
+#define DPRINT(fmt, ...) do { } while (0)
+#endif
+
+static int dts_version = 1;
+
+#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
+ BEGIN(V1); \
+
+static void push_input_file(const char *filename);
+static bool pop_input_file(void);
+static void lexical_error(const char *fmt, ...);
+%}
+
+%%
+<*>"/include/"{WS}*{STRING} {
+ char *name = strchr(dtss_yytext, '\"') + 1;
+ dtss_yytext[dtss_yyleng-1] = '\0';
+ push_input_file(name);
+ }
+
+<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
+ char *line, *tmp, *fn;
+ /* skip text before line # */
+ line = dtss_yytext;
+ while (!isdigit(*line))
+ line++;
+ /* skip digits in line # */
+ tmp = line;
+ while (!isspace(*tmp))
+ tmp++;
+ /* "NULL"-terminate line # */
+ *tmp = '\0';
+ /* start of filename */
+ fn = strchr(tmp + 1, '"') + 1;
+ /* strip trailing " from filename */
+ tmp = strchr(fn, '"');
+ *tmp = 0;
+ /* -1 since #line is the number of the next line */
+ srcpos_set_line(xstrdup(fn), atoi(line) - 1);
+ }
+
+<*><<EOF>> {
+ if (!pop_input_file()) {
+ yyterminate();
+ }
+ }
+
+<*>{STRING} {
+ DPRINT("String: %s\n", dtss_yytext);
+ dtss_yylval.data = data_copy_escape_string(dtss_yytext+1,
+ dtss_yyleng-2);
+ return DT_STRING;
+ }
+
+<*>"/dtss-v1/" {
+ DPRINT("Keyword: /dtss-v1/\n");
+ dts_version = 0x8001;
+ BEGIN_DEFAULT();
+ return DTSS_V1;
+ }
+
+<*>"/bits/" {
+ DPRINT("Keyword: /bits/\n");
+ BEGIN_DEFAULT();
+ return DT_BITS;
+ }
+
+<*>"/delete-property/" {
+ DPRINT("Keyword: /delete-property/\n");
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ return DT_DEL_PROP;
+ }
+
+<*>"/delete-node/" {
+ DPRINT("Keyword: /delete-node/\n");
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ return DT_DEL_NODE;
+ }
+
+<*>"/match/" {
+ DPRINT("Keyword: /match/\n");
+ return DTSS_MATCH;
+ }
+
+<*>"/require/" {
+ DPRINT("Keyword: /require/\n");
+ return DTSS_REQUIRE;
+ }
+
+<*>"/use/" {
+ DPRINT("Keyword: /use/\n");
+ return DTSS_USE;
+ }
+
+<*>"/incomplete/" {
+ DPRINT("Keyword: /incomplete/\n");
+ return DTSS_INCOMPLETE;
+ }
+
+<*>"/optional/" {
+ DPRINT("Keyword: /optional/\n");
+ return DTSS_OPTIONAL;
+ }
+
+<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
+ char *e;
+ DPRINT("Integer Literal: '%s'\n", yytext);
+
+ errno = 0;
+ dtss_yylval.integer = strtoull(yytext, &e, 0);
+
+ assert(!(*e) || !e[strspn(e, "UL")]);
+
+ if (errno == ERANGE)
+ lexical_error("Integer literal '%s' out of range",
+ yytext);
+ else
+ /* ERANGE is the only strtoull error triggerable
+ * by strings matching the pattern */
+ assert(errno == 0);
+ return DT_LITERAL;
+ }
+
+<*>{CHAR_LITERAL} {
+ struct data d;
+ DPRINT("Character literal: %s\n", yytext);
+
+ d = data_copy_escape_string(yytext+1, yyleng-2);
+ if (d.len == 1) {
+ lexical_error("Empty character literal");
+ dtss_yylval.integer = 0;
+ return DT_CHAR_LITERAL;
+ }
+
+ dtss_yylval.integer = (unsigned char)d.val[0];
+
+ if (d.len > 2)
+ lexical_error("Character literal has %d"
+ " characters instead of 1",
+ d.len - 1);
+
+ return DT_CHAR_LITERAL;
+ }
+
+<*>\&{LABEL} { /* label reference */
+ DPRINT("Ref: %s\n", dtss_yytext+1);
+ dtss_yylval.labelref = xstrdup(dtss_yytext+1);
+ return DT_REF;
+ }
+
+<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
+ dtss_yytext[dtss_yyleng-1] = '\0';
+ DPRINT("Ref: %s\n", dtss_yytext+2);
+ dtss_yylval.labelref = xstrdup(dtss_yytext+2);
+ return DT_REF;
+ }
+
+<BYTESTRING>[0-9a-fA-F]{2} {
+ dtss_yylval.byte = strtol(dtss_yytext, NULL, 16);
+ DPRINT("Byte: %02x\n", (int)dtss_yylval.byte);
+ return DT_BYTE;
+ }
+
+<BYTESTRING>"]" {
+ DPRINT("/BYTESTRING\n");
+ BEGIN_DEFAULT();
+ return ']';
+ }
+
+<PROPNODENAME>\\?{PROPNODECHAR}+ {
+ DPRINT("PropNodeName: %s\n", dtss_yytext);
+ dtss_yylval.propnodename = xstrdup((dtss_yytext[0] == '\\') ?
+ dtss_yytext + 1 : dtss_yytext);
+ BEGIN_DEFAULT();
+ return DT_PROPNODENAME;
+ }
+
+<*>{WS}+ /* eat whitespace */
+<*>{COMMENT}+ /* eat C-style comments */
+<*>{LINECOMMENT}+ /* eat C++-style comments */
+
+<*>. {
+ DPRINT("Char: %c (\\x%02x)\n", dtss_yytext[0],
+ (unsigned)dtss_yytext[0]);
+ if (dtss_yytext[0] == '[') {
+ DPRINT("<BYTESTRING>\n");
+ BEGIN(BYTESTRING);
+ }
+ if ((dtss_yytext[0] == '{')
+ || (dtss_yytext[0] == ';')) {
+ DPRINT("<PROPNODENAME>\n");
+ BEGIN(PROPNODENAME);
+ }
+ return dtss_yytext[0];
+ }
+
+%%
+
+static void push_input_file(const char *filename)
+{
+ assert(filename);
+
+ srcfile_push(filename);
+
+ dtss_yyin = current_srcfile->f;
+
+ dtss_yypush_buffer_state(dtss_yy_create_buffer(dtss_yyin, YY_BUF_SIZE));
+}
+
+
+static bool pop_input_file(void)
+{
+ if (srcfile_pop() == 0)
+ return false;
+
+ dtss_yypop_buffer_state();
+ dtss_yyin = current_srcfile->f;
+
+ return true;
+}
+
+static void lexical_error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ srcpos_verror(&dtss_yylloc, "Lexical error", fmt, ap);
+ va_end(ap);
+
+ treesource_error = true;
+}
diff --git a/dtss-parser.y b/dtss-parser.y
new file mode 100644
index 0000000..1c807da
--- /dev/null
+++ b/dtss-parser.y
@@ -0,0 +1,341 @@
+/*
+ * (C) Copyright David Gibson <dwg-8fk3Idey6ehBDgjK7y7TUQ@public.gmane.org>, IBM Corporation. 2005.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+%define api.prefix dtss_yy
+
+%{
+#include <stdio.h>
+
+#include "dtc.h"
+#include "srcpos.h"
+
+#define DTSS_YYLTYPE struct srcpos
+
+extern int dtss_yylex(void);
+extern void dtss_yyerror(char const *s);
+#define ERROR(loc, ...) \
+ do { \
+ srcpos_error((loc), "Error", __VA_ARGS__); \
+ treesource_error = true; \
+ } while (0)
+
+extern struct boot_info *the_boot_info;
+extern bool treesource_error;
+%}
+
+%union {
+ char *propnodename;
+ char *labelref;
+ unsigned int cbase;
+ uint8_t byte;
+ struct data data;
+
+ struct {
+ struct data data;
+ int bits;
+ } array;
+
+ struct property *prop;
+ struct property *proplist;
+ struct node *node;
+ struct node *nodelist;
+ struct reserve_info *re;
+ uint64_t integer;
+}
+
+%token DTSS_V1
+%token DT_BITS
+%token DT_DEL_PROP
+%token DT_DEL_NODE
+%token DTSS_INCOMPLETE
+%token DTSS_MATCH
+%token DTSS_USE
+%token DTSS_REQUIRE
+%token DTSS_OPTIONAL
+%token <propnodename> DT_PROPNODENAME
+%token <integer> DT_LITERAL
+%token <integer> DT_CHAR_LITERAL
+%token <cbase> DT_BASE
+%token <byte> DT_BYTE
+%token <data> DT_STRING
+%token <data> DTSS_TYPESPEC
+%token <labelref> DT_LABEL
+%token <labelref> DT_REF
+%token DT_INCBIN
+
+%type <data> propdata
+%type <data> propdataprefix
+%type <array> arrayprefix
+%type <data> bytestring
+%type <prop> propdef
+%type <proplist> proplist
+
+%type <node> schema
+%type <node> schemaroot
+%type <node> nodedef
+%type <node> subnode
+%type <nodelist> subnodes
+
+%type <integer> integer_prim
+
+%%
+
+sourcefile:
+ DTSS_V1 ';' schema
+ {
+ the_boot_info = build_boot_info(NULL, $3, 0);
+ }
+ ;
+
+schemaroot:
+ subnodes
+ {
+ $$ = build_node(NULL, $1);
+ }
+ ;
+
+schema:
+ schemaroot
+ {
+ $$ = name_node($1, "/");
+ }
+ ;
+
+nodedef:
+ '{' proplist subnodes '}' ';'
+ {
+ $$ = build_node($2, $3);
+ }
+ ;
+
+proplist:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | proplist propdef
+ {
+ $$ = chain_property($2, $1);
+ }
+ ;
+
+propdef:
+ DT_PROPNODENAME '=' propdata ';'
+ {
+ $$ = build_property($1, $3);
+ }
+ | DT_PROPNODENAME ';'
+ {
+ $$ = build_property($1, empty_data);
+ }
+ | DT_DEL_PROP DT_PROPNODENAME ';'
+ {
+ $$ = build_property_delete($2);
+ }
+ | DTSS_MATCH propdef
+ {
+ $2->type = PROPERTY_MATCH;
+ $$ = $2;
+ }
+ | DTSS_USE propdef
+ {
+ $2->type = PROPERTY_USE;
+ $$ = $2;
+ }
+ | DTSS_REQUIRE propdef
+ {
+ $2->type = PROPERTY_REQUIRE;
+ $$ = $2;
+ }
+ | DTSS_OPTIONAL propdef
+ {
+ $2->flags |= PROPERTY_FLAG_OPTIONAL;
+ $$ = $2;
+ }
+ ;
+
+propdata:
+ propdataprefix DT_STRING
+ {
+ $$ = data_merge($1, $2);
+ }
+ | propdataprefix arrayprefix '>'
+ {
+ $$ = data_merge($1, $2.data);
+ }
+ | propdataprefix '[' bytestring ']'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
+ {
+ FILE *f = srcfile_relative_open($4.val, NULL);
+ struct data d;
+
+ if ($6 != 0)
+ if (fseek(f, $6, SEEK_SET) != 0)
+ die("Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)$6, $4.val,
+ strerror(errno));
+
+ d = data_copy_file(f, $8);
+
+ $$ = data_merge($1, d);
+ fclose(f);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ')'
+ {
+ FILE *f = srcfile_relative_open($4.val, NULL);
+ struct data d = empty_data;
+
+ d = data_copy_file(f, -1);
+
+ $$ = data_merge($1, d);
+ fclose(f);
+ }
+ ;
+
+propdataprefix:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | propdata ','
+ {
+ $$ = $1;
+ }
+ | propdataprefix DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+arrayprefix:
+ DT_BITS DT_LITERAL '<'
+ {
+ unsigned long long bits;
+
+ bits = $2;
+
+ if ((bits != 8) && (bits != 16) &&
+ (bits != 32) && (bits != 64)) {
+ ERROR(&@2, "Array elements must be"
+ " 8, 16, 32 or 64-bits");
+ bits = 32;
+ }
+
+ $$.data = empty_data;
+ $$.bits = bits;
+ }
+ | '<'
+ {
+ $$.data = empty_data;
+ $$.bits = 32;
+ }
+ | arrayprefix integer_prim
+ {
+ if ($1.bits < 64) {
+ uint64_t mask = (1ULL << $1.bits) - 1;
+ /*
+ * Bits above mask must either be all zero
+ * (positive within range of mask) or all one
+ * (negative and sign-extended). The second
+ * condition is true if when we set all bits
+ * within the mask to one (i.e. | in the
+ * mask), all bits are one.
+ */
+ if (($2 > mask) && (($2 | mask) != -1ULL))
+ ERROR(&@2, "Value out of range for"
+ " %d-bit array element", $1.bits);
+ }
+
+ $$.data = data_append_integer($1.data, $2, $1.bits);
+ }
+ ;
+
+integer_prim:
+ DT_LITERAL
+ | DT_CHAR_LITERAL
+ ;
+
+bytestring:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | bytestring DT_BYTE
+ {
+ $$ = data_append_byte($1, $2);
+ }
+ ;
+
+subnodes:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | subnode subnodes
+ {
+ $$ = chain_node($1, $2);
+ }
+ | subnode propdef
+ {
+ ERROR(&@2, "Properties must precede subnodes");
+ YYERROR;
+ }
+ ;
+
+subnode:
+ DT_PROPNODENAME nodedef
+ {
+ $$ = name_node($2, $1);
+ }
+ | DT_DEL_NODE DT_PROPNODENAME ';'
+ {
+ $$ = name_node(build_node_delete(), $2);
+ }
+ | DTSS_USE subnode
+ {
+ $2->type = NODE_USE;
+ $$ = $2;
+ }
+ | DTSS_REQUIRE subnode
+ {
+ $2->type = NODE_REQUIRE;
+ $$ = $2;
+ }
+ | DTSS_OPTIONAL subnode
+ {
+ $2->flags |= NODE_FLAG_OPTIONAL;
+ $$ = $2;
+ }
+ | DTSS_INCOMPLETE subnode
+ {
+ $2->flags |= NODE_FLAG_INCOMPLETE;
+ $$ = $2;
+ }
+ ;
+
+%%
+
+void dtss_yyerror(char const *s)
+{
+ ERROR(&yylloc, "%s", s);
+}
diff --git a/schemas/schema.c b/schemas/schema.c
new file mode 100644
index 0000000..e5258cf
--- /dev/null
+++ b/schemas/schema.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2013 Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "schema.h"
+
+static struct schema_checker schema_list = {
+ .next = &schema_list,
+};
+
+int schema_check_node(struct node *root, struct node *node)
+{
+ const struct schema_checker *checker;
+ int match;
+ int checked = 0;
+
+ checker = schema_list.next;
+ for (; checker != &schema_list; checker = checker->next) {
+ match = checker->matchfn(node, checker);
+ if (!match)
+ continue;
+
+ pr_info("Node %s matches checker %s at level %d\n",
+ node->fullpath, checker->name, match);
+
+ checker->checkfn(root, node, checker);
+ checked = 1;
+ }
+
+ /*
+ * FIXME: this is too noisy right now. Make it optional until schemas
+ * for most bindings are implemented.
+ */
+ if (!checked) {
+ pr_warn("no schema for node %s\n", node->fullpath);
+ return 0;
+ }
+
+ /*
+ * FIXME: grab validation state from global somewhere.
+ * Using global state avoids having check return values after every
+ * function call, thus making the code less verbose and appear more
+ * assertion-based.
+ */
+ return 0;
+}
+
+int schema_match_path(struct node *node, const struct schema_checker *checker)
+{
+ return !strcmp(node->fullpath, checker->u.path.path);
+}
+
+int schema_match_compatible(struct node *node,
+ const struct schema_checker *checker)
+{
+ struct property *compat_prop;
+ int index;
+ const char *node_compat;
+ const char **test_compats;
+
+ compat_prop = get_property(node, "compatible");
+ if (!compat_prop)
+ return 0;
+
+ /*
+ * Match with any compatible value of schema with any compatible
+ * value of node being verified.
+ */
+ for (node_compat = compat_prop->val.val, index = 0;
+ *node_compat;
+ node_compat += strlen(node_compat) + 1, index++) {
+ for (test_compats = checker->u.compatible.compats;
+ *test_compats; test_compats++) {
+ if (!strcmp(node_compat, *test_compats))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+struct property *schema_get_param(struct node *params, const char *name)
+{
+ if (!params)
+ return NULL;
+
+ return get_property(params, name);
+}
+
+int schema_get_param_cell(struct node *params, const char *name, cell_t *val)
+{
+ struct property *prop;
+
+ prop = schema_get_param(params, name);
+ if (!prop)
+ return -ENOENT;
+
+ if (!prop->val.len)
+ return -EINVAL;
+
+ *val = propval_cell(prop);
+ return 0;
+}
+
+struct property *require_property(struct node *node, const char *name)
+{
+ struct property *prop;
+
+ prop = get_property(node, name);
+ if (!prop) {
+ /*
+ * FIXME: set global error state. The same comment applies
+ * everywhere.
+ */
+ pr_err("node '%s' missing '%s' property\n",
+ node->fullpath, name);
+ }
+
+ return prop;
+}
+
+static void check_required_property(struct node *node, struct property *schema)
+{
+ struct property *prop;
+
+ prop = require_property(node, schema->name);
+ if (!prop)
+ return;
+
+ if (schema->val.len
+ && (schema->val.len != prop->val.len
+ || memcmp(schema->val.val, prop->val.val, prop->val.len)))
+ pr_err("node %s with wrong constant value of property %s\n",
+ node->fullpath, schema->name);
+}
+
+static void check_optional_property(struct node *node, struct property *schema)
+{
+ struct property *prop;
+
+ prop = get_property(node, schema->name);
+ if (!prop)
+ return;
+
+ check_required_property(node, schema);
+}
+
+/*
+ * FIXME: Use a more generic solution, which does not rely on linker
+ * specific features.
+ */
+extern const struct generic_schema __start_generic_schemas;
+extern const struct generic_schema __stop_generic_schemas;
+
+static void check_generic_schema(struct node *root, struct node *node,
+ const char *name,
+ struct node *schema_node,
+ bool required)
+{
+ const struct generic_schema *gs;
+ int i;
+ bool checked = false;
+ unsigned int count = &__stop_generic_schemas - &__start_generic_schemas;
+
+ pr_info("running schema \"%s\"\n", name);
+
+ gs = &__start_generic_schemas;
+ for (i = 0; i < count; ++i, ++gs) {
+ if (strcmp(gs->name, name))
+ continue;
+
+ gs->checkfn(gs, root, node, schema_node, required);
+
+ checked = true;
+ }
+
+ if (!checked)
+ pr_err("schema \"%s\" not found\n", name);
+}
+
+static void check_dtss_schema(struct node *root, struct node *node,
+ const struct schema_checker *checker)
+{
+ struct property *prop_schema;
+ struct node *schema = checker->node, *node_schema;
+
+ for_each_property(schema, prop_schema) {
+ if (!strcmp(prop_schema->name, "compatible")
+ || !strcmp(prop_schema->name, "device_type"))
+ continue;
+
+ switch (prop_schema->type) {
+ case PROPERTY_DATA:
+ if (prop_schema->flags & PROPERTY_FLAG_OPTIONAL)
+ check_optional_property(node, prop_schema);
+ else
+ check_required_property(node, prop_schema);
+ break;
+
+ case PROPERTY_REQUIRE:
+ check_generic_schema(root, node, prop_schema->name,
+ NULL, true);
+ break;
+
+ case PROPERTY_USE:
+ check_generic_schema(root, node, prop_schema->name,
+ NULL, false);
+ break;
+ }
+ }
+
+ for_each_child(schema, node_schema) {
+ switch (node_schema->type) {
+ case NODE_DATA:
+ /* TODO: verify subnodes */
+ break;
+
+ case NODE_REQUIRE:
+ check_generic_schema(root, node, node_schema->name,
+ node_schema, true);
+ break;
+
+ case NODE_USE:
+ check_generic_schema(root, node, node_schema->name,
+ node_schema, false);
+ break;
+ }
+ }
+
+ /* TODO: detect unknown properties */
+}
+
+void build_schema_list(struct boot_info *schema_tree)
+{
+ struct node *root, *schema;
+
+ root = get_node_by_path(schema_tree->dt, "/");
+ if (!root) {
+ pr_err("schema file missing / node\n");
+ return;
+ }
+
+ for_each_child(root, schema) {
+ struct schema_checker *sc = xmalloc(sizeof(*sc));
+ struct property *prop;
+
+ sc->node = schema;
+ sc->checkfn = check_dtss_schema;
+ sc->name = schema->name;
+
+ for_each_property(schema, prop)
+ if (prop->type == PROPERTY_MATCH)
+ goto found_match;
+
+ pr_err("schema '%s' without matching key\n", sc->name);
+ free(sc);
+ continue;
+
+found_match:
+ if (!strcmp(prop->name, "compatible")) {
+ int count;
+ const char **compats;
+ const char *compat;
+
+ count = propval_string_count(schema, prop) + 1;
+ compats = xmalloc(count * sizeof(*compats));
+
+ sc->u.compatible.compats = compats;
+
+ while ((compat = propval_next_string(prop, compat))) {
+ *compats = compat;
+ ++compats;
+ }
+ *compats = NULL;
+
+ sc->matchfn = schema_match_compatible;
+ sc->next = schema_list.next;
+ schema_list.next = sc;
+ } else if (!strcmp(prop->name, "device_type")) {
+ sc->u.type.type = propval_next_string(prop, NULL);
+ sc->next = schema_list.next;
+ schema_list.next = sc;
+ } else if (!strcmp(prop->name, "path")) {
+ sc->u.path.path = propval_next_string(prop, NULL);
+ sc->matchfn = schema_match_path;
+ sc->next = schema_list.next;
+ schema_list.next = sc;
+ } else {
+ pr_err("wrong schema key type\n");
+ free(sc);
+ }
+ }
+}
diff --git a/schemas/schema.h b/schemas/schema.h
new file mode 100644
index 0000000..9972a17
--- /dev/null
+++ b/schemas/schema.h
@@ -0,0 +1,89 @@
+#ifndef _SCHEMAS_SCHEMA_H
+#define _SCHEMAS_SCHEMA_H
+
+#include "dtc.h"
+
+struct schema_checker;
+
+typedef int (schema_matcher_func)(struct node *node,
+ const struct schema_checker *checker);
+typedef void (schema_checker_func)(struct node *root, struct node *node,
+ const struct schema_checker *checker);
+
+struct schema_checker {
+ const char *name;
+ schema_matcher_func *matchfn;
+ schema_checker_func *checkfn;
+ struct node *node;
+ union {
+ struct {
+ const char *path;
+ } path;
+ struct {
+ const char **compats;
+ } compatible;
+ struct {
+ const char *type;
+ } type;
+ } u;
+ struct schema_checker *next;
+};
+
+int schema_check_node(struct node *root, struct node *node);
+
+int schema_match_path(struct node *node, const struct schema_checker *checker);
+int schema_match_compatible(struct node *node,
+ const struct schema_checker *checker);
+
+#define SCHEMA_MATCH_PATH(_name_, _path_) \
+ struct schema_checker schema_checker_##_name_ = { \
+ .name = #_name_, \
+ .matchfn = schema_match_path, \
+ .checkfn = checkfn_##_name_, \
+ .u.path.path = _path_, \
+ };
+
+#define SCHEMA_MATCH_COMPATIBLE(_name_) \
+ struct schema_checker schema_checker_##_name_ = { \
+ .name = #_name_, \
+ .matchfn = schema_match_compatible, \
+ .checkfn = checkfn_##_name_, \
+ .u.compatible.compats = compats_##_name_, \
+ };
+
+struct generic_schema;
+
+typedef void (generic_schema_checker_func)(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required);
+
+struct generic_schema {
+ const char *name;
+ generic_schema_checker_func *checkfn;
+};
+
+#define __used __attribute__((__used__))
+#define __section(S) __attribute__ ((__section__(#S)))
+
+#define GENERIC_SCHEMA(_dt_name_, _name_) \
+ static const struct generic_schema generic_schema_##_name_ \
+ __used __section(generic_schemas) = { \
+ .name = _dt_name_, \
+ .checkfn = generic_checkfn_##_name_, \
+ };
+
+struct property *require_property(struct node *node, const char *propname);
+struct property *schema_get_param(struct node *params, const char *name);
+int schema_get_param_cell(struct node *params, const char *name, cell_t *val);
+
+void build_schema_list(struct boot_info *schema_tree);
+
+#define schema_err(s,fmt,args...) pr_err("%s: " fmt, (s)->name, ##args)
+#define schema_warn(s,fmt,args...) pr_warn("%s: " fmt, (s)->name, ##args)
+#define schema_info(s,fmt,args...) pr_info("%s: " fmt, (s)->name, ##args)
+
+#define node_err(n,fmt,args...) pr_err("%s: " fmt, (n)->fullpath, ##args)
+#define node_warn(n,fmt,args...) pr_warn("%s: " fmt, (n)->fullpath, ##args)
+#define node_info(n,fmt,args...) pr_info("%s: " fmt, (n)->fullpath, ##args)
+
+#endif
diff --git a/srcpos.h b/srcpos.h
index f81827b..b761522 100644
--- a/srcpos.h
+++ b/srcpos.h
@@ -75,7 +75,9 @@ struct srcpos {
struct srcfile_state *file;
};
+#ifndef YYLTYPE
#define YYLTYPE struct srcpos
+#endif
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
diff --git a/treesource.c b/treesource.c
index bf7a626..e50285c 100644
--- a/treesource.c
+++ b/treesource.c
@@ -25,6 +25,10 @@ extern FILE *yyin;
extern int yyparse(void);
extern YYLTYPE yylloc;
+extern FILE *dtss_yyin;
+extern int dtss_yyparse(void);
+extern YYLTYPE dtss_yylloc;
+
struct boot_info *the_boot_info;
bool treesource_error;
@@ -46,6 +50,24 @@ struct boot_info *dt_from_source(const char *fname)
return the_boot_info;
}
+struct boot_info *schema_from_source(const char *fname)
+{
+ the_boot_info = NULL;
+ treesource_error = false;
+
+ srcfile_push(fname);
+ dtss_yyin = current_srcfile->f;
+ dtss_yylloc.file = current_srcfile;
+
+ if (dtss_yyparse() != 0)
+ die("Unable to parse input tree\n");
+
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
+
+ return the_boot_info;
+}
+
static void write_prefix(FILE *f, int level)
{
int i;
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH RFC 4/5] Add sample C-based generic bindings
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
` (2 preceding siblings ...)
2014-02-20 18:06 ` [PATCH RFC 3/5] Implement DT schema checker using hybrid approach Tomasz Figa
@ 2014-02-20 18:06 ` Tomasz Figa
2014-02-20 18:06 ` [PATCH RFC 5/5] Add sample DTS and DTSS schema Tomasz Figa
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Tomasz Figa @ 2014-02-20 18:06 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
Tomasz Figa
Signed-off-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
Makefile.dtc | 7 +-
schemas/clock/clock.c | 77 +++++
schemas/gpio/gpio.c | 93 ++++++
schemas/i2c/i2c.c | 42 +++
schemas/interrupt-controller/interrupts.c | 452 ++++++++++++++++++++++++++++++
schemas/mmio-bus.c | 97 +++++++
6 files changed, 767 insertions(+), 1 deletion(-)
create mode 100644 schemas/clock/clock.c
create mode 100644 schemas/gpio/gpio.c
create mode 100644 schemas/i2c/i2c.c
create mode 100644 schemas/interrupt-controller/interrupts.c
create mode 100644 schemas/mmio-bus.c
diff --git a/Makefile.dtc b/Makefile.dtc
index bf19564..b75da69 100644
--- a/Makefile.dtc
+++ b/Makefile.dtc
@@ -13,7 +13,12 @@ DTC_SRCS = \
srcpos.c \
treesource.c \
util.c \
- schemas/schema.c
+ schemas/mmio-bus.c \
+ schemas/schema.c \
+ schemas/clock/clock.c \
+ schemas/gpio/gpio.c \
+ schemas/i2c/i2c.c \
+ schemas/interrupt-controller/interrupts.c \
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c dtss-lexer.lex.c dtss-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
diff --git a/schemas/clock/clock.c b/schemas/clock/clock.c
new file mode 100644
index 0000000..d22b759
--- /dev/null
+++ b/schemas/clock/clock.c
@@ -0,0 +1,77 @@
+#include "dtc.h"
+#include "schema.h"
+
+static void clocks_check_names(struct node *root, struct node *node,
+ struct property *names, bool optional)
+{
+ const char *name = NULL;
+ struct property *clocks, *clock_names;
+
+ clocks = require_property(node, "clocks");
+ clock_names = require_property(node, "clock-names");
+
+ if (!clocks || !clock_names)
+ return;
+
+ for_each_propval_string(names, name) {
+ struct of_phandle_args args;
+ int ret;
+
+ ret = propval_match_string(clock_names, name);
+ if (ret < 0) {
+ if (optional)
+ continue;
+
+ pr_err("clock '%s' not specified in node '%s'\n",
+ name, node->fullpath);
+ continue;
+ }
+
+ ret = propval_parse_phandle_with_args(root, clocks,
+ "#clock-cells", ret,
+ &args);
+ if (ret < 0)
+ pr_err("failed to parse specifier of clock '%s' in node '%s'\n",
+ name, node->fullpath);
+ }
+}
+
+static void clocks_check_count(struct node *root, struct node *node,
+ struct property *count_prop)
+{
+ struct property *clocks;
+ cell_t count = propval_cell(count_prop);
+ int ret;
+
+ clocks = require_property(node, "clocks");
+ if (!clocks)
+ return;
+
+ ret = propval_count_phandle_with_args(root, clocks, "#clock-cells");
+ if (ret < 0)
+ pr_err("failed to parse clocks property\n");
+ else if (ret < count)
+ pr_err("not enough clock specifiers (expected %u, got %d)\n",
+ count, ret);
+}
+
+static void generic_checkfn_clocks(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+
+ if (!params) {
+ pr_err("schema clocks requires arguments\n");
+ return;
+ }
+
+ prop = get_property(params, "names");
+ if (prop)
+ clocks_check_names(root, node, prop, !required);
+
+ prop = get_property(params, "count");
+ if (prop)
+ clocks_check_count(root, node, prop);
+}
+GENERIC_SCHEMA("clocks", clocks);
diff --git a/schemas/gpio/gpio.c b/schemas/gpio/gpio.c
new file mode 100644
index 0000000..9100c95
--- /dev/null
+++ b/schemas/gpio/gpio.c
@@ -0,0 +1,93 @@
+#include "schema.h"
+
+static void check_gpios_named(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required,
+ const char *prop_name)
+{
+ struct property *prop;
+ cell_t count;
+ int ret;
+ int i;
+
+ ret = schema_get_param_cell(params, "count", &count);
+ if (ret < 0) {
+ schema_err(schema, "missing schema argument: 'count'\n");
+ return;
+ }
+
+ if (required)
+ prop = require_property(node, prop_name);
+ else
+ prop = get_property(node, prop_name);
+ if (!prop)
+ return;
+
+ for (i = 0; i < count; ++i) {
+ struct of_phandle_args args;
+
+ ret = propval_parse_phandle_with_args(root, prop,
+ "#gpio-cells", i, &args);
+ if (ret < 0)
+ pr_err("failed to parse gpio specifier %d in '%s' property of node '%s'\n",
+ i, prop_name, node->fullpath);
+ }
+}
+
+static void generic_checkfn_gpios(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ check_gpios_named(schema, root, node, params, required, "gpios");
+}
+GENERIC_SCHEMA("gpios", gpios);
+
+static void generic_checkfn_named_gpios(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ const char *name;
+
+ prop = schema_get_param(params, "name");
+ if (!prop) {
+ schema_err(schema, "missing schema argument: 'name'\n");
+ return;
+ }
+
+ name = propval_next_string(prop, NULL);
+
+ check_gpios_named(schema, root, node, params, required, name);
+}
+GENERIC_SCHEMA("named-gpios", named_gpios);
+
+static void generic_checkfn_gpio_provider(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ cell_t cells, val;
+ int ret;
+
+ ret = schema_get_param_cell(params, "cells", &cells);
+ if (ret < 0) {
+ schema_err(schema, "missing schema argument: 'cells'\n");
+ return;
+ }
+
+ prop = require_property(node, "gpio-controller");
+ if (!prop)
+ return;
+
+ prop = require_property(node, "#gpio-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val != cells) {
+ pr_err("wrong value of #interrupt-cells property in node '%s' (expected %u, got %u)\n",
+ node->fullpath, cells, val);
+ return;
+ }
+}
+GENERIC_SCHEMA("gpio-provider", gpio_provider);
diff --git a/schemas/i2c/i2c.c b/schemas/i2c/i2c.c
new file mode 100644
index 0000000..ba8fd34
--- /dev/null
+++ b/schemas/i2c/i2c.c
@@ -0,0 +1,42 @@
+#include "schema.h"
+
+static void generic_checkfn_i2c_device(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ prop = require_property(node, "reg");
+ if (!prop)
+ return;
+
+ if (prop->val.len != sizeof(cell_t))
+ node_err(node, "i2c-bus expects reg property to be a single cell\n");
+
+ /* TODO: Check if parent device is an i2c bus. */
+}
+GENERIC_SCHEMA("i2c-device", i2c_device);
+
+static void generic_checkfn_i2c_bus(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ cell_t val;
+
+ prop = require_property(node, "#address-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val != 1)
+ node_err(node, "i2c-bus requires #address-cells == 1\n");
+
+ prop = require_property(node, "#size-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val != 0)
+ node_err(node, "i2c-bus requires #size-cells == 0\n");
+}
+GENERIC_SCHEMA("i2c-bus", i2c_bus);
diff --git a/schemas/interrupt-controller/interrupts.c b/schemas/interrupt-controller/interrupts.c
new file mode 100644
index 0000000..7eda441
--- /dev/null
+++ b/schemas/interrupt-controller/interrupts.c
@@ -0,0 +1,452 @@
+#include "schema.h"
+
+/*******************************************************************************
+ * Copypasta from kernel's drivers/of/irq.c starts here.
+ * (Well, maybe with some minor changes to make it compile here.)
+ ******************************************************************************/
+
+/* Adaptation glue... */
+
+#define pr_debug(...)
+typedef cell_t __be32;
+typedef cell_t phandle;
+#define of_node_get(node) (node)
+#define of_node_put(node)
+#define of_irq_workarounds (0)
+#define OF_IMAP_OLDWORLD_MAC 0x00000001
+#define OF_IMAP_NO_PHANDLE 0x00000002
+#define of_irq_dflt_pic (NULL)
+#define be32_to_cpu(val) fdt32_to_cpu((val))
+#define be32_to_cpup(ptr) be32_to_cpu(*(ptr))
+#define cpu_to_be32(val) cpu_to_fdt32(val)
+#define raw_spin_lock_irqsave(...)
+#define raw_spin_unlock_irqrestore(...)
+typedef uint32_t u32;
+#define WARN_ON(x) (x)
+#define of_irq_parse_oldworld(...) (-EINVAL)
+#define of_node_full_name(x) ((x)->fullpath)
+
+static const cell_t dummy = 0;
+
+static const void *of_get_property(struct node *np, const char *name,
+ int *lenp)
+{
+ struct property *prop;
+
+ prop = get_property(np, name);
+ if(!prop)
+ return NULL;
+
+ if (lenp)
+ *lenp = prop->val.len;
+
+ if (!prop->val.val)
+ return &dummy;
+
+ return prop->val.val;
+}
+
+static struct node *of_get_parent(const struct node *node)
+{
+ return node ? node->parent : NULL;
+}
+
+static int of_device_is_available(struct node *device)
+{
+ const char *status;
+ int statlen;
+
+ if (!device)
+ return 0;
+
+ status = of_get_property(device, "status", &statlen);
+ if (status == NULL)
+ return 1;
+
+ if (statlen > 0) {
+ if (!strcmp(status, "okay") || !strcmp(status, "ok"))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* End of adaptation glue. */
+
+/**
+ * of_irq_find_parent - Given a device node, find its interrupt parent node
+ * @child: pointer to device node
+ *
+ * Returns a pointer to the interrupt parent node, or NULL if the interrupt
+ * parent could not be determined.
+ */
+static struct node *of_irq_find_parent(struct node *root, struct node *child)
+{
+ struct node *p;
+ const __be32 *parp;
+
+ if (!of_node_get(child))
+ return NULL;
+
+ do {
+ parp = of_get_property(child, "interrupt-parent", NULL);
+ if (parp == NULL)
+ p = of_get_parent(child);
+ else {
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ p = of_node_get(of_irq_dflt_pic);
+ else
+ p = get_node_by_phandle(root,
+ be32_to_cpup(parp));
+ }
+ of_node_put(child);
+ child = p;
+ } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
+
+ return p;
+}
+
+/**
+ * of_irq_parse_raw - Low level interrupt tree parsing
+ * @parent: the device interrupt parent
+ * @addr: address specifier (start of "reg" property of the device) in be32 format
+ * @out_irq: structure of_irq updated by this function
+ *
+ * Returns 0 on success and a negative number on error
+ *
+ * This function is a low-level interrupt tree walking function. It
+ * can be used to do a partial walk with synthetized reg and interrupts
+ * properties, for example when resolving PCI interrupts when no device
+ * node exist for the parent. It takes an interrupt specifier structure as
+ * input, walks the tree looking for any interrupt-map properties, translates
+ * the specifier for each map, and then returns the translated map.
+ */
+static int of_irq_parse_raw(struct node *root,
+ const __be32 *addr, struct of_phandle_args *out_irq)
+{
+ struct node *ipar, *tnode, *old = NULL, *newpar = NULL;
+ __be32 initial_match_array[MAX_PHANDLE_ARGS];
+ const __be32 *match_array = initial_match_array;
+ const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
+ u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
+ int imaplen, match, i;
+
+#ifdef DEBUG
+ of_print_phandle_args("of_irq_parse_raw: ", out_irq);
+#endif
+
+ ipar = of_node_get(out_irq->np);
+
+ /* First get the #interrupt-cells property of the current cursor
+ * that tells us how to interpret the passed-in intspec. If there
+ * is none, we are nice and just walk up the tree
+ */
+ do {
+ tmp = of_get_property(ipar, "#interrupt-cells", NULL);
+ if (tmp != NULL) {
+ intsize = be32_to_cpu(*tmp);
+ break;
+ }
+ tnode = ipar;
+ ipar = of_irq_find_parent(root, ipar);
+ of_node_put(tnode);
+ } while (ipar);
+ if (ipar == NULL) {
+ pr_debug(" -> no parent found !\n");
+ goto fail;
+ }
+
+ pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
+
+ if (out_irq->args_count != intsize)
+ return -EINVAL;
+
+ /* Look for this #address-cells. We have to implement the old linux
+ * trick of looking for the parent here as some device-trees rely on it
+ */
+ old = of_node_get(ipar);
+ do {
+ tmp = of_get_property(old, "#address-cells", NULL);
+ tnode = of_get_parent(old);
+ of_node_put(old);
+ old = tnode;
+ } while (old && tmp == NULL);
+ of_node_put(old);
+ old = NULL;
+ addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
+
+ pr_debug(" -> addrsize=%d\n", addrsize);
+
+ /* Range check so that the temporary buffer doesn't overflow */
+ if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
+ goto fail;
+
+ /* Precalculate the match array - this simplifies match loop */
+ for (i = 0; i < addrsize; i++)
+ initial_match_array[i] = addr ? addr[i] : 0;
+ for (i = 0; i < intsize; i++)
+ initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
+
+ /* Now start the actual "proper" walk of the interrupt tree */
+ while (ipar != NULL) {
+ /* Now check if cursor is an interrupt-controller and if it is
+ * then we are done
+ */
+ if (of_get_property(ipar, "interrupt-controller", NULL) !=
+ NULL) {
+ pr_debug(" -> got it !\n");
+ return 0;
+ }
+
+ /*
+ * interrupt-map parsing does not work without a reg
+ * property when #address-cells != 0
+ */
+ if (addrsize && !addr) {
+ pr_debug(" -> no reg passed in when needed !\n");
+ goto fail;
+ }
+
+ /* Now look for an interrupt-map */
+ imap = of_get_property(ipar, "interrupt-map", &imaplen);
+ /* No interrupt map, check for an interrupt parent */
+ if (imap == NULL) {
+ pr_debug(" -> no map, getting parent\n");
+ newpar = of_irq_find_parent(root, ipar);
+ goto skiplevel;
+ }
+ imaplen /= sizeof(u32);
+
+ /* Look for a mask */
+ imask = of_get_property(ipar, "interrupt-map-mask", NULL);
+ if (!imask)
+ imask = dummy_imask;
+
+ /* Parse interrupt-map */
+ match = 0;
+ while (imaplen > (addrsize + intsize + 1) && !match) {
+ /* Compare specifiers */
+ match = 1;
+ for (i = 0; i < (addrsize + intsize); i++, imaplen--)
+ match &= !((match_array[i] ^ *imap++) & imask[i]);
+
+ pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
+
+ /* Get the interrupt parent */
+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
+ newpar = of_node_get(of_irq_dflt_pic);
+ else
+ newpar = get_node_by_phandle(root,
+ be32_to_cpup(imap));
+ imap++;
+ --imaplen;
+
+ /* Check if not found */
+ if (newpar == NULL) {
+ pr_debug(" -> imap parent not found !\n");
+ goto fail;
+ }
+
+ if (!of_device_is_available(newpar))
+ match = 0;
+
+ /* Get #interrupt-cells and #address-cells of new
+ * parent
+ */
+ tmp = of_get_property(newpar, "#interrupt-cells", NULL);
+ if (tmp == NULL) {
+ pr_debug(" -> parent lacks #interrupt-cells!\n");
+ goto fail;
+ }
+ newintsize = be32_to_cpu(*tmp);
+ tmp = of_get_property(newpar, "#address-cells", NULL);
+ newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
+
+ pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
+ newintsize, newaddrsize);
+
+ /* Check for malformed properties */
+ if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
+ goto fail;
+ if (imaplen < (newaddrsize + newintsize))
+ goto fail;
+
+ imap += newaddrsize + newintsize;
+ imaplen -= newaddrsize + newintsize;
+
+ pr_debug(" -> imaplen=%d\n", imaplen);
+ }
+ if (!match)
+ goto fail;
+
+ /*
+ * Successfully parsed an interrrupt-map translation; copy new
+ * interrupt specifier into the out_irq structure
+ */
+ out_irq->np = newpar;
+
+ match_array = imap - newaddrsize - newintsize;
+ for (i = 0; i < newintsize; i++)
+ out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
+ out_irq->args_count = intsize = newintsize;
+ addrsize = newaddrsize;
+
+ skiplevel:
+ /* Iterate again with new parent */
+ pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
+ of_node_put(ipar);
+ ipar = newpar;
+ newpar = NULL;
+ }
+ fail:
+ of_node_put(ipar);
+ of_node_put(newpar);
+
+ return -EINVAL;
+}
+
+/**
+ * of_irq_parse_one - Resolve an interrupt for a device
+ * @device: the device whose interrupt is to be resolved
+ * @index: index of the interrupt to resolve
+ * @out_irq: structure of_irq filled by this function
+ *
+ * This function resolves an interrupt for a node by walking the interrupt tree,
+ * finding which interrupt controller node it is attached to, and returning the
+ * interrupt specifier that can be used to retrieve a Linux IRQ number.
+ */
+static int of_irq_parse_one(struct node *root, struct node *device,
+ int index, struct of_phandle_args *out_irq)
+{
+ struct node *p;
+ const __be32 *intspec, *tmp, *addr;
+ u32 intsize, intlen;
+ int i, res = -EINVAL;
+
+ pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
+
+ /* OldWorld mac stuff is "special", handle out of line */
+ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
+ return of_irq_parse_oldworld(device, index, out_irq);
+
+ /* Get the reg property (if any) */
+ addr = of_get_property(device, "reg", NULL);
+
+ /* Get the interrupts property */
+ intspec = of_get_property(device, "interrupts", (int *)&intlen);
+ if (intspec == NULL) {
+ struct property *prop;
+
+ prop = get_property(device, "interrupts-extended");
+ if (!prop)
+ return -EINVAL;
+
+ /* Try the new-style interrupts-extended */
+ res = propval_parse_phandle_with_args(root, prop,
+ "#interrupt-cells",
+ index, out_irq);
+ if (res)
+ return -EINVAL;
+ return of_irq_parse_raw(root, addr, out_irq);
+ }
+ intlen /= sizeof(*intspec);
+
+ pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
+
+ /* Look for the interrupt parent. */
+ p = of_irq_find_parent(root, device);
+ if (p == NULL)
+ return -EINVAL;
+
+ /* Get size of interrupt specifier */
+ tmp = of_get_property(p, "#interrupt-cells", NULL);
+ if (tmp == NULL)
+ goto out;
+ intsize = be32_to_cpu(*tmp);
+
+ pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
+
+ /* Check index */
+ if ((index + 1) * intsize > intlen)
+ goto out;
+
+ /* Copy intspec into irq structure */
+ intspec += index * intsize;
+ out_irq->np = p;
+ out_irq->args_count = intsize;
+ for (i = 0; i < intsize; i++)
+ out_irq->args[i] = be32_to_cpup(intspec++);
+
+ /* Check if there are any interrupt-map translations to process */
+ res = of_irq_parse_raw(root, addr, out_irq);
+ out:
+ of_node_put(p);
+ return res;
+}
+
+/*******************************************************************************
+ * Copypasta ends here.
+ ******************************************************************************/
+
+static void generic_checkfn_interrupts(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct of_phandle_args irq;
+ cell_t count;
+ int ret;
+ int i;
+
+ ret = schema_get_param_cell(params, "count", &count);
+ if (ret < 0) {
+ schema_err(schema, "missing schema argument: 'count'\n");
+ return;
+ }
+
+ if (!required
+ && !get_property(node, "interrupts")
+ && !get_property(node, "interrupts-extended"))
+ return;
+
+ for (i = 0; i < count; ++i) {
+ ret = of_irq_parse_one(root, node, i, &irq);
+ if (ret < 0)
+ pr_err("failed to parse interrupt entry %d of node '%s'\n",
+ i, node->fullpath);
+ }
+}
+GENERIC_SCHEMA("interrupts", interrupts);
+
+static void generic_checkfn_interrupt_controller(
+ const struct generic_schema *schema,
+ struct node *root,
+ struct node *node,
+ struct node *params,
+ bool required)
+{
+ struct property *prop;
+ cell_t cells, val;
+ int ret;
+
+ ret = schema_get_param_cell(params, "cells", &cells);
+ if (ret < 0) {
+ schema_err(schema, "missing schema argument: 'cells'\n");
+ return;
+ }
+
+ prop = require_property(node, "interrupt-controller");
+ if (!prop)
+ return;
+
+ prop = require_property(node, "#interrupt-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val != cells) {
+ pr_err("wrong value of #interrupt-cells property in node '%s' (expected %u, got %u)\n",
+ node->fullpath, cells, val);
+ return;
+ }
+}
+GENERIC_SCHEMA("interrupt-controller", interrupt_controller);
diff --git a/schemas/mmio-bus.c b/schemas/mmio-bus.c
new file mode 100644
index 0000000..bd7888d
--- /dev/null
+++ b/schemas/mmio-bus.c
@@ -0,0 +1,97 @@
+#include "schema.h"
+
+static unsigned int get_address_cells(struct node *node)
+{
+ struct property *prop;
+
+ prop = get_property(node->parent, "#address-cells");
+ if (!prop) {
+ pr_warn("missing #address-cells property, assuming 2\n");
+ return 2;
+ }
+
+ return propval_cell(prop);
+}
+
+static unsigned int get_size_cells(struct node *node)
+{
+ struct property *prop;
+
+ prop = get_property(node->parent, "#size-cells");
+ if (!prop) {
+ pr_warn("missing #size-cells property, assuming 1\n");
+ return 1;
+ }
+
+ return propval_cell(prop);
+}
+
+static void generic_checkfn_mmio_device(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ cell_t count;
+ unsigned int address_cells, size_cells;
+
+ if (!params) {
+ pr_err("schema mmio-device requires arguments\n");
+ return;
+ }
+
+ prop = get_property(params, "reg-count");
+ if (!prop) {
+ pr_err("schema mmio-device requires reg-count argument\n");
+ return;
+ }
+
+ count = propval_cell(prop);
+ if (!count) {
+ pr_err("wrong number of reg entries requested\n");
+ return;
+ }
+
+ if (!node->parent) {
+ pr_err("root node can not be an mmio-device\n");
+ return;
+ }
+
+ address_cells = get_address_cells(node);
+ size_cells = get_size_cells(node);
+
+ prop = require_property(node, "reg");
+ if (!prop)
+ return;
+
+ if (prop->val.len % (address_cells + size_cells))
+ pr_err("malformed reg property - not a multiple of (#address-cells + #size-cells)\n");
+
+ if (prop->val.len < count * (address_cells + size_cells))
+ pr_err("not enough entries in reg property - expected %u\n", count);
+}
+GENERIC_SCHEMA("mmio-device", mmio_device);
+
+static void generic_checkfn_mmio_bus(const struct generic_schema *schema,
+ struct node *root, struct node *node,
+ struct node *params, bool required)
+{
+ struct property *prop;
+ cell_t val;
+
+ prop = require_property(node, "#address-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val < 1)
+ pr_err("mmio-bus requires positive #address-cells value\n");
+
+ prop = require_property(node, "#size-cells");
+ if (!prop)
+ return;
+
+ val = propval_cell(prop);
+ if (val < 1)
+ pr_err("mmio-bus requires positive #size-cells value\n");
+}
+GENERIC_SCHEMA("mmio-bus", mmio_bus);
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH RFC 5/5] Add sample DTS and DTSS schema
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
` (3 preceding siblings ...)
2014-02-20 18:06 ` [PATCH RFC 4/5] Add sample C-based generic bindings Tomasz Figa
@ 2014-02-20 18:06 ` Tomasz Figa
2014-03-09 12:22 ` [PATCH RFC 0/5] Hybrid approach for DT schema checking David Gibson
2014-05-13 13:21 ` Tomasz Figa
6 siblings, 0 replies; 11+ messages in thread
From: Tomasz Figa @ 2014-02-20 18:06 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
Tomasz Figa
Signed-off-by: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
sample.dts | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
schema.dtss | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 156 insertions(+)
create mode 100644 sample.dts
create mode 100644 schema.dtss
diff --git a/sample.dts b/sample.dts
new file mode 100644
index 0000000..f962051
--- /dev/null
+++ b/sample.dts
@@ -0,0 +1,70 @@
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+ compatible = "foo,bar";
+ model = "Foo Bar board";
+
+ chosen {
+ bootargs = "console=ttySAC2,115200N8";
+ };
+
+ aliases {
+ i2c0 = &i2c_0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x40000000>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gic: interrupt-controller@10490000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x10490000 0x1000>, <0x10480000 0x100>;
+ cpu-offset = <0x4000>;
+ };
+
+ i2c_0: i2c@13860000 {
+ compatible = "nvidia,tegra20-i2c";
+ reg = <0x13860000 0x100>;
+ interrupts = <0 57 0>;
+ clocks = <&clocks 43>, <&clocks 28>;
+ clock-names = "div-clk", "fast-clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ audio-codec@33 {
+ compatible = "wlf,wm8903";
+ reg = <0x33>;
+ gpio-controller;
+ #gpio-cells = <1>;
+ };
+ };
+
+ gpio: pinctrl@11400000 {
+ compatible = "foo,bar-gpio";
+ reg = <0x11400000 0x1000>;
+ interrupts = <0 47 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ clocks: clock-controller@15440000 {
+ compatible = "foo,bar-clocks";
+ reg = <0x15440000 0x1000>;
+ #clock-cells = <1>;
+ };
+ };
+};
diff --git a/schema.dtss b/schema.dtss
new file mode 100644
index 0000000..7a819fe
--- /dev/null
+++ b/schema.dtss
@@ -0,0 +1,86 @@
+/*
+ * schema.dtss - Sample Device Tree schema file.
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dtss-v1/;
+
+root-node {
+ /match/ path = "/";
+ /require/ mmio-bus;
+
+ compatible;
+ /optional/ model;
+};
+
+wlf,wm8903 {
+ /match/ compatible = "wlf,wm8903";
+
+ /optional/ micdet-cfg;
+ /optional/ micdet-delay;
+ /optional/ gpio-cfg;
+
+ /require/ i2c-device;
+
+ /require/ gpio-provider {
+ cells = <1>;
+ };
+
+ /use/ interrupts {
+ count = <1>;
+ };
+};
+
+nvidia,tegra20-i2c {
+ /match/ compatible = "nvidia,tegra20-i2c", "nvidia,tegra30-i2c";
+
+ resets;
+ reset-names;
+ dmas;
+ dma-names;
+
+ /require/ i2c-bus;
+
+ /require/ mmio-device {
+ reg-count = <1>;
+ };
+
+ /require/ interrupts {
+ count = <1>;
+ };
+
+ /require/ clocks {
+ names = "div-clk", "fast-clk";
+ };
+};
+
+foo,bar-gpio {
+ /match/ compatible = "foo,bar-gpio";
+
+ /require/ interrupts {
+ count = <1>;
+ };
+
+ /require/ mmio-device {
+ reg-count = <1>;
+ };
+
+ /require/ gpio-provider {
+ cells = <2>;
+ };
+
+ /require/ interrupt-controller {
+ cells = <2>;
+ };
+};
--
1.8.5.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH RFC 0/5] Hybrid approach for DT schema checking
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
` (4 preceding siblings ...)
2014-02-20 18:06 ` [PATCH RFC 5/5] Add sample DTS and DTSS schema Tomasz Figa
@ 2014-03-09 12:22 ` David Gibson
2014-05-13 13:21 ` Tomasz Figa
6 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-03-09 12:22 UTC (permalink / raw)
To: Tomasz Figa
Cc: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
jdl-CYoMK+44s/E, Arnd Bergmann,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/
[-- Attachment #1: Type: text/plain, Size: 4967 bytes --]
On Thu, Feb 20, 2014 at 07:06:46PM +0100, Tomasz Figa wrote:
> This series adds a proof of concept framework to implement schema checker
> using a combined C and DTSS based approach. Several example bindings are
> also implemented using C and DTSS[1].
>
> Complex and generic bindings can be implemented directly in C and then
> instantiated from simple device-specific bindings using DTS-like DTSS
> language.
>
> A quick description of C part:
>
> A new check is registered in dtc checks framework to perform schema checking
> of each node. Checking is done by searching specified schema set for matching
> schemas (by compatible, device_type or absolute path) and applying matched
> schemas to the node.
We already have an infrastructure for handling C schemas - the checks
infrastructure itself. By all means extend/fix it where it needs it,
but implementing another layer for "schemas" as a special kind of
checks is silly.
[snip]
> A quick description of DTSS part:
>
> * DTSS is a DTS-like language for specification of simple bindings, e.g.
> bindings of particular devices. The basic syntax is very similar to DTS,
> with main elements being nodes and properties. At root level a series of
> nodes should be specified representing particular bindings:
>
> /dtss-v1/;
>
> binding1 {
> /* Definition of binding 1 */
> };
>
> binding2 {
> /* Definition of binding 2 */
> };
>
> * Matching key for each binding can be specified using /match/ keyword:
>
> root-node {
> /match/ path = "/";
> };
>
> wlf,wm8903 {
> /match/ compatible = "wlf,wm8903";
> };
>
> pci-bus {
> /match/ device_type = "memory";
> };
>
> Currently supported matches: path, compatible, device_type.
>
> * Bindings can be specified either by listing properties they require
> (or can use) directly or by instantiating generic C-based bindings.
>
> binding {
> required-property;
>
> /optional/ optional-property;
>
> /require/ required-generic-schema;
>
> /use/ optional-generic-schema {
> schema-argument = <1>;
> };
> };
>
> Generic schemas are implemented in C, as described above, and can use
> arguments specified in DTSS as properties. /require/ calls the schema with
> required=true, while /use/ with required=false.
>
> This is based on Stephen Warren's C based DT schema checker proof of
> concept patch adding C-based validation[2].
>
> TODO:
> - specification of subnodes directly from DTSS,
> - specification of simple property values from DTSS (cells, strings,
> phandles),
> - reporting of unrecognized properties,
> - probably many more...
>
> [1] Device Tree Schema Source
> [2] http://thread.gmane.org/gmane.linux.ports.arm.kernel/275896
>
> Tomasz Figa (5):
> dtc: Add helpers for various message levels
> dtc: livetree: Add more tree parsing helpers
> Another try of DT schema checker using hybrid C and DTSS based
> approach
> Add sample C-based generic bindings
> Add sample DTS and DTSS schema
>
> Makefile | 2 +-
> Makefile.dtc | 10 +-
> checks.c | 15 +
> dtc.c | 17 +-
> dtc.h | 57 ++++
> dtss-lexer.l | 291 +++++++++++++++++++
> dtss-parser.y | 341 ++++++++++++++++++++++
> livetree.c | 230 +++++++++++++++
> sample.dts | 70 +++++
> schema.dtss | 86 ++++++
> schemas/clock/clock.c | 77 +++++
> schemas/gpio/gpio.c | 93 ++++++
> schemas/i2c/i2c.c | 42 +++
> schemas/interrupt-controller/interrupts.c | 452 ++++++++++++++++++++++++++++++
> schemas/mmio-bus.c | 97 +++++++
> schemas/schema.c | 311 ++++++++++++++++++++
> schemas/schema.h | 89 ++++++
> srcpos.h | 2 +
> treesource.c | 22 ++
> 19 files changed, 2300 insertions(+), 4 deletions(-)
> create mode 100644 dtss-lexer.l
> create mode 100644 dtss-parser.y
> create mode 100644 sample.dts
> create mode 100644 schema.dtss
> create mode 100644 schemas/clock/clock.c
> create mode 100644 schemas/gpio/gpio.c
> create mode 100644 schemas/i2c/i2c.c
> create mode 100644 schemas/interrupt-controller/interrupts.c
> create mode 100644 schemas/mmio-bus.c
> create mode 100644 schemas/schema.c
> create mode 100644 schemas/schema.h
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH RFC 0/5] Hybrid approach for DT schema checking
[not found] ` <1392919611-10746-1-git-send-email-t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
` (5 preceding siblings ...)
2014-03-09 12:22 ` [PATCH RFC 0/5] Hybrid approach for DT schema checking David Gibson
@ 2014-05-13 13:21 ` Tomasz Figa
6 siblings, 0 replies; 11+ messages in thread
From: Tomasz Figa @ 2014-05-13 13:21 UTC (permalink / raw)
To: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren,
Marek Szyprowski, grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
bcousson-rdvid1DuHRBWk0Htik3J/w, olof-nZhT3qVonbNeoWH0uzbU5w,
galak-sgV2jX0FEOL9JmXXK+q4OQ, mark.rutland-5wv7dgnIgG8,
a.hajda-Sze3O3UU22JBDgjK7y7TUQ, pawel.moll-5wv7dgnIgG8,
david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+, jdl-CYoMK+44s/E,
Arnd Bergmann, jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/
Hi,
Just wanted to add that you can also find the code in my dtc tree on
kernel.org:
git://git.kernel.org/pub/scm/linux/kernel/git/tfiga/dtc.git
or if you prefer web interface to quickly look through the changes:
https://git.kernel.org/cgit/linux/kernel/git/tfiga/dtc.git/
Best regards,
Tomasz
On 20.02.2014 19:06, Tomasz Figa wrote:
> This series adds a proof of concept framework to implement schema checker
> using a combined C and DTSS based approach. Several example bindings are
> also implemented using C and DTSS[1].
>
> Complex and generic bindings can be implemented directly in C and then
> instantiated from simple device-specific bindings using DTS-like DTSS
> language.
>
> A quick description of C part:
>
> A new check is registered in dtc checks framework to perform schema checking
> of each node. Checking is done by searching specified schema set for matching
> schemas (by compatible, device_type or absolute path) and applying matched
> schemas to the node.
>
> Schemas for complex generic bindings (such as interrupts, gpios, clocks, i2c,
> mmio-bus, etc.) can be implemented directly in C and instantiated from DTSS
> schemas of particular devices. An example C schema may look like:
>
> static void generic_checkfn_xxx_yyy(const struct generic_schema *schema,
> struct node *root, struct node *node,
> struct node *params, bool required)
> {
> /*
> * Get necessary schema arguments from DTSS schema by looking
> * at properties of @params node.
> *
> * Check whether @node node matches the schema.
> *
> * The @required argument may be used to check whether some error
> * conditions should be ignored (e.g. unspecified interrupt).
> */
> }
> GENERIC_SCHEMA("xxx-yyy", xxx_yyy);
>
> A quick description of DTSS part:
>
> * DTSS is a DTS-like language for specification of simple bindings, e.g.
> bindings of particular devices. The basic syntax is very similar to DTS,
> with main elements being nodes and properties. At root level a series of
> nodes should be specified representing particular bindings:
>
> /dtss-v1/;
>
> binding1 {
> /* Definition of binding 1 */
> };
>
> binding2 {
> /* Definition of binding 2 */
> };
>
> * Matching key for each binding can be specified using /match/ keyword:
>
> root-node {
> /match/ path = "/";
> };
>
> wlf,wm8903 {
> /match/ compatible = "wlf,wm8903";
> };
>
> pci-bus {
> /match/ device_type = "memory";
> };
>
> Currently supported matches: path, compatible, device_type.
>
> * Bindings can be specified either by listing properties they require
> (or can use) directly or by instantiating generic C-based bindings.
>
> binding {
> required-property;
>
> /optional/ optional-property;
>
> /require/ required-generic-schema;
>
> /use/ optional-generic-schema {
> schema-argument = <1>;
> };
> };
>
> Generic schemas are implemented in C, as described above, and can use
> arguments specified in DTSS as properties. /require/ calls the schema with
> required=true, while /use/ with required=false.
>
> This is based on Stephen Warren's C based DT schema checker proof of
> concept patch adding C-based validation[2].
>
> TODO:
> - specification of subnodes directly from DTSS,
> - specification of simple property values from DTSS (cells, strings,
> phandles),
> - reporting of unrecognized properties,
> - probably many more...
>
> [1] Device Tree Schema Source
> [2] http://thread.gmane.org/gmane.linux.ports.arm.kernel/275896
>
> Tomasz Figa (5):
> dtc: Add helpers for various message levels
> dtc: livetree: Add more tree parsing helpers
> Another try of DT schema checker using hybrid C and DTSS based
> approach
> Add sample C-based generic bindings
> Add sample DTS and DTSS schema
>
> Makefile | 2 +-
> Makefile.dtc | 10 +-
> checks.c | 15 +
> dtc.c | 17 +-
> dtc.h | 57 ++++
> dtss-lexer.l | 291 +++++++++++++++++++
> dtss-parser.y | 341 ++++++++++++++++++++++
> livetree.c | 230 +++++++++++++++
> sample.dts | 70 +++++
> schema.dtss | 86 ++++++
> schemas/clock/clock.c | 77 +++++
> schemas/gpio/gpio.c | 93 ++++++
> schemas/i2c/i2c.c | 42 +++
> schemas/interrupt-controller/interrupts.c | 452 ++++++++++++++++++++++++++++++
> schemas/mmio-bus.c | 97 +++++++
> schemas/schema.c | 311 ++++++++++++++++++++
> schemas/schema.h | 89 ++++++
> srcpos.h | 2 +
> treesource.c | 22 ++
> 19 files changed, 2300 insertions(+), 4 deletions(-)
> create mode 100644 dtss-lexer.l
> create mode 100644 dtss-parser.y
> create mode 100644 sample.dts
> create mode 100644 schema.dtss
> create mode 100644 schemas/clock/clock.c
> create mode 100644 schemas/gpio/gpio.c
> create mode 100644 schemas/i2c/i2c.c
> create mode 100644 schemas/interrupt-controller/interrupts.c
> create mode 100644 schemas/mmio-bus.c
> create mode 100644 schemas/schema.c
> create mode 100644 schemas/schema.h
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread