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
node_cmp(const void * a,const void * b)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
node_name_eq(const struct ufdt_node * node,const char * name,int len)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
ufdt_node_construct(void * fdtp,fdt32_t * fdt_tag_ptr)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
ufdt_node_destruct(struct ufdt_node * node)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
ufdt_node_add_child(struct ufdt_node * parent,struct ufdt_node * child)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
ufdt_node_get_subnode_by_name_len(const struct ufdt_node * node,const char * name,int len)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
ufdt_node_get_subnode_by_name(const struct ufdt_node * node,const char * name)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
ufdt_node_get_property_by_name_len(const struct ufdt_node * node,const char * name,int len)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
ufdt_node_get_property_by_name(const struct ufdt_node * node,const char * name)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
ufdt_node_get_fdt_prop_data(const struct ufdt_node * node,int * out_len)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
ufdt_node_get_fdt_prop_data_by_name_len(const struct ufdt_node * node,const char * name,int len,int * out_len)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
ufdt_node_get_fdt_prop_data_by_name(const struct ufdt_node * node,const char * name,int * out_len)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
ufdt_node_get_phandle(const struct ufdt_node * node)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
ufdt_node_get_node_by_path_len(const struct ufdt_node * node,const char * path,int len)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
ufdt_node_get_node_by_path(const struct ufdt_node * node,const char * path)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
ufdt_node_print(const struct ufdt_node * node,int depth)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
ufdt_node_map(struct ufdt_node * node,struct ufdt_node_closure closure)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