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 19int 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 25bool 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 37struct 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 58void 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 71int 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 98struct 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 107struct 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 112struct 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 123struct 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 128char *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 139char *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 146char *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 160uint32_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 175struct 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 201struct 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 212void 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 250void 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