fdt_ro.c revision 1.1.1.2 1 1.1.1.2 skrll /* $NetBSD: fdt_ro.c,v 1.1.1.2 2017/06/08 15:53:12 skrll Exp $ */
2 1.1.1.2 skrll
3 1.1 macallan /*
4 1.1 macallan * libfdt - Flat Device Tree manipulation
5 1.1 macallan * Copyright (C) 2006 David Gibson, IBM Corporation.
6 1.1 macallan *
7 1.1 macallan * libfdt is dual licensed: you can use it either under the terms of
8 1.1 macallan * the GPL, or the BSD license, at your option.
9 1.1 macallan *
10 1.1 macallan * a) This library is free software; you can redistribute it and/or
11 1.1 macallan * modify it under the terms of the GNU General Public License as
12 1.1 macallan * published by the Free Software Foundation; either version 2 of the
13 1.1 macallan * License, or (at your option) any later version.
14 1.1 macallan *
15 1.1 macallan * This library is distributed in the hope that it will be useful,
16 1.1 macallan * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 1.1 macallan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 1.1 macallan * GNU General Public License for more details.
19 1.1 macallan *
20 1.1 macallan * You should have received a copy of the GNU General Public
21 1.1 macallan * License along with this library; if not, write to the Free
22 1.1 macallan * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
23 1.1 macallan * MA 02110-1301 USA
24 1.1 macallan *
25 1.1 macallan * Alternatively,
26 1.1 macallan *
27 1.1 macallan * b) Redistribution and use in source and binary forms, with or
28 1.1 macallan * without modification, are permitted provided that the following
29 1.1 macallan * conditions are met:
30 1.1 macallan *
31 1.1 macallan * 1. Redistributions of source code must retain the above
32 1.1 macallan * copyright notice, this list of conditions and the following
33 1.1 macallan * disclaimer.
34 1.1 macallan * 2. Redistributions in binary form must reproduce the above
35 1.1 macallan * copyright notice, this list of conditions and the following
36 1.1 macallan * disclaimer in the documentation and/or other materials
37 1.1 macallan * provided with the distribution.
38 1.1 macallan *
39 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
40 1.1 macallan * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
41 1.1 macallan * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
42 1.1 macallan * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43 1.1 macallan * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
44 1.1 macallan * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 1.1 macallan * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 1.1 macallan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 1.1 macallan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 1.1 macallan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
50 1.1 macallan * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
51 1.1 macallan * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 1.1 macallan */
53 1.1 macallan #include "libfdt_env.h"
54 1.1 macallan
55 1.1 macallan #include <fdt.h>
56 1.1 macallan #include <libfdt.h>
57 1.1 macallan
58 1.1 macallan #include "libfdt_internal.h"
59 1.1 macallan
60 1.1 macallan static int _fdt_nodename_eq(const void *fdt, int offset,
61 1.1 macallan const char *s, int len)
62 1.1 macallan {
63 1.1 macallan const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
64 1.1 macallan
65 1.1 macallan if (! p)
66 1.1 macallan /* short match */
67 1.1 macallan return 0;
68 1.1 macallan
69 1.1 macallan if (memcmp(p, s, len) != 0)
70 1.1 macallan return 0;
71 1.1 macallan
72 1.1 macallan if (p[len] == '\0')
73 1.1 macallan return 1;
74 1.1 macallan else if (!memchr(s, '@', len) && (p[len] == '@'))
75 1.1 macallan return 1;
76 1.1 macallan else
77 1.1 macallan return 0;
78 1.1 macallan }
79 1.1 macallan
80 1.1 macallan const char *fdt_string(const void *fdt, int stroffset)
81 1.1 macallan {
82 1.1 macallan return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
83 1.1 macallan }
84 1.1 macallan
85 1.1 macallan static int _fdt_string_eq(const void *fdt, int stroffset,
86 1.1 macallan const char *s, int len)
87 1.1 macallan {
88 1.1 macallan const char *p = fdt_string(fdt, stroffset);
89 1.1 macallan
90 1.1 macallan return (strlen(p) == len) && (memcmp(p, s, len) == 0);
91 1.1 macallan }
92 1.1 macallan
93 1.1.1.2 skrll uint32_t fdt_get_max_phandle(const void *fdt)
94 1.1.1.2 skrll {
95 1.1.1.2 skrll uint32_t max_phandle = 0;
96 1.1.1.2 skrll int offset;
97 1.1.1.2 skrll
98 1.1.1.2 skrll for (offset = fdt_next_node(fdt, -1, NULL);;
99 1.1.1.2 skrll offset = fdt_next_node(fdt, offset, NULL)) {
100 1.1.1.2 skrll uint32_t phandle;
101 1.1.1.2 skrll
102 1.1.1.2 skrll if (offset == -FDT_ERR_NOTFOUND)
103 1.1.1.2 skrll return max_phandle;
104 1.1.1.2 skrll
105 1.1.1.2 skrll if (offset < 0)
106 1.1.1.2 skrll return (uint32_t)-1;
107 1.1.1.2 skrll
108 1.1.1.2 skrll phandle = fdt_get_phandle(fdt, offset);
109 1.1.1.2 skrll if (phandle == (uint32_t)-1)
110 1.1.1.2 skrll continue;
111 1.1.1.2 skrll
112 1.1.1.2 skrll if (phandle > max_phandle)
113 1.1.1.2 skrll max_phandle = phandle;
114 1.1.1.2 skrll }
115 1.1.1.2 skrll
116 1.1.1.2 skrll return 0;
117 1.1.1.2 skrll }
118 1.1.1.2 skrll
119 1.1 macallan int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
120 1.1 macallan {
121 1.1 macallan FDT_CHECK_HEADER(fdt);
122 1.1 macallan *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
123 1.1 macallan *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
124 1.1 macallan return 0;
125 1.1 macallan }
126 1.1 macallan
127 1.1 macallan int fdt_num_mem_rsv(const void *fdt)
128 1.1 macallan {
129 1.1 macallan int i = 0;
130 1.1 macallan
131 1.1 macallan while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
132 1.1 macallan i++;
133 1.1 macallan return i;
134 1.1 macallan }
135 1.1 macallan
136 1.1 macallan static int _nextprop(const void *fdt, int offset)
137 1.1 macallan {
138 1.1 macallan uint32_t tag;
139 1.1 macallan int nextoffset;
140 1.1 macallan
141 1.1 macallan do {
142 1.1 macallan tag = fdt_next_tag(fdt, offset, &nextoffset);
143 1.1 macallan
144 1.1 macallan switch (tag) {
145 1.1 macallan case FDT_END:
146 1.1 macallan if (nextoffset >= 0)
147 1.1 macallan return -FDT_ERR_BADSTRUCTURE;
148 1.1 macallan else
149 1.1 macallan return nextoffset;
150 1.1 macallan
151 1.1 macallan case FDT_PROP:
152 1.1 macallan return offset;
153 1.1 macallan }
154 1.1 macallan offset = nextoffset;
155 1.1 macallan } while (tag == FDT_NOP);
156 1.1 macallan
157 1.1 macallan return -FDT_ERR_NOTFOUND;
158 1.1 macallan }
159 1.1 macallan
160 1.1 macallan int fdt_subnode_offset_namelen(const void *fdt, int offset,
161 1.1 macallan const char *name, int namelen)
162 1.1 macallan {
163 1.1 macallan int depth;
164 1.1 macallan
165 1.1 macallan FDT_CHECK_HEADER(fdt);
166 1.1 macallan
167 1.1 macallan for (depth = 0;
168 1.1 macallan (offset >= 0) && (depth >= 0);
169 1.1 macallan offset = fdt_next_node(fdt, offset, &depth))
170 1.1 macallan if ((depth == 1)
171 1.1 macallan && _fdt_nodename_eq(fdt, offset, name, namelen))
172 1.1 macallan return offset;
173 1.1 macallan
174 1.1 macallan if (depth < 0)
175 1.1 macallan return -FDT_ERR_NOTFOUND;
176 1.1 macallan return offset; /* error */
177 1.1 macallan }
178 1.1 macallan
179 1.1 macallan int fdt_subnode_offset(const void *fdt, int parentoffset,
180 1.1 macallan const char *name)
181 1.1 macallan {
182 1.1 macallan return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
183 1.1 macallan }
184 1.1 macallan
185 1.1 macallan int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
186 1.1 macallan {
187 1.1 macallan const char *end = path + namelen;
188 1.1 macallan const char *p = path;
189 1.1 macallan int offset = 0;
190 1.1 macallan
191 1.1 macallan FDT_CHECK_HEADER(fdt);
192 1.1 macallan
193 1.1 macallan /* see if we have an alias */
194 1.1 macallan if (*path != '/') {
195 1.1 macallan const char *q = memchr(path, '/', end - p);
196 1.1 macallan
197 1.1 macallan if (!q)
198 1.1 macallan q = end;
199 1.1 macallan
200 1.1 macallan p = fdt_get_alias_namelen(fdt, p, q - p);
201 1.1 macallan if (!p)
202 1.1 macallan return -FDT_ERR_BADPATH;
203 1.1 macallan offset = fdt_path_offset(fdt, p);
204 1.1 macallan
205 1.1 macallan p = q;
206 1.1 macallan }
207 1.1 macallan
208 1.1 macallan while (p < end) {
209 1.1 macallan const char *q;
210 1.1 macallan
211 1.1 macallan while (*p == '/') {
212 1.1 macallan p++;
213 1.1 macallan if (p == end)
214 1.1 macallan return offset;
215 1.1 macallan }
216 1.1 macallan q = memchr(p, '/', end - p);
217 1.1 macallan if (! q)
218 1.1 macallan q = end;
219 1.1 macallan
220 1.1 macallan offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
221 1.1 macallan if (offset < 0)
222 1.1 macallan return offset;
223 1.1 macallan
224 1.1 macallan p = q;
225 1.1 macallan }
226 1.1 macallan
227 1.1 macallan return offset;
228 1.1 macallan }
229 1.1 macallan
230 1.1 macallan int fdt_path_offset(const void *fdt, const char *path)
231 1.1 macallan {
232 1.1 macallan return fdt_path_offset_namelen(fdt, path, strlen(path));
233 1.1 macallan }
234 1.1 macallan
235 1.1 macallan const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
236 1.1 macallan {
237 1.1 macallan const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
238 1.1 macallan int err;
239 1.1 macallan
240 1.1 macallan if (((err = fdt_check_header(fdt)) != 0)
241 1.1 macallan || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
242 1.1 macallan goto fail;
243 1.1 macallan
244 1.1 macallan if (len)
245 1.1 macallan *len = strlen(nh->name);
246 1.1 macallan
247 1.1 macallan return nh->name;
248 1.1 macallan
249 1.1 macallan fail:
250 1.1 macallan if (len)
251 1.1 macallan *len = err;
252 1.1 macallan return NULL;
253 1.1 macallan }
254 1.1 macallan
255 1.1 macallan int fdt_first_property_offset(const void *fdt, int nodeoffset)
256 1.1 macallan {
257 1.1 macallan int offset;
258 1.1 macallan
259 1.1 macallan if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
260 1.1 macallan return offset;
261 1.1 macallan
262 1.1 macallan return _nextprop(fdt, offset);
263 1.1 macallan }
264 1.1 macallan
265 1.1 macallan int fdt_next_property_offset(const void *fdt, int offset)
266 1.1 macallan {
267 1.1 macallan if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
268 1.1 macallan return offset;
269 1.1 macallan
270 1.1 macallan return _nextprop(fdt, offset);
271 1.1 macallan }
272 1.1 macallan
273 1.1 macallan const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
274 1.1 macallan int offset,
275 1.1 macallan int *lenp)
276 1.1 macallan {
277 1.1 macallan int err;
278 1.1 macallan const struct fdt_property *prop;
279 1.1 macallan
280 1.1 macallan if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
281 1.1 macallan if (lenp)
282 1.1 macallan *lenp = err;
283 1.1 macallan return NULL;
284 1.1 macallan }
285 1.1 macallan
286 1.1 macallan prop = _fdt_offset_ptr(fdt, offset);
287 1.1 macallan
288 1.1 macallan if (lenp)
289 1.1 macallan *lenp = fdt32_to_cpu(prop->len);
290 1.1 macallan
291 1.1 macallan return prop;
292 1.1 macallan }
293 1.1 macallan
294 1.1 macallan const struct fdt_property *fdt_get_property_namelen(const void *fdt,
295 1.1 macallan int offset,
296 1.1 macallan const char *name,
297 1.1 macallan int namelen, int *lenp)
298 1.1 macallan {
299 1.1 macallan for (offset = fdt_first_property_offset(fdt, offset);
300 1.1 macallan (offset >= 0);
301 1.1 macallan (offset = fdt_next_property_offset(fdt, offset))) {
302 1.1 macallan const struct fdt_property *prop;
303 1.1 macallan
304 1.1 macallan if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
305 1.1 macallan offset = -FDT_ERR_INTERNAL;
306 1.1 macallan break;
307 1.1 macallan }
308 1.1 macallan if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
309 1.1 macallan name, namelen))
310 1.1 macallan return prop;
311 1.1 macallan }
312 1.1 macallan
313 1.1 macallan if (lenp)
314 1.1 macallan *lenp = offset;
315 1.1 macallan return NULL;
316 1.1 macallan }
317 1.1 macallan
318 1.1 macallan const struct fdt_property *fdt_get_property(const void *fdt,
319 1.1 macallan int nodeoffset,
320 1.1 macallan const char *name, int *lenp)
321 1.1 macallan {
322 1.1 macallan return fdt_get_property_namelen(fdt, nodeoffset, name,
323 1.1 macallan strlen(name), lenp);
324 1.1 macallan }
325 1.1 macallan
326 1.1 macallan const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
327 1.1 macallan const char *name, int namelen, int *lenp)
328 1.1 macallan {
329 1.1 macallan const struct fdt_property *prop;
330 1.1 macallan
331 1.1 macallan prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
332 1.1 macallan if (! prop)
333 1.1 macallan return NULL;
334 1.1 macallan
335 1.1 macallan return prop->data;
336 1.1 macallan }
337 1.1 macallan
338 1.1 macallan const void *fdt_getprop_by_offset(const void *fdt, int offset,
339 1.1 macallan const char **namep, int *lenp)
340 1.1 macallan {
341 1.1 macallan const struct fdt_property *prop;
342 1.1 macallan
343 1.1 macallan prop = fdt_get_property_by_offset(fdt, offset, lenp);
344 1.1 macallan if (!prop)
345 1.1 macallan return NULL;
346 1.1 macallan if (namep)
347 1.1 macallan *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
348 1.1 macallan return prop->data;
349 1.1 macallan }
350 1.1 macallan
351 1.1 macallan const void *fdt_getprop(const void *fdt, int nodeoffset,
352 1.1 macallan const char *name, int *lenp)
353 1.1 macallan {
354 1.1 macallan return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
355 1.1 macallan }
356 1.1 macallan
357 1.1 macallan uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
358 1.1 macallan {
359 1.1 macallan const fdt32_t *php;
360 1.1 macallan int len;
361 1.1 macallan
362 1.1 macallan /* FIXME: This is a bit sub-optimal, since we potentially scan
363 1.1 macallan * over all the properties twice. */
364 1.1 macallan php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
365 1.1 macallan if (!php || (len != sizeof(*php))) {
366 1.1 macallan php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
367 1.1 macallan if (!php || (len != sizeof(*php)))
368 1.1 macallan return 0;
369 1.1 macallan }
370 1.1 macallan
371 1.1 macallan return fdt32_to_cpu(*php);
372 1.1 macallan }
373 1.1 macallan
374 1.1 macallan const char *fdt_get_alias_namelen(const void *fdt,
375 1.1 macallan const char *name, int namelen)
376 1.1 macallan {
377 1.1 macallan int aliasoffset;
378 1.1 macallan
379 1.1 macallan aliasoffset = fdt_path_offset(fdt, "/aliases");
380 1.1 macallan if (aliasoffset < 0)
381 1.1 macallan return NULL;
382 1.1 macallan
383 1.1 macallan return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
384 1.1 macallan }
385 1.1 macallan
386 1.1 macallan const char *fdt_get_alias(const void *fdt, const char *name)
387 1.1 macallan {
388 1.1 macallan return fdt_get_alias_namelen(fdt, name, strlen(name));
389 1.1 macallan }
390 1.1 macallan
391 1.1 macallan int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
392 1.1 macallan {
393 1.1 macallan int pdepth = 0, p = 0;
394 1.1 macallan int offset, depth, namelen;
395 1.1 macallan const char *name;
396 1.1 macallan
397 1.1 macallan FDT_CHECK_HEADER(fdt);
398 1.1 macallan
399 1.1 macallan if (buflen < 2)
400 1.1 macallan return -FDT_ERR_NOSPACE;
401 1.1 macallan
402 1.1 macallan for (offset = 0, depth = 0;
403 1.1 macallan (offset >= 0) && (offset <= nodeoffset);
404 1.1 macallan offset = fdt_next_node(fdt, offset, &depth)) {
405 1.1 macallan while (pdepth > depth) {
406 1.1 macallan do {
407 1.1 macallan p--;
408 1.1 macallan } while (buf[p-1] != '/');
409 1.1 macallan pdepth--;
410 1.1 macallan }
411 1.1 macallan
412 1.1 macallan if (pdepth >= depth) {
413 1.1 macallan name = fdt_get_name(fdt, offset, &namelen);
414 1.1 macallan if (!name)
415 1.1 macallan return namelen;
416 1.1 macallan if ((p + namelen + 1) <= buflen) {
417 1.1 macallan memcpy(buf + p, name, namelen);
418 1.1 macallan p += namelen;
419 1.1 macallan buf[p++] = '/';
420 1.1 macallan pdepth++;
421 1.1 macallan }
422 1.1 macallan }
423 1.1 macallan
424 1.1 macallan if (offset == nodeoffset) {
425 1.1 macallan if (pdepth < (depth + 1))
426 1.1 macallan return -FDT_ERR_NOSPACE;
427 1.1 macallan
428 1.1 macallan if (p > 1) /* special case so that root path is "/", not "" */
429 1.1 macallan p--;
430 1.1 macallan buf[p] = '\0';
431 1.1 macallan return 0;
432 1.1 macallan }
433 1.1 macallan }
434 1.1 macallan
435 1.1 macallan if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
436 1.1 macallan return -FDT_ERR_BADOFFSET;
437 1.1 macallan else if (offset == -FDT_ERR_BADOFFSET)
438 1.1 macallan return -FDT_ERR_BADSTRUCTURE;
439 1.1 macallan
440 1.1 macallan return offset; /* error from fdt_next_node() */
441 1.1 macallan }
442 1.1 macallan
443 1.1 macallan int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
444 1.1 macallan int supernodedepth, int *nodedepth)
445 1.1 macallan {
446 1.1 macallan int offset, depth;
447 1.1 macallan int supernodeoffset = -FDT_ERR_INTERNAL;
448 1.1 macallan
449 1.1 macallan FDT_CHECK_HEADER(fdt);
450 1.1 macallan
451 1.1 macallan if (supernodedepth < 0)
452 1.1 macallan return -FDT_ERR_NOTFOUND;
453 1.1 macallan
454 1.1 macallan for (offset = 0, depth = 0;
455 1.1 macallan (offset >= 0) && (offset <= nodeoffset);
456 1.1 macallan offset = fdt_next_node(fdt, offset, &depth)) {
457 1.1 macallan if (depth == supernodedepth)
458 1.1 macallan supernodeoffset = offset;
459 1.1 macallan
460 1.1 macallan if (offset == nodeoffset) {
461 1.1 macallan if (nodedepth)
462 1.1 macallan *nodedepth = depth;
463 1.1 macallan
464 1.1 macallan if (supernodedepth > depth)
465 1.1 macallan return -FDT_ERR_NOTFOUND;
466 1.1 macallan else
467 1.1 macallan return supernodeoffset;
468 1.1 macallan }
469 1.1 macallan }
470 1.1 macallan
471 1.1 macallan if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
472 1.1 macallan return -FDT_ERR_BADOFFSET;
473 1.1 macallan else if (offset == -FDT_ERR_BADOFFSET)
474 1.1 macallan return -FDT_ERR_BADSTRUCTURE;
475 1.1 macallan
476 1.1 macallan return offset; /* error from fdt_next_node() */
477 1.1 macallan }
478 1.1 macallan
479 1.1 macallan int fdt_node_depth(const void *fdt, int nodeoffset)
480 1.1 macallan {
481 1.1 macallan int nodedepth;
482 1.1 macallan int err;
483 1.1 macallan
484 1.1 macallan err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
485 1.1 macallan if (err)
486 1.1 macallan return (err < 0) ? err : -FDT_ERR_INTERNAL;
487 1.1 macallan return nodedepth;
488 1.1 macallan }
489 1.1 macallan
490 1.1 macallan int fdt_parent_offset(const void *fdt, int nodeoffset)
491 1.1 macallan {
492 1.1 macallan int nodedepth = fdt_node_depth(fdt, nodeoffset);
493 1.1 macallan
494 1.1 macallan if (nodedepth < 0)
495 1.1 macallan return nodedepth;
496 1.1 macallan return fdt_supernode_atdepth_offset(fdt, nodeoffset,
497 1.1 macallan nodedepth - 1, NULL);
498 1.1 macallan }
499 1.1 macallan
500 1.1 macallan int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
501 1.1 macallan const char *propname,
502 1.1 macallan const void *propval, int proplen)
503 1.1 macallan {
504 1.1 macallan int offset;
505 1.1 macallan const void *val;
506 1.1 macallan int len;
507 1.1 macallan
508 1.1 macallan FDT_CHECK_HEADER(fdt);
509 1.1 macallan
510 1.1 macallan /* FIXME: The algorithm here is pretty horrible: we scan each
511 1.1 macallan * property of a node in fdt_getprop(), then if that didn't
512 1.1 macallan * find what we want, we scan over them again making our way
513 1.1 macallan * to the next node. Still it's the easiest to implement
514 1.1 macallan * approach; performance can come later. */
515 1.1 macallan for (offset = fdt_next_node(fdt, startoffset, NULL);
516 1.1 macallan offset >= 0;
517 1.1 macallan offset = fdt_next_node(fdt, offset, NULL)) {
518 1.1 macallan val = fdt_getprop(fdt, offset, propname, &len);
519 1.1 macallan if (val && (len == proplen)
520 1.1 macallan && (memcmp(val, propval, len) == 0))
521 1.1 macallan return offset;
522 1.1 macallan }
523 1.1 macallan
524 1.1 macallan return offset; /* error from fdt_next_node() */
525 1.1 macallan }
526 1.1 macallan
527 1.1 macallan int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
528 1.1 macallan {
529 1.1 macallan int offset;
530 1.1 macallan
531 1.1 macallan if ((phandle == 0) || (phandle == -1))
532 1.1 macallan return -FDT_ERR_BADPHANDLE;
533 1.1 macallan
534 1.1 macallan FDT_CHECK_HEADER(fdt);
535 1.1 macallan
536 1.1 macallan /* FIXME: The algorithm here is pretty horrible: we
537 1.1 macallan * potentially scan each property of a node in
538 1.1 macallan * fdt_get_phandle(), then if that didn't find what
539 1.1 macallan * we want, we scan over them again making our way to the next
540 1.1 macallan * node. Still it's the easiest to implement approach;
541 1.1 macallan * performance can come later. */
542 1.1 macallan for (offset = fdt_next_node(fdt, -1, NULL);
543 1.1 macallan offset >= 0;
544 1.1 macallan offset = fdt_next_node(fdt, offset, NULL)) {
545 1.1 macallan if (fdt_get_phandle(fdt, offset) == phandle)
546 1.1 macallan return offset;
547 1.1 macallan }
548 1.1 macallan
549 1.1 macallan return offset; /* error from fdt_next_node() */
550 1.1 macallan }
551 1.1 macallan
552 1.1 macallan int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
553 1.1 macallan {
554 1.1 macallan int len = strlen(str);
555 1.1 macallan const char *p;
556 1.1 macallan
557 1.1 macallan while (listlen >= len) {
558 1.1 macallan if (memcmp(str, strlist, len+1) == 0)
559 1.1 macallan return 1;
560 1.1 macallan p = memchr(strlist, '\0', listlen);
561 1.1 macallan if (!p)
562 1.1 macallan return 0; /* malformed strlist.. */
563 1.1 macallan listlen -= (p-strlist) + 1;
564 1.1 macallan strlist = p + 1;
565 1.1 macallan }
566 1.1 macallan return 0;
567 1.1 macallan }
568 1.1 macallan
569 1.1 macallan int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
570 1.1 macallan {
571 1.1 macallan const char *list, *end;
572 1.1 macallan int length, count = 0;
573 1.1 macallan
574 1.1 macallan list = fdt_getprop(fdt, nodeoffset, property, &length);
575 1.1 macallan if (!list)
576 1.1.1.2 skrll return length;
577 1.1 macallan
578 1.1 macallan end = list + length;
579 1.1 macallan
580 1.1 macallan while (list < end) {
581 1.1 macallan length = strnlen(list, end - list) + 1;
582 1.1 macallan
583 1.1 macallan /* Abort if the last string isn't properly NUL-terminated. */
584 1.1 macallan if (list + length > end)
585 1.1 macallan return -FDT_ERR_BADVALUE;
586 1.1 macallan
587 1.1 macallan list += length;
588 1.1 macallan count++;
589 1.1 macallan }
590 1.1 macallan
591 1.1 macallan return count;
592 1.1 macallan }
593 1.1 macallan
594 1.1 macallan int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
595 1.1 macallan const char *string)
596 1.1 macallan {
597 1.1 macallan int length, len, idx = 0;
598 1.1 macallan const char *list, *end;
599 1.1 macallan
600 1.1 macallan list = fdt_getprop(fdt, nodeoffset, property, &length);
601 1.1 macallan if (!list)
602 1.1.1.2 skrll return length;
603 1.1 macallan
604 1.1 macallan len = strlen(string) + 1;
605 1.1 macallan end = list + length;
606 1.1 macallan
607 1.1 macallan while (list < end) {
608 1.1 macallan length = strnlen(list, end - list) + 1;
609 1.1 macallan
610 1.1 macallan /* Abort if the last string isn't properly NUL-terminated. */
611 1.1 macallan if (list + length > end)
612 1.1 macallan return -FDT_ERR_BADVALUE;
613 1.1 macallan
614 1.1 macallan if (length == len && memcmp(list, string, length) == 0)
615 1.1 macallan return idx;
616 1.1 macallan
617 1.1 macallan list += length;
618 1.1 macallan idx++;
619 1.1 macallan }
620 1.1 macallan
621 1.1 macallan return -FDT_ERR_NOTFOUND;
622 1.1 macallan }
623 1.1 macallan
624 1.1 macallan const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
625 1.1 macallan const char *property, int idx,
626 1.1 macallan int *lenp)
627 1.1 macallan {
628 1.1 macallan const char *list, *end;
629 1.1 macallan int length;
630 1.1 macallan
631 1.1 macallan list = fdt_getprop(fdt, nodeoffset, property, &length);
632 1.1 macallan if (!list) {
633 1.1 macallan if (lenp)
634 1.1 macallan *lenp = length;
635 1.1 macallan
636 1.1 macallan return NULL;
637 1.1 macallan }
638 1.1 macallan
639 1.1 macallan end = list + length;
640 1.1 macallan
641 1.1 macallan while (list < end) {
642 1.1 macallan length = strnlen(list, end - list) + 1;
643 1.1 macallan
644 1.1 macallan /* Abort if the last string isn't properly NUL-terminated. */
645 1.1 macallan if (list + length > end) {
646 1.1 macallan if (lenp)
647 1.1 macallan *lenp = -FDT_ERR_BADVALUE;
648 1.1 macallan
649 1.1 macallan return NULL;
650 1.1 macallan }
651 1.1 macallan
652 1.1 macallan if (idx == 0) {
653 1.1 macallan if (lenp)
654 1.1 macallan *lenp = length - 1;
655 1.1 macallan
656 1.1 macallan return list;
657 1.1 macallan }
658 1.1 macallan
659 1.1 macallan list += length;
660 1.1 macallan idx--;
661 1.1 macallan }
662 1.1 macallan
663 1.1 macallan if (lenp)
664 1.1 macallan *lenp = -FDT_ERR_NOTFOUND;
665 1.1 macallan
666 1.1 macallan return NULL;
667 1.1 macallan }
668 1.1 macallan
669 1.1 macallan int fdt_node_check_compatible(const void *fdt, int nodeoffset,
670 1.1 macallan const char *compatible)
671 1.1 macallan {
672 1.1 macallan const void *prop;
673 1.1 macallan int len;
674 1.1 macallan
675 1.1 macallan prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
676 1.1 macallan if (!prop)
677 1.1 macallan return len;
678 1.1.1.2 skrll
679 1.1.1.2 skrll return !fdt_stringlist_contains(prop, len, compatible);
680 1.1 macallan }
681 1.1 macallan
682 1.1 macallan int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
683 1.1 macallan const char *compatible)
684 1.1 macallan {
685 1.1 macallan int offset, err;
686 1.1 macallan
687 1.1 macallan FDT_CHECK_HEADER(fdt);
688 1.1 macallan
689 1.1 macallan /* FIXME: The algorithm here is pretty horrible: we scan each
690 1.1 macallan * property of a node in fdt_node_check_compatible(), then if
691 1.1 macallan * that didn't find what we want, we scan over them again
692 1.1 macallan * making our way to the next node. Still it's the easiest to
693 1.1 macallan * implement approach; performance can come later. */
694 1.1 macallan for (offset = fdt_next_node(fdt, startoffset, NULL);
695 1.1 macallan offset >= 0;
696 1.1 macallan offset = fdt_next_node(fdt, offset, NULL)) {
697 1.1 macallan err = fdt_node_check_compatible(fdt, offset, compatible);
698 1.1 macallan if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
699 1.1 macallan return err;
700 1.1 macallan else if (err == 0)
701 1.1 macallan return offset;
702 1.1 macallan }
703 1.1 macallan
704 1.1 macallan return offset; /* error from fdt_next_node() */
705 1.1 macallan }
706