Home | History | Annotate | Download | only in libufdt
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "libufdt.h"
     18 
     19 int node_cmp(const void *a, const void *b) {
     20   const struct ufdt_node *na = *(struct ufdt_node **)a;
     21   const struct ufdt_node *nb = *(struct ufdt_node **)b;
     22   return dto_strcmp(name_of(na), name_of(nb));
     23 }
     24 
     25 bool node_name_eq(const struct ufdt_node *node, const char *name, int len) {
     26   if (!node) return false;
     27   if (!name) return false;
     28   if (dto_strncmp(name_of(node), name, len) != 0) return false;
     29   if (name_of(node)[len] != '\0') return false;
     30   return true;
     31 }
     32 
     33 /*
     34  * ufdt_node methods.
     35  */
     36 
     37 struct ufdt_node *ufdt_node_construct(void *fdtp, fdt32_t *fdt_tag_ptr) {
     38   uint32_t tag = fdt32_to_cpu(*fdt_tag_ptr);
     39   if (tag == FDT_PROP) {
     40     const struct fdt_property *prop = (const struct fdt_property *)fdt_tag_ptr;
     41     struct fdt_prop_ufdt_node *res = dto_malloc(sizeof(struct fdt_prop_ufdt_node));
     42     if (res == NULL) return NULL;
     43     res->parent.fdt_tag_ptr = fdt_tag_ptr;
     44     res->parent.sibling = NULL;
     45     res->name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
     46     return (struct ufdt_node *)res;
     47   } else {
     48     struct fdt_node_ufdt_node *res = dto_malloc(sizeof(struct fdt_node_ufdt_node));
     49     if (res == NULL) return NULL;
     50     res->parent.fdt_tag_ptr = fdt_tag_ptr;
     51     res->parent.sibling = NULL;
     52     res->child = NULL;
     53     res->last_child_p = &res->child;
     54     return (struct ufdt_node *)res;
     55   }
     56 }
     57 
     58 void ufdt_node_destruct(struct ufdt_node *node) {
     59   if (node == NULL) return;
     60 
     61   if (tag_of(node) == FDT_BEGIN_NODE) {
     62     ufdt_node_destruct(((struct fdt_node_ufdt_node *)node)->child);
     63   }
     64 
     65   ufdt_node_destruct(node->sibling);
     66   dto_free(node);
     67 
     68   return;
     69 }
     70 
     71 int ufdt_node_add_child(struct ufdt_node *parent, struct ufdt_node *child) {
     72   if (!parent || !child) return -1;
     73   if (tag_of(parent) != FDT_BEGIN_NODE) return -1;
     74 
     75   int err = 0;
     76   uint32_t child_tag = tag_of(child);
     77 
     78   switch (child_tag) {
     79     case FDT_PROP:
     80     case FDT_BEGIN_NODE:
     81       // Append the child node to the last child of parant node
     82       *((struct fdt_node_ufdt_node *)parent)->last_child_p = child;
     83       ((struct fdt_node_ufdt_node *)parent)->last_child_p = &child->sibling;
     84       break;
     85 
     86     default:
     87       err = -1;
     88       dto_error("invalid children tag type\n");
     89   }
     90 
     91   return err;
     92 }
     93 
     94 /*
     95  * BEGIN of FDT_PROP related methods.
     96  */
     97 
     98 struct ufdt_node *ufdt_node_get_subnode_by_name_len(const struct ufdt_node *node,
     99                                                   const char *name, int len) {
    100   struct ufdt_node **it = NULL;
    101   for_each_node(it, node) {
    102     if (node_name_eq(*it, name, len)) return *it;
    103   }
    104   return NULL;
    105 }
    106 
    107 struct ufdt_node *ufdt_node_get_subnode_by_name(const struct ufdt_node *node,
    108                                               const char *name) {
    109   return ufdt_node_get_subnode_by_name_len(node, name, strlen(name));
    110 }
    111 
    112 struct ufdt_node *ufdt_node_get_property_by_name_len(
    113     const struct ufdt_node *node, const char *name, int len) {
    114   if (!node) return NULL;
    115 
    116   struct ufdt_node **it = NULL;
    117   for_each_prop(it, node) {
    118     if (node_name_eq(*it, name, len)) return *it;
    119   }
    120   return NULL;
    121 }
    122 
    123 struct ufdt_node *ufdt_node_get_property_by_name(const struct ufdt_node *node,
    124                                                  const char *name) {
    125   return ufdt_node_get_property_by_name_len(node, name, dto_strlen(name));
    126 }
    127 
    128 char *ufdt_node_get_fdt_prop_data(const struct ufdt_node *node, int *out_len) {
    129   if (!node || tag_of(node) != FDT_PROP) {
    130     return NULL;
    131   }
    132   const struct fdt_property *prop = (struct fdt_property *)node->fdt_tag_ptr;
    133   if (out_len != NULL) {
    134     *out_len = fdt32_to_cpu(prop->len);
    135   }
    136   return (char *)prop->data;
    137 }
    138 
    139 char *ufdt_node_get_fdt_prop_data_by_name_len(const struct ufdt_node *node,
    140                                               const char *name, int len,
    141                                               int *out_len) {
    142   return ufdt_node_get_fdt_prop_data(
    143       ufdt_node_get_property_by_name_len(node, name, len), out_len);
    144 }
    145 
    146 char *ufdt_node_get_fdt_prop_data_by_name(const struct ufdt_node *node,
    147                                           const char *name, int *out_len) {
    148   return ufdt_node_get_fdt_prop_data(ufdt_node_get_property_by_name(node, name),
    149                                      out_len);
    150 }
    151 
    152 /*
    153  * END of FDT_PROP related methods.
    154  */
    155 
    156 /*
    157  * BEGIN of searching-in-ufdt_node methods.
    158  */
    159 
    160 uint32_t ufdt_node_get_phandle(const struct ufdt_node *node) {
    161   if (!node || tag_of(node) != FDT_BEGIN_NODE) {
    162     return 0;
    163   }
    164   int len = 0;
    165   void *ptr = ufdt_node_get_fdt_prop_data_by_name(node, "phandle", &len);
    166   if (!ptr || len != sizeof(fdt32_t)) {
    167     ptr = ufdt_node_get_fdt_prop_data_by_name(node, "linux,phandle", &len);
    168     if (!ptr || len != sizeof(fdt32_t)) {
    169       return 0;
    170     }
    171   }
    172   return fdt32_to_cpu(*((fdt32_t *)ptr));
    173 }
    174 
    175 struct ufdt_node *ufdt_node_get_node_by_path_len(const struct ufdt_node *node,
    176                                                  const char *path, int len) {
    177   const char *end = path + len;
    178 
    179   struct ufdt_node *cur = (struct ufdt_node *)node;
    180 
    181   while (path < end) {
    182     while (path[0] == '/') path++;
    183     if (path == end) return cur;
    184 
    185     const char *next_slash;
    186     next_slash = dto_memchr(path, '/', end - path);
    187     if (!next_slash) next_slash = end;
    188 
    189     struct ufdt_node *next = NULL;
    190 
    191     next = ufdt_node_get_subnode_by_name_len(cur, path, next_slash - path);
    192 
    193     cur = next;
    194     path = next_slash;
    195     if (!cur) return cur;
    196   }
    197 
    198   return cur;
    199 }
    200 
    201 struct ufdt_node *ufdt_node_get_node_by_path(const struct ufdt_node *node,
    202                                              const char *path) {
    203   return ufdt_node_get_node_by_path_len(node, path, dto_strlen(path));
    204 }
    205 
    206 /*
    207  * END of searching-in-ufdt_node methods.
    208  */
    209 
    210 #define TAB_SIZE 2
    211 
    212 void ufdt_node_print(const struct ufdt_node *node, int depth) {
    213   if (!node) return;
    214 
    215   int i;
    216   for (i = 0; i < depth * TAB_SIZE; i++) dto_print(" ");
    217 
    218   uint32_t tag;
    219   tag = tag_of(node);
    220 
    221   switch (tag) {
    222     case FDT_BEGIN_NODE:
    223       dto_print("NODE ");
    224       break;
    225     case FDT_PROP:
    226       dto_print("PROP ");
    227       break;
    228     default:
    229       dto_print("UNKNOWN ");
    230       break;
    231   }
    232 
    233   if (name_of(node)) {
    234     dto_print(":%s:\n", name_of(node));
    235   } else {
    236     dto_print("node name is NULL.\n");
    237   }
    238 
    239   if (tag_of(node) == FDT_BEGIN_NODE) {
    240     struct ufdt_node **it;
    241 
    242     for_each_prop(it, node) ufdt_node_print(*it, depth + 1);
    243 
    244     for_each_node(it, node) ufdt_node_print(*it, depth + 1);
    245   }
    246 
    247   return;
    248 }
    249 
    250 void ufdt_node_map(struct ufdt_node *node, struct ufdt_node_closure closure) {
    251   if (node == NULL) return;
    252   closure.func(node, closure.env);
    253   if (tag_of(node) == FDT_BEGIN_NODE) {
    254     struct ufdt_node **it;
    255     for_each_prop(it, node) ufdt_node_map(*it, closure);
    256     for_each_node(it, node) ufdt_node_map(*it, closure);
    257   }
    258   return;
    259 }
    260