]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/FdtLib/fdt_ro.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / fdt_ro.c
CommitLineData
1e57a462 1/*\r
2 * libfdt - Flat Device Tree manipulation\r
3 * Copyright (C) 2006 David Gibson, IBM Corporation.\r
4 *\r
5 * libfdt is dual licensed: you can use it either under the terms of\r
6 * the GPL, or the BSD license, at your option.\r
7 *\r
8 * a) This library is free software; you can redistribute it and/or\r
9 * modify it under the terms of the GNU General Public License as\r
10 * published by the Free Software Foundation; either version 2 of the\r
11 * License, or (at your option) any later version.\r
12 *\r
13 * This library is distributed in the hope that it will be useful,\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
16 * GNU General Public License for more details.\r
17 *\r
18 * You should have received a copy of the GNU General Public\r
19 * License along with this library; if not, write to the Free\r
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,\r
21 * MA 02110-1301 USA\r
22 *\r
23 * Alternatively,\r
24 *\r
25 * b) Redistribution and use in source and binary forms, with or\r
26 * without modification, are permitted provided that the following\r
27 * conditions are met:\r
28 *\r
29 * 1. Redistributions of source code must retain the above\r
30 * copyright notice, this list of conditions and the following\r
31 * disclaimer.\r
32 * 2. Redistributions in binary form must reproduce the above\r
33 * copyright notice, this list of conditions and the following\r
34 * disclaimer in the documentation and/or other materials\r
35 * provided with the distribution.\r
36 *\r
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
50 */\r
51#include "libfdt_env.h"\r
52\r
53#include <fdt.h>\r
54#include <libfdt.h>\r
55\r
56#include "libfdt_internal.h"\r
57\r
e7108d0e
MK
58static int\r
59_fdt_nodename_eq (\r
60 const void *fdt,\r
61 int offset,\r
62 const char *s,\r
63 int len\r
64 )\r
1e57a462 65{\r
e7108d0e 66 const char *p = fdt_offset_ptr (fdt, offset + FDT_TAGSIZE, len+1);\r
1e57a462 67\r
e7108d0e
MK
68 if (!p) {\r
69 /* short match */\r
70 return 0;\r
71 }\r
1e57a462 72\r
e7108d0e
MK
73 if (memcmp (p, s, len) != 0) {\r
74 return 0;\r
75 }\r
1e57a462 76\r
e7108d0e
MK
77 if (p[len] == '\0') {\r
78 return 1;\r
79 } else if (!memchr (s, '@', len) && (p[len] == '@')) {\r
80 return 1;\r
81 } else {\r
82 return 0;\r
83 }\r
1e57a462 84}\r
85\r
e7108d0e
MK
86const char *\r
87fdt_string (\r
88 const void *fdt,\r
89 int stroffset\r
90 )\r
1e57a462 91{\r
e7108d0e 92 return (const char *)fdt + fdt_off_dt_strings (fdt) + stroffset;\r
1e57a462 93}\r
94\r
e7108d0e
MK
95static int\r
96_fdt_string_eq (\r
97 const void *fdt,\r
98 int stroffset,\r
99 const char *s,\r
100 int len\r
101 )\r
1e57a462 102{\r
e7108d0e 103 const char *p = fdt_string (fdt, stroffset);\r
1e57a462 104\r
e7108d0e 105 return (strlen (p) == len) && (memcmp (p, s, len) == 0);\r
1e57a462 106}\r
107\r
e7108d0e
MK
108uint32_t\r
109fdt_get_max_phandle (\r
110 const void *fdt\r
111 )\r
a0992390 112{\r
e7108d0e
MK
113 uint32_t max_phandle = 0;\r
114 int offset;\r
a0992390 115\r
e7108d0e
MK
116 for (offset = fdt_next_node (fdt, -1, NULL); ;\r
117 offset = fdt_next_node (fdt, offset, NULL))\r
118 {\r
119 uint32_t phandle;\r
a0992390 120\r
e7108d0e
MK
121 if (offset == -FDT_ERR_NOTFOUND) {\r
122 return max_phandle;\r
123 }\r
a0992390 124\r
e7108d0e
MK
125 if (offset < 0) {\r
126 return (uint32_t)-1;\r
127 }\r
a0992390 128\r
e7108d0e
MK
129 phandle = fdt_get_phandle (fdt, offset);\r
130 if (phandle == (uint32_t)-1) {\r
131 continue;\r
132 }\r
a0992390 133\r
e7108d0e
MK
134 if (phandle > max_phandle) {\r
135 max_phandle = phandle;\r
136 }\r
137 }\r
a0992390 138\r
e7108d0e 139 return 0;\r
a0992390
PB
140}\r
141\r
e7108d0e
MK
142int\r
143fdt_get_mem_rsv (\r
144 const void *fdt,\r
145 int n,\r
146 uint64_t *address,\r
147 uint64_t *size\r
148 )\r
1e57a462 149{\r
e7108d0e
MK
150 FDT_CHECK_HEADER (fdt);\r
151 *address = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->address);\r
152 *size = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->size);\r
153 return 0;\r
1e57a462 154}\r
155\r
e7108d0e
MK
156int\r
157fdt_num_mem_rsv (\r
158 const void *fdt\r
159 )\r
1e57a462 160{\r
e7108d0e 161 int i = 0;\r
1e57a462 162\r
e7108d0e
MK
163 while (fdt64_to_cpu (_fdt_mem_rsv (fdt, i)->size) != 0) {\r
164 i++;\r
165 }\r
1e57a462 166\r
e7108d0e 167 return i;\r
1e57a462 168}\r
169\r
e7108d0e
MK
170static int\r
171_nextprop (\r
172 const void *fdt,\r
173 int offset\r
174 )\r
1e57a462 175{\r
e7108d0e
MK
176 uint32_t tag;\r
177 int nextoffset;\r
1e57a462 178\r
e7108d0e
MK
179 do {\r
180 tag = fdt_next_tag (fdt, offset, &nextoffset);\r
1e57a462 181\r
e7108d0e
MK
182 switch (tag) {\r
183 case FDT_END:\r
184 if (nextoffset >= 0) {\r
185 return -FDT_ERR_BADSTRUCTURE;\r
186 } else {\r
187 return nextoffset;\r
188 }\r
1e57a462 189\r
e7108d0e
MK
190 case FDT_PROP:\r
191 return offset;\r
192 }\r
1e57a462 193\r
e7108d0e
MK
194 offset = nextoffset;\r
195 } while (tag == FDT_NOP);\r
1e57a462 196\r
e7108d0e 197 return -FDT_ERR_NOTFOUND;\r
1e57a462 198}\r
199\r
e7108d0e
MK
200int\r
201fdt_subnode_offset_namelen (\r
202 const void *fdt,\r
203 int offset,\r
204 const char *name,\r
205 int namelen\r
206 )\r
a0992390 207{\r
e7108d0e 208 int depth;\r
a0992390 209\r
e7108d0e 210 FDT_CHECK_HEADER (fdt);\r
1e57a462 211\r
e7108d0e
MK
212 for (depth = 0;\r
213 (offset >= 0) && (depth >= 0);\r
214 offset = fdt_next_node (fdt, offset, &depth))\r
215 {\r
216 if ( (depth == 1)\r
217 && _fdt_nodename_eq (fdt, offset, name, namelen))\r
218 {\r
219 return offset;\r
220 }\r
221 }\r
1e57a462 222\r
e7108d0e
MK
223 if (depth < 0) {\r
224 return -FDT_ERR_NOTFOUND;\r
225 }\r
1e57a462 226\r
e7108d0e 227 return offset; /* error */\r
1e57a462 228}\r
229\r
e7108d0e
MK
230int\r
231fdt_subnode_offset (\r
232 const void *fdt,\r
233 int parentoffset,\r
234 const char *name\r
235 )\r
1e57a462 236{\r
e7108d0e 237 return fdt_subnode_offset_namelen (fdt, parentoffset, name, strlen (name));\r
1e57a462 238}\r
239\r
e7108d0e
MK
240int\r
241fdt_path_offset_namelen (\r
242 const void *fdt,\r
243 const char *path,\r
244 int namelen\r
245 )\r
1e57a462 246{\r
e7108d0e
MK
247 const char *end = path + namelen;\r
248 const char *p = path;\r
249 int offset = 0;\r
1e57a462 250\r
e7108d0e 251 FDT_CHECK_HEADER (fdt);\r
1e57a462 252\r
e7108d0e
MK
253 /* see if we have an alias */\r
254 if (*path != '/') {\r
255 const char *q = memchr (path, '/', end - p);\r
1e57a462 256\r
e7108d0e
MK
257 if (!q) {\r
258 q = end;\r
259 }\r
1e57a462 260\r
e7108d0e
MK
261 p = fdt_get_alias_namelen (fdt, p, q - p);\r
262 if (!p) {\r
263 return -FDT_ERR_BADPATH;\r
264 }\r
1e57a462 265\r
e7108d0e 266 offset = fdt_path_offset (fdt, p);\r
1e57a462 267\r
e7108d0e
MK
268 p = q;\r
269 }\r
1e57a462 270\r
e7108d0e
MK
271 while (p < end) {\r
272 const char *q;\r
1e57a462 273\r
e7108d0e
MK
274 while (*p == '/') {\r
275 p++;\r
276 if (p == end) {\r
277 return offset;\r
278 }\r
279 }\r
1e57a462 280\r
e7108d0e
MK
281 q = memchr (p, '/', end - p);\r
282 if (!q) {\r
283 q = end;\r
284 }\r
1e57a462 285\r
e7108d0e
MK
286 offset = fdt_subnode_offset_namelen (fdt, offset, p, q-p);\r
287 if (offset < 0) {\r
288 return offset;\r
289 }\r
1e57a462 290\r
e7108d0e
MK
291 p = q;\r
292 }\r
1e57a462 293\r
e7108d0e 294 return offset;\r
1e57a462 295}\r
296\r
e7108d0e
MK
297int\r
298fdt_path_offset (\r
299 const void *fdt,\r
300 const char *path\r
301 )\r
1e57a462 302{\r
e7108d0e 303 return fdt_path_offset_namelen (fdt, path, strlen (path));\r
1e57a462 304}\r
305\r
e7108d0e
MK
306const char *\r
307fdt_get_name (\r
308 const void *fdt,\r
309 int nodeoffset,\r
310 int *len\r
311 )\r
1e57a462 312{\r
e7108d0e
MK
313 const struct fdt_node_header *nh = _fdt_offset_ptr (fdt, nodeoffset);\r
314 int err;\r
1e57a462 315\r
e7108d0e
MK
316 if ( ((err = fdt_check_header (fdt)) != 0)\r
317 || ((err = _fdt_check_node_offset (fdt, nodeoffset)) < 0))\r
318 {\r
319 goto fail;\r
320 }\r
1e57a462 321\r
e7108d0e
MK
322 if (len) {\r
323 *len = strlen (nh->name);\r
324 }\r
1e57a462 325\r
e7108d0e 326 return nh->name;\r
1e57a462 327\r
e7108d0e
MK
328fail:\r
329 if (len) {\r
330 *len = err;\r
331 }\r
1e57a462 332\r
e7108d0e 333 return NULL;\r
1e57a462 334}\r
335\r
e7108d0e
MK
336int\r
337fdt_first_property_offset (\r
338 const void *fdt,\r
339 int nodeoffset\r
340 )\r
1e57a462 341{\r
e7108d0e 342 int offset;\r
1e57a462 343\r
e7108d0e
MK
344 if ((offset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) {\r
345 return offset;\r
346 }\r
1e57a462 347\r
e7108d0e 348 return _nextprop (fdt, offset);\r
1e57a462 349}\r
350\r
e7108d0e
MK
351int\r
352fdt_next_property_offset (\r
353 const void *fdt,\r
354 int offset\r
355 )\r
1e57a462 356{\r
e7108d0e
MK
357 if ((offset = _fdt_check_prop_offset (fdt, offset)) < 0) {\r
358 return offset;\r
359 }\r
1e57a462 360\r
e7108d0e 361 return _nextprop (fdt, offset);\r
1e57a462 362}\r
363\r
e7108d0e
MK
364const struct fdt_property *\r
365fdt_get_property_by_offset (\r
366 const void *fdt,\r
367 int offset,\r
368 int *lenp\r
369 )\r
1e57a462 370{\r
e7108d0e
MK
371 int err;\r
372 const struct fdt_property *prop;\r
1e57a462 373\r
e7108d0e
MK
374 if ((err = _fdt_check_prop_offset (fdt, offset)) < 0) {\r
375 if (lenp) {\r
376 *lenp = err;\r
377 }\r
1e57a462 378\r
e7108d0e
MK
379 return NULL;\r
380 }\r
1e57a462 381\r
e7108d0e 382 prop = _fdt_offset_ptr (fdt, offset);\r
1e57a462 383\r
e7108d0e
MK
384 if (lenp) {\r
385 *lenp = fdt32_to_cpu (prop->len);\r
386 }\r
1e57a462 387\r
e7108d0e 388 return prop;\r
1e57a462 389}\r
390\r
e7108d0e
MK
391const struct fdt_property *\r
392fdt_get_property_namelen (\r
393 const void *fdt,\r
394 int offset,\r
395 const char *name,\r
396 int namelen,\r
397 int *lenp\r
398 )\r
1e57a462 399{\r
e7108d0e
MK
400 for (offset = fdt_first_property_offset (fdt, offset);\r
401 (offset >= 0);\r
402 (offset = fdt_next_property_offset (fdt, offset)))\r
403 {\r
404 const struct fdt_property *prop;\r
1e57a462 405\r
e7108d0e
MK
406 if (!(prop = fdt_get_property_by_offset (fdt, offset, lenp))) {\r
407 offset = -FDT_ERR_INTERNAL;\r
408 break;\r
409 }\r
1e57a462 410\r
e7108d0e
MK
411 if (_fdt_string_eq (\r
412 fdt,\r
413 fdt32_to_cpu (prop->nameoff),\r
414 name,\r
415 namelen\r
416 ))\r
417 {\r
418 return prop;\r
419 }\r
420 }\r
1e57a462 421\r
e7108d0e
MK
422 if (lenp) {\r
423 *lenp = offset;\r
424 }\r
1e57a462 425\r
e7108d0e 426 return NULL;\r
1e57a462 427}\r
428\r
e7108d0e
MK
429const struct fdt_property *\r
430fdt_get_property (\r
431 const void *fdt,\r
432 int nodeoffset,\r
433 const char *name,\r
434 int *lenp\r
435 )\r
1e57a462 436{\r
e7108d0e
MK
437 return fdt_get_property_namelen (\r
438 fdt,\r
439 nodeoffset,\r
440 name,\r
441 strlen (name),\r
442 lenp\r
443 );\r
1e57a462 444}\r
445\r
e7108d0e
MK
446const void *\r
447fdt_getprop_namelen (\r
448 const void *fdt,\r
449 int nodeoffset,\r
450 const char *name,\r
451 int namelen,\r
452 int *lenp\r
453 )\r
a0992390 454{\r
e7108d0e 455 const struct fdt_property *prop;\r
a0992390 456\r
e7108d0e
MK
457 prop = fdt_get_property_namelen (fdt, nodeoffset, name, namelen, lenp);\r
458 if (!prop) {\r
459 return NULL;\r
460 }\r
a0992390 461\r
e7108d0e
MK
462 return prop->data;\r
463}\r
464\r
465const void *\r
466fdt_getprop_by_offset (\r
467 const void *fdt,\r
468 int offset,\r
469 const char **namep,\r
470 int *lenp\r
471 )\r
472{\r
473 const struct fdt_property *prop;\r
474\r
475 prop = fdt_get_property_by_offset (fdt, offset, lenp);\r
476 if (!prop) {\r
477 return NULL;\r
478 }\r
479\r
480 if (namep) {\r
481 *namep = fdt_string (fdt, fdt32_to_cpu (prop->nameoff));\r
482 }\r
483\r
484 return prop->data;\r
485}\r
486\r
487const void *\r
488fdt_getprop (\r
489 const void *fdt,\r
490 int nodeoffset,\r
491 const char *name,\r
492 int *lenp\r
493 )\r
494{\r
495 return fdt_getprop_namelen (fdt, nodeoffset, name, strlen (name), lenp);\r
496}\r
497\r
498uint32_t\r
499fdt_get_phandle (\r
500 const void *fdt,\r
501 int nodeoffset\r
502 )\r
503{\r
504 const fdt32_t *php;\r
505 int len;\r
506\r
507 /* FIXME: This is a bit sub-optimal, since we potentially scan\r
508 * over all the properties twice. */\r
509 php = fdt_getprop (fdt, nodeoffset, "phandle", &len);\r
510 if (!php || (len != sizeof (*php))) {\r
511 php = fdt_getprop (fdt, nodeoffset, "linux,phandle", &len);\r
512 if (!php || (len != sizeof (*php))) {\r
513 return 0;\r
514 }\r
515 }\r
516\r
517 return fdt32_to_cpu (*php);\r
518}\r
519\r
520const char *\r
521fdt_get_alias_namelen (\r
522 const void *fdt,\r
523 const char *name,\r
524 int namelen\r
525 )\r
526{\r
527 int aliasoffset;\r
528\r
529 aliasoffset = fdt_path_offset (fdt, "/aliases");\r
530 if (aliasoffset < 0) {\r
531 return NULL;\r
532 }\r
533\r
534 return fdt_getprop_namelen (fdt, aliasoffset, name, namelen, NULL);\r
535}\r
536\r
537const char *\r
538fdt_get_alias (\r
539 const void *fdt,\r
540 const char *name\r
541 )\r
542{\r
543 return fdt_get_alias_namelen (fdt, name, strlen (name));\r
544}\r
545\r
546int\r
547fdt_get_path (\r
548 const void *fdt,\r
549 int nodeoffset,\r
550 char *buf,\r
551 int buflen\r
552 )\r
553{\r
554 int pdepth = 0, p = 0;\r
555 int offset, depth, namelen;\r
556 const char *name;\r
557\r
558 FDT_CHECK_HEADER (fdt);\r
559\r
560 if (buflen < 2) {\r
561 return -FDT_ERR_NOSPACE;\r
562 }\r
563\r
564 for (offset = 0, depth = 0;\r
565 (offset >= 0) && (offset <= nodeoffset);\r
566 offset = fdt_next_node (fdt, offset, &depth))\r
567 {\r
568 while (pdepth > depth) {\r
569 do {\r
570 p--;\r
571 } while (buf[p-1] != '/');\r
572\r
573 pdepth--;\r
574 }\r
575\r
576 if (pdepth >= depth) {\r
577 name = fdt_get_name (fdt, offset, &namelen);\r
578 if (!name) {\r
579 return namelen;\r
580 }\r
581\r
582 if ((p + namelen + 1) <= buflen) {\r
583 memcpy (buf + p, name, namelen);\r
584 p += namelen;\r
585 buf[p++] = '/';\r
586 pdepth++;\r
587 }\r
588 }\r
589\r
590 if (offset == nodeoffset) {\r
591 if (pdepth < (depth + 1)) {\r
592 return -FDT_ERR_NOSPACE;\r
593 }\r
594\r
595 if (p > 1) {\r
596 /* special case so that root path is "/", not "" */\r
597 p--;\r
598 }\r
599\r
600 buf[p] = '\0';\r
601 return 0;\r
602 }\r
603 }\r
604\r
605 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) {\r
606 return -FDT_ERR_BADOFFSET;\r
607 } else if (offset == -FDT_ERR_BADOFFSET) {\r
608 return -FDT_ERR_BADSTRUCTURE;\r
609 }\r
610\r
611 return offset; /* error from fdt_next_node() */\r
612}\r
613\r
614int\r
615fdt_supernode_atdepth_offset (\r
616 const void *fdt,\r
617 int nodeoffset,\r
618 int supernodedepth,\r
619 int *nodedepth\r
620 )\r
621{\r
622 int offset, depth;\r
623 int supernodeoffset = -FDT_ERR_INTERNAL;\r
624\r
625 FDT_CHECK_HEADER (fdt);\r
626\r
627 if (supernodedepth < 0) {\r
628 return -FDT_ERR_NOTFOUND;\r
629 }\r
630\r
631 for (offset = 0, depth = 0;\r
632 (offset >= 0) && (offset <= nodeoffset);\r
633 offset = fdt_next_node (fdt, offset, &depth))\r
634 {\r
635 if (depth == supernodedepth) {\r
636 supernodeoffset = offset;\r
637 }\r
638\r
639 if (offset == nodeoffset) {\r
640 if (nodedepth) {\r
641 *nodedepth = depth;\r
642 }\r
643\r
644 if (supernodedepth > depth) {\r
645 return -FDT_ERR_NOTFOUND;\r
646 } else {\r
647 return supernodeoffset;\r
648 }\r
649 }\r
650 }\r
651\r
652 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) {\r
653 return -FDT_ERR_BADOFFSET;\r
654 } else if (offset == -FDT_ERR_BADOFFSET) {\r
655 return -FDT_ERR_BADSTRUCTURE;\r
656 }\r
657\r
658 return offset; /* error from fdt_next_node() */\r
659}\r
660\r
661int\r
662fdt_node_depth (\r
663 const void *fdt,\r
664 int nodeoffset\r
665 )\r
666{\r
667 int nodedepth;\r
668 int err;\r
669\r
670 err = fdt_supernode_atdepth_offset (fdt, nodeoffset, 0, &nodedepth);\r
671 if (err) {\r
672 return (err < 0) ? err : -FDT_ERR_INTERNAL;\r
673 }\r
674\r
675 return nodedepth;\r
676}\r
677\r
678int\r
679fdt_parent_offset (\r
680 const void *fdt,\r
681 int nodeoffset\r
682 )\r
683{\r
684 int nodedepth = fdt_node_depth (fdt, nodeoffset);\r
685\r
686 if (nodedepth < 0) {\r
687 return nodedepth;\r
688 }\r
689\r
690 return fdt_supernode_atdepth_offset (\r
691 fdt,\r
692 nodeoffset,\r
693 nodedepth - 1,\r
694 NULL\r
695 );\r
696}\r
697\r
698int\r
699fdt_node_offset_by_prop_value (\r
700 const void *fdt,\r
701 int startoffset,\r
702 const char *propname,\r
703 const void *propval,\r
704 int proplen\r
705 )\r
706{\r
707 int offset;\r
708 const void *val;\r
709 int len;\r
710\r
711 FDT_CHECK_HEADER (fdt);\r
712\r
713 /* FIXME: The algorithm here is pretty horrible: we scan each\r
714 * property of a node in fdt_getprop(), then if that didn't\r
715 * find what we want, we scan over them again making our way\r
716 * to the next node. Still it's the easiest to implement\r
717 * approach; performance can come later. */\r
718 for (offset = fdt_next_node (fdt, startoffset, NULL);\r
719 offset >= 0;\r
720 offset = fdt_next_node (fdt, offset, NULL))\r
721 {\r
722 val = fdt_getprop (fdt, offset, propname, &len);\r
723 if ( val && (len == proplen)\r
724 && (memcmp (val, propval, len) == 0))\r
725 {\r
726 return offset;\r
727 }\r
728 }\r
729\r
730 return offset; /* error from fdt_next_node() */\r
731}\r
732\r
733int\r
734fdt_node_offset_by_phandle (\r
735 const void *fdt,\r
736 uint32_t phandle\r
737 )\r
738{\r
739 int offset;\r
740\r
741 if ((phandle == 0) || (phandle == -1)) {\r
742 return -FDT_ERR_BADPHANDLE;\r
743 }\r
744\r
745 FDT_CHECK_HEADER (fdt);\r
746\r
747 /* FIXME: The algorithm here is pretty horrible: we\r
748 * potentially scan each property of a node in\r
749 * fdt_get_phandle(), then if that didn't find what\r
750 * we want, we scan over them again making our way to the next\r
751 * node. Still it's the easiest to implement approach;\r
752 * performance can come later. */\r
753 for (offset = fdt_next_node (fdt, -1, NULL);\r
754 offset >= 0;\r
755 offset = fdt_next_node (fdt, offset, NULL))\r
756 {\r
757 if (fdt_get_phandle (fdt, offset) == phandle) {\r
758 return offset;\r
759 }\r
760 }\r
761\r
762 return offset; /* error from fdt_next_node() */\r
763}\r
764\r
765int\r
766fdt_stringlist_contains (\r
767 const char *strlist,\r
768 int listlen,\r
769 const char *str\r
770 )\r
771{\r
772 int len = strlen (str);\r
773 const char *p;\r
774\r
775 while (listlen >= len) {\r
776 if (memcmp (str, strlist, len+1) == 0) {\r
777 return 1;\r
778 }\r
779\r
780 p = memchr (strlist, '\0', listlen);\r
781 if (!p) {\r
782 return 0; /* malformed strlist.. */\r
783 }\r
784\r
785 listlen -= (p-strlist) + 1;\r
786 strlist = p + 1;\r
787 }\r
788\r
789 return 0;\r
790}\r
791\r
792int\r
793fdt_stringlist_count (\r
794 const void *fdt,\r
795 int nodeoffset,\r
796 const char *property\r
797 )\r
798{\r
799 const char *list, *end;\r
800 int length, count = 0;\r
801\r
802 list = fdt_getprop (fdt, nodeoffset, property, &length);\r
803 if (!list) {\r
804 return length;\r
805 }\r
806\r
807 end = list + length;\r
808\r
809 while (list < end) {\r
810 length = strnlen (list, end - list) + 1;\r
811\r
812 /* Abort if the last string isn't properly NUL-terminated. */\r
813 if (list + length > end) {\r
814 return -FDT_ERR_BADVALUE;\r
815 }\r
a0992390 816\r
e7108d0e
MK
817 list += length;\r
818 count++;\r
819 }\r
a0992390 820\r
e7108d0e 821 return count;\r
a0992390
PB
822}\r
823\r
e7108d0e
MK
824int\r
825fdt_stringlist_search (\r
826 const void *fdt,\r
827 int nodeoffset,\r
828 const char *property,\r
829 const char *string\r
830 )\r
a0992390 831{\r
e7108d0e
MK
832 int length, len, idx = 0;\r
833 const char *list, *end;\r
a0992390 834\r
e7108d0e
MK
835 list = fdt_getprop (fdt, nodeoffset, property, &length);\r
836 if (!list) {\r
837 return length;\r
838 }\r
a0992390 839\r
e7108d0e
MK
840 len = strlen (string) + 1;\r
841 end = list + length;\r
a0992390 842\r
e7108d0e
MK
843 while (list < end) {\r
844 length = strnlen (list, end - list) + 1;\r
a0992390 845\r
e7108d0e
MK
846 /* Abort if the last string isn't properly NUL-terminated. */\r
847 if (list + length > end) {\r
848 return -FDT_ERR_BADVALUE;\r
849 }\r
a0992390 850\r
e7108d0e
MK
851 if ((length == len) && (memcmp (list, string, length) == 0)) {\r
852 return idx;\r
853 }\r
a0992390 854\r
e7108d0e
MK
855 list += length;\r
856 idx++;\r
857 }\r
a0992390 858\r
e7108d0e 859 return -FDT_ERR_NOTFOUND;\r
a0992390
PB
860}\r
861\r
e7108d0e
MK
862const char *\r
863fdt_stringlist_get (\r
864 const void *fdt,\r
865 int nodeoffset,\r
866 const char *property,\r
867 int idx,\r
868 int *lenp\r
869 )\r
a0992390 870{\r
e7108d0e
MK
871 const char *list, *end;\r
872 int length;\r
a0992390 873\r
e7108d0e
MK
874 list = fdt_getprop (fdt, nodeoffset, property, &length);\r
875 if (!list) {\r
876 if (lenp) {\r
877 *lenp = length;\r
878 }\r
a0992390 879\r
e7108d0e
MK
880 return NULL;\r
881 }\r
a0992390 882\r
e7108d0e 883 end = list + length;\r
a0992390 884\r
e7108d0e
MK
885 while (list < end) {\r
886 length = strnlen (list, end - list) + 1;\r
a0992390 887\r
e7108d0e
MK
888 /* Abort if the last string isn't properly NUL-terminated. */\r
889 if (list + length > end) {\r
890 if (lenp) {\r
891 *lenp = -FDT_ERR_BADVALUE;\r
892 }\r
a0992390 893\r
e7108d0e
MK
894 return NULL;\r
895 }\r
a0992390 896\r
e7108d0e
MK
897 if (idx == 0) {\r
898 if (lenp) {\r
899 *lenp = length - 1;\r
900 }\r
a0992390 901\r
e7108d0e
MK
902 return list;\r
903 }\r
a0992390 904\r
e7108d0e
MK
905 list += length;\r
906 idx--;\r
907 }\r
a0992390 908\r
e7108d0e
MK
909 if (lenp) {\r
910 *lenp = -FDT_ERR_NOTFOUND;\r
911 }\r
a0992390 912\r
e7108d0e 913 return NULL;\r
a0992390
PB
914}\r
915\r
e7108d0e
MK
916int\r
917fdt_node_check_compatible (\r
918 const void *fdt,\r
919 int nodeoffset,\r
920 const char *compatible\r
921 )\r
1e57a462 922{\r
e7108d0e
MK
923 const void *prop;\r
924 int len;\r
925\r
926 prop = fdt_getprop (fdt, nodeoffset, "compatible", &len);\r
927 if (!prop) {\r
928 return len;\r
929 }\r
1e57a462 930\r
e7108d0e 931 return !fdt_stringlist_contains (prop, len, compatible);\r
1e57a462 932}\r
933\r
e7108d0e
MK
934int\r
935fdt_node_offset_by_compatible (\r
936 const void *fdt,\r
937 int startoffset,\r
938 const char *compatible\r
939 )\r
1e57a462 940{\r
e7108d0e 941 int offset, err;\r
1e57a462 942\r
e7108d0e 943 FDT_CHECK_HEADER (fdt);\r
1e57a462 944\r
e7108d0e
MK
945 /* FIXME: The algorithm here is pretty horrible: we scan each\r
946 * property of a node in fdt_node_check_compatible(), then if\r
947 * that didn't find what we want, we scan over them again\r
948 * making our way to the next node. Still it's the easiest to\r
949 * implement approach; performance can come later. */\r
950 for (offset = fdt_next_node (fdt, startoffset, NULL);\r
951 offset >= 0;\r
952 offset = fdt_next_node (fdt, offset, NULL))\r
953 {\r
954 err = fdt_node_check_compatible (fdt, offset, compatible);\r
955 if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) {\r
956 return err;\r
957 } else if (err == 0) {\r
958 return offset;\r
959 }\r
960 }\r
961\r
962 return offset; /* error from fdt_next_node() */\r
1e57a462 963}\r