fdt_ro.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * libfdt - Flat Device Tree manipulation
  3. * Copyright (C) 2006 David Gibson, IBM Corporation.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public License
  7. * as published by the Free Software Foundation; either version 2.1 of
  8. * the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "libfdt_env.h"
  20. #include <fdt.h>
  21. #include <libfdt.h>
  22. #include "libfdt_internal.h"
  23. #define CHECK_HEADER(fdt) \
  24. { \
  25. int err; \
  26. if ((err = _fdt_check_header(fdt)) != 0) \
  27. return err; \
  28. }
  29. static int offset_streq(const void *fdt, int offset,
  30. const char *s, int len)
  31. {
  32. const char *p = fdt_offset_ptr(fdt, offset, len+1);
  33. if (! p)
  34. /* short match */
  35. return 0;
  36. if (memcmp(p, s, len) != 0)
  37. return 0;
  38. if (p[len] != '\0')
  39. return 0;
  40. return 1;
  41. }
  42. char *fdt_string(const void *fdt, int stroffset)
  43. {
  44. return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
  45. }
  46. int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
  47. const char *name, int namelen)
  48. {
  49. int level = 0;
  50. uint32_t tag;
  51. int offset, nextoffset;
  52. CHECK_HEADER(fdt);
  53. tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
  54. if (tag != FDT_BEGIN_NODE)
  55. return -FDT_ERR_BADOFFSET;
  56. do {
  57. offset = nextoffset;
  58. tag = _fdt_next_tag(fdt, offset, &nextoffset);
  59. switch (tag) {
  60. case FDT_END:
  61. return -FDT_ERR_TRUNCATED;
  62. case FDT_BEGIN_NODE:
  63. level++;
  64. if (level != 1)
  65. continue;
  66. if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
  67. /* Found it! */
  68. return offset;
  69. break;
  70. case FDT_END_NODE:
  71. level--;
  72. break;
  73. case FDT_PROP:
  74. case FDT_NOP:
  75. break;
  76. default:
  77. return -FDT_ERR_BADSTRUCTURE;
  78. }
  79. } while (level >= 0);
  80. return -FDT_ERR_NOTFOUND;
  81. }
  82. int fdt_subnode_offset(const void *fdt, int parentoffset,
  83. const char *name)
  84. {
  85. return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
  86. }
  87. int fdt_path_offset(const void *fdt, const char *path)
  88. {
  89. const char *end = path + strlen(path);
  90. const char *p = path;
  91. int offset = 0;
  92. CHECK_HEADER(fdt);
  93. if (*path != '/')
  94. return -FDT_ERR_BADPATH;
  95. while (*p) {
  96. const char *q;
  97. while (*p == '/')
  98. p++;
  99. if (! *p)
  100. return -FDT_ERR_BADPATH;
  101. q = strchr(p, '/');
  102. if (! q)
  103. q = end;
  104. offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
  105. if (offset < 0)
  106. return offset;
  107. p = q;
  108. }
  109. return offset;
  110. }
  111. struct fdt_property *fdt_get_property(const void *fdt,
  112. int nodeoffset,
  113. const char *name, int *lenp)
  114. {
  115. int level = 0;
  116. uint32_t tag;
  117. struct fdt_property *prop;
  118. int namestroff;
  119. int offset, nextoffset;
  120. int err;
  121. if ((err = _fdt_check_header(fdt)) != 0)
  122. goto fail;
  123. err = -FDT_ERR_BADOFFSET;
  124. if (nodeoffset % FDT_TAGSIZE)
  125. goto fail;
  126. tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
  127. if (tag != FDT_BEGIN_NODE)
  128. goto fail;
  129. do {
  130. offset = nextoffset;
  131. tag = _fdt_next_tag(fdt, offset, &nextoffset);
  132. switch (tag) {
  133. case FDT_END:
  134. err = -FDT_ERR_TRUNCATED;
  135. goto fail;
  136. case FDT_BEGIN_NODE:
  137. level++;
  138. break;
  139. case FDT_END_NODE:
  140. level--;
  141. break;
  142. case FDT_PROP:
  143. if (level != 0)
  144. continue;
  145. err = -FDT_ERR_BADSTRUCTURE;
  146. prop = fdt_offset_ptr_typed(fdt, offset, prop);
  147. if (! prop)
  148. goto fail;
  149. namestroff = fdt32_to_cpu(prop->nameoff);
  150. if (streq(fdt_string(fdt, namestroff), name)) {
  151. /* Found it! */
  152. int len = fdt32_to_cpu(prop->len);
  153. prop = fdt_offset_ptr(fdt, offset,
  154. sizeof(*prop)+len);
  155. if (! prop)
  156. goto fail;
  157. if (lenp)
  158. *lenp = len;
  159. return prop;
  160. }
  161. break;
  162. case FDT_NOP:
  163. break;
  164. default:
  165. err = -FDT_ERR_BADSTRUCTURE;
  166. goto fail;
  167. }
  168. } while (level >= 0);
  169. err = -FDT_ERR_NOTFOUND;
  170. fail:
  171. if (lenp)
  172. *lenp = err;
  173. return NULL;
  174. }
  175. void *fdt_getprop(const void *fdt, int nodeoffset,
  176. const char *name, int *lenp)
  177. {
  178. const struct fdt_property *prop;
  179. prop = fdt_get_property(fdt, nodeoffset, name, lenp);
  180. if (! prop)
  181. return NULL;
  182. return prop->data;
  183. }