Hi,

so that we can easily check if a node is compatible or to find nodes
that are compatible, I would like to add helpers to the fdt routines.

This way the drivers can check if they "match" to a node by simply
calling:

        if (fdt_node_compatible(ma->ma_node, "samsung,exynos4210-ehci"))
                return (1);

Sometimes it's helpful to find any node that is compatible.  It can
be helpful for instance on finding the early uart.  Simplified example:

        if ((node = fdt_find_compatible("arm,pl011")) != NULL)
                pl011cnattach(...);

Thoughts? ok?

Patrick

diff --git sys/dev/ofw/fdt.c sys/dev/ofw/fdt.c
index 4cf7248..3fdbd63 100644
--- sys/dev/ofw/fdt.c
+++ sys/dev/ofw/fdt.c
@@ -34,6 +34,7 @@ void  *skip_node(void *);
 void   *fdt_parent_node_recurse(void *, void *);
 int     fdt_node_property_int(void *, char *, int *);
 int     fdt_node_property_ints(void *, char *, int *, int);
+void   *fdt_find_compatible_node(void *, char *);
 int     fdt_translate_memory_address(void *, struct fdt_memory *);
 #ifdef DEBUG
 void    fdt_print_node_recurse(void *, int);
@@ -393,6 +394,62 @@ fdt_parent_node(void *node)
 }
 
 /*
+ * Find the first node which is compatible.
+ */
+void *
+fdt_find_compatible_node(void *node, char *compatible)
+{
+       void *child;
+
+       while (node != NULL) {
+               if (fdt_node_compatible(node, compatible))
+                       return node;
+
+               child = fdt_child_node(node);
+               if (child != NULL) {
+                       child = fdt_find_compatible_node(
+                          fdt_child_node(node), compatible);
+                       if (child != NULL)
+                               return child;
+               }
+
+               node = fdt_next_node(node);
+       }
+
+       return NULL;
+}
+
+void *
+fdt_find_compatible(char *compatible)
+{
+       return fdt_find_compatible_node(fdt_next_node(0), compatible);
+}
+
+/*
+ * Check that node is compatible.
+ */
+int
+fdt_node_compatible(void *node, char *compatible)
+{
+       char *data;
+       int len, clen = strlen(compatible);
+
+       if (node == NULL)
+               return 0;
+
+       len = fdt_node_property(node, "compatible", &data);
+       while (len > 0 && len >= clen + 1) {
+               if (strlen(data) == clen)
+                       if (!strncmp(data, compatible, clen))
+                               return 1;
+               len -= (strlen(data) + 1);
+               data += (strlen(data) + 1);
+       }
+
+       return 0;
+}
+
+/*
  * Translate memory address depending on parent's range.
  *
  * Ranges are a way of mapping one address to another.  This ranges attribute
diff --git sys/dev/ofw/fdt.h sys/dev/ofw/fdt.h
index ff5ef0d..0cdb459 100644
--- sys/dev/ofw/fdt.h
+++ sys/dev/ofw/fdt.h
@@ -60,6 +60,8 @@ char  *fdt_node_name(void *);
 void   *fdt_find_node(char *);
 int     fdt_node_property(void *, char *, char **);
 void   *fdt_parent_node(void *);
+void   *fdt_find_compatible(char *);
+int     fdt_node_compatible(void *, char *);
 int     fdt_get_memory_address(void *, int, struct fdt_memory *);
 #ifdef DEBUG
 void   *fdt_print_property(void *, int);

Reply via email to