[POWERPC] Update PCI nodes in the 83xx/85xx boards device tree
[safe/jmp/linux-2.6] / arch / powerpc / boot / flatdevtree.c
index 0fa4f98..b732644 100644 (file)
@@ -246,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
                        if (rgn == FT_STRUCT)
                                ft_node_update_before(cxt, p, -nextra);
                }
-               *p -= nextra;
+               *pp -= nextra;
                cxt->rgn[rgn].start -= nextra;
                cxt->rgn[rgn].size += nextra;
                return 1;
@@ -429,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
 {
        int off, len;
 
-       off = lookup_string(cxt, name);
+       off = map_string(cxt, name);
        if (off == NO_STRING)
                return -1;
 
@@ -654,6 +654,19 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path)
        return ft_get_phandle(cxt, node);
 }
 
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+                         const char *srch_path)
+{
+       char *node;
+
+       node = ft_node_ph2node(cxt, top);
+       if (node == NULL)
+               return NULL;
+
+       node = ft_find_descendent(cxt, node, srch_path);
+       return ft_get_phandle(cxt, node);
+}
+
 void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
 {
        struct ft_atom atom;
@@ -715,20 +728,15 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
        return NULL;
 }
 
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+void *__ft_get_parent(struct ft_cxt *cxt, void *node)
 {
-       void *node;
        int d;
        struct ft_atom atom;
        char *p;
 
-       node = ft_node_ph2node(cxt, phandle);
-       if (node == NULL)
-               return NULL;
-
        for (d = 0; cxt->genealogy[d] != NULL; ++d)
                if (cxt->genealogy[d] == node)
-                       return cxt->genealogy[d > 0 ? d - 1 : 0];
+                       return d > 0 ? cxt->genealogy[d - 1] : NULL;
 
        /* have to do it the hard way... */
        p = ft_root_node(cxt);
@@ -740,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
                        if (node == atom.data) {
                                /* found it */
                                cxt->genealogy[d + 1] = NULL;
-                               return d > 0 ? cxt->genealogy[d - 1] : node;
+                               return d > 0 ? cxt->genealogy[d - 1] : NULL;
                        }
                        ++d;
                        break;
@@ -752,69 +760,158 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
        return NULL;
 }
 
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
-               void *buf, const unsigned int buflen)
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
 {
-       struct ft_atom atom;
-       void *node;
-       char *p;
-       int depth;
-       unsigned int size;
-
-       node = ft_node_ph2node(cxt, phandle);
+       void *node = ft_node_ph2node(cxt, phandle);
        if (node == NULL)
-               return -1;
+               return NULL;
 
-       depth = 0;
-       p = (char *)node;
+       node = __ft_get_parent(cxt, node);
+       return ft_get_phandle(cxt, node);
+}
 
-       while ((p = ft_next(cxt, p, &atom)) != NULL) {
+static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
+                                 const char *propname, unsigned int *len)
+{
+       struct ft_atom atom;
+       int depth = 0;
+
+       while ((node = ft_next(cxt, node, &atom)) != NULL) {
                switch (atom.tag) {
                case OF_DT_BEGIN_NODE:
                        ++depth;
                        break;
+
                case OF_DT_PROP:
-                       if ((depth != 1) || strcmp(atom.name, propname))
+                       if (depth != 1 || strcmp(atom.name, propname))
                                break;
-                       size = min(atom.size, buflen);
-                       memcpy(buf, atom.data, size);
-                       return atom.size;
+
+                       if (len)
+                               *len = atom.size;
+
+                       return atom.data;
+
                case OF_DT_END_NODE:
                        if (--depth <= 0)
-                               return -1;
+                               return NULL;
                }
        }
+
+       return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+               void *buf, const unsigned int buflen)
+{
+       const void *data;
+       unsigned int size;
+
+       void *node = ft_node_ph2node(cxt, phandle);
+       if (!node)
+               return -1;
+
+       data = __ft_get_prop(cxt, node, propname, &size);
+       if (data) {
+               unsigned int clipped_size = min(size, buflen);
+               memcpy(buf, data, clipped_size);
+               return size;
+       }
+
        return -1;
 }
 
+void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
+                                   const char *propname, const char *propval,
+                                   unsigned int proplen)
+{
+       struct ft_atom atom;
+       char *p = ft_root_node(cxt);
+       char *next;
+       int past_prev = prev ? 0 : 1;
+       int depth = -1;
+
+       while ((next = ft_next(cxt, p, &atom)) != NULL) {
+               const void *data;
+               unsigned int size;
+
+               switch (atom.tag) {
+               case OF_DT_BEGIN_NODE:
+                       depth++;
+
+                       if (prev == p) {
+                               past_prev = 1;
+                               break;
+                       }
+
+                       if (!past_prev || depth < 1)
+                               break;
+
+                       data = __ft_get_prop(cxt, p, propname, &size);
+                       if (!data || size != proplen)
+                               break;
+                       if (memcmp(data, propval, size))
+                               break;
+
+                       return p;
+
+               case OF_DT_END_NODE:
+                       if (depth-- == 0)
+                               return NULL;
+
+                       break;
+               }
+
+               p = next;
+       }
+
+       return NULL;
+}
+
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+                                 const char *propname, const char *propval,
+                                 int proplen)
+{
+       void *node = NULL;
+
+       if (prev) {
+               node = ft_node_ph2node(cxt, prev);
+
+               if (!node)
+                       return NULL;
+       }
+
+       node = __ft_find_node_by_prop_value(cxt, node, propname,
+                                           propval, proplen);
+       return ft_get_phandle(cxt, node);
+}
+
 int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
                const void *buf, const unsigned int buflen)
 {
        struct ft_atom atom;
        void *node;
        char *p, *next;
-       int nextra, depth;
+       int nextra;
 
        node = ft_node_ph2node(cxt, phandle);
        if (node == NULL)
                return -1;
 
-       depth = 0;
-       p = node;
+       next = ft_next(cxt, node, &atom);
+       if (atom.tag != OF_DT_BEGIN_NODE)
+               /* phandle didn't point to a node */
+               return -1;
+       p = next;
 
        while ((next = ft_next(cxt, p, &atom)) != NULL) {
                switch (atom.tag) {
-               case OF_DT_BEGIN_NODE:
-                       ++depth;
-                       break;
+               case OF_DT_BEGIN_NODE: /* properties must go before subnodes */
                case OF_DT_END_NODE:
-                       if (--depth > 0)
-                               break;
                        /* haven't found the property, insert here */
                        cxt->p = p;
                        return ft_prop(cxt, propname, buf, buflen);
                case OF_DT_PROP:
-                       if ((depth != 1) || strcmp(atom.name, propname))
+                       if (strcmp(atom.name, propname))
                                break;
                        /* found an existing property, overwrite it */
                        nextra = _ALIGN(buflen, 4) - _ALIGN(atom.size, 4);
@@ -863,19 +960,26 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
        return -1;
 }
 
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
 {
        struct ft_atom atom;
        char *p, *next;
        int depth = 0;
 
-       p = ft_root_node(cxt);
+       if (parent) {
+               p = ft_node_ph2node(cxt, parent);
+               if (!p)
+                       return NULL;
+       } else {
+               p = ft_root_node(cxt);
+       }
+
        while ((next = ft_next(cxt, p, &atom)) != NULL) {
                switch (atom.tag) {
                case OF_DT_BEGIN_NODE:
                        ++depth;
-                       if (depth == 1 && strcmp(atom.name, path) == 0)
-                               /* duplicate node path, return error */
+                       if (depth == 1 && strcmp(atom.name, name) == 0)
+                               /* duplicate node name, return error */
                                return NULL;
                        break;
                case OF_DT_END_NODE:
@@ -884,7 +988,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
                                break;
                        /* end of node, insert here */
                        cxt->p = p;
-                       ft_begin_node(cxt, path);
+                       ft_begin_node(cxt, name);
                        ft_end_node(cxt);
                        return p;
                }