blob: 28a6d16a471305333815e8fd29b0ce3a6c052256 [file] [log] [blame]
David Gibson3da0f9a2006-11-27 16:21:28 +11001/*
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
21#include <fdt.h>
22#include <libfdt.h>
23
24#include "libfdt_internal.h"
25
David Gibson9a9fdf52006-12-15 15:12:51 +110026#define CHECK_HEADER(fdt) \
David Gibson3da0f9a2006-11-27 16:21:28 +110027 { \
28 int err; \
David Gibson42369762006-12-01 15:07:19 +110029 if ((err = _fdt_check_header(fdt)) != 0) \
David Gibson9a9fdf52006-12-15 15:12:51 +110030 return err; \
David Gibson3da0f9a2006-11-27 16:21:28 +110031 }
32
David Gibson73d60922006-12-15 15:12:47 +110033static int offset_streq(const void *fdt, int offset,
David Gibson3da0f9a2006-11-27 16:21:28 +110034 const char *s, int len)
35{
36 const char *p = fdt_offset_ptr(fdt, offset, len+1);
37
38 if (! p)
39 /* short match */
40 return 0;
41
42 if (memcmp(p, s, len) != 0)
43 return 0;
44
45 if (p[len] != '\0')
46 return 0;
47
48 return 1;
49}
50
David Gibson73d60922006-12-15 15:12:47 +110051char *fdt_string(const void *fdt, int stroffset)
David Gibson3aa4cfd2006-11-29 16:34:30 +110052{
David Gibsonede25de2006-12-01 15:02:10 +110053 return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
David Gibson3aa4cfd2006-11-29 16:34:30 +110054}
55
David Gibson73d60922006-12-15 15:12:47 +110056int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
David Gibson3da0f9a2006-11-27 16:21:28 +110057 const char *name, int namelen)
58{
59 int level = 0;
60 uint32_t tag;
61 int offset, nextoffset;
62
David Gibson9a9fdf52006-12-15 15:12:51 +110063 CHECK_HEADER(fdt);
David Gibson3da0f9a2006-11-27 16:21:28 +110064
65 tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
66 if (tag != FDT_BEGIN_NODE)
David Gibson9a9fdf52006-12-15 15:12:51 +110067 return -FDT_ERR_BADOFFSET;
David Gibson3da0f9a2006-11-27 16:21:28 +110068
69 do {
70 offset = nextoffset;
71 tag = _fdt_next_tag(fdt, offset, &nextoffset);
72
73 switch (tag) {
74 case FDT_END:
David Gibson9a9fdf52006-12-15 15:12:51 +110075 return -FDT_ERR_TRUNCATED;
David Gibson3da0f9a2006-11-27 16:21:28 +110076
77 case FDT_BEGIN_NODE:
78 level++;
79 if (level != 1)
80 continue;
81 if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
82 /* Found it! */
83 return offset;
84 break;
85
86 case FDT_END_NODE:
87 level--;
88 break;
89
90 case FDT_PROP:
91 case FDT_NOP:
92 break;
93
94 default:
David Gibson9a9fdf52006-12-15 15:12:51 +110095 return -FDT_ERR_BADSTRUCTURE;
David Gibson3da0f9a2006-11-27 16:21:28 +110096 }
97 } while (level >= 0);
98
David Gibson9a9fdf52006-12-15 15:12:51 +110099 return -FDT_ERR_NOTFOUND;
David Gibson3da0f9a2006-11-27 16:21:28 +1100100}
101
David Gibson73d60922006-12-15 15:12:47 +1100102int fdt_subnode_offset(const void *fdt, int parentoffset,
David Gibson3da0f9a2006-11-27 16:21:28 +1100103 const char *name)
104{
105 return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
106}
107
David Gibson73d60922006-12-15 15:12:47 +1100108int fdt_path_offset(const void *fdt, const char *path)
David Gibson3da0f9a2006-11-27 16:21:28 +1100109{
110 const char *end = path + strlen(path);
111 const char *p = path;
112 int offset = 0;
113
David Gibson9a9fdf52006-12-15 15:12:51 +1100114 CHECK_HEADER(fdt);
David Gibson3da0f9a2006-11-27 16:21:28 +1100115
116 if (*path != '/')
David Gibson9a9fdf52006-12-15 15:12:51 +1100117 return -FDT_ERR_BADPATH;
David Gibson3da0f9a2006-11-27 16:21:28 +1100118
119 while (*p) {
120 const char *q;
121
122 while (*p == '/')
123 p++;
124 if (! *p)
David Gibson9a9fdf52006-12-15 15:12:51 +1100125 return -FDT_ERR_BADPATH;
David Gibson3da0f9a2006-11-27 16:21:28 +1100126 q = strchr(p, '/');
127 if (! q)
128 q = end;
129
130 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
David Gibson9a9fdf52006-12-15 15:12:51 +1100131 if (offset < 0)
David Gibson3da0f9a2006-11-27 16:21:28 +1100132 return offset;
133
134 p = q;
135 }
136
137 return offset;
138}
139
David Gibsona6c76f92007-06-13 14:18:10 +1000140const struct fdt_property *fdt_get_property(const void *fdt,
141 int nodeoffset,
142 const char *name, int *lenp)
David Gibson3da0f9a2006-11-27 16:21:28 +1100143{
David Gibson94993f42006-12-11 16:15:34 +1100144 int level = 0;
145 uint32_t tag;
David Gibsona6c76f92007-06-13 14:18:10 +1000146 const struct fdt_property *prop;
David Gibson94993f42006-12-11 16:15:34 +1100147 int namestroff;
148 int offset, nextoffset;
David Gibsona7ee95d2006-12-15 15:12:49 +1100149 int err;
David Gibson3da0f9a2006-11-27 16:21:28 +1100150
David Gibsona7ee95d2006-12-15 15:12:49 +1100151 if ((err = _fdt_check_header(fdt)) != 0)
152 goto fail;
David Gibson3da0f9a2006-11-27 16:21:28 +1100153
David Gibson9a9fdf52006-12-15 15:12:51 +1100154 err = -FDT_ERR_BADOFFSET;
David Gibson94993f42006-12-11 16:15:34 +1100155 if (nodeoffset % FDT_TAGSIZE)
David Gibsona7ee95d2006-12-15 15:12:49 +1100156 goto fail;
David Gibson3da0f9a2006-11-27 16:21:28 +1100157
David Gibson94993f42006-12-11 16:15:34 +1100158 tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
159 if (tag != FDT_BEGIN_NODE)
David Gibsona7ee95d2006-12-15 15:12:49 +1100160 goto fail;
David Gibson3da0f9a2006-11-27 16:21:28 +1100161
David Gibson94993f42006-12-11 16:15:34 +1100162 do {
163 offset = nextoffset;
David Gibson94993f42006-12-11 16:15:34 +1100164
165 tag = _fdt_next_tag(fdt, offset, &nextoffset);
166 switch (tag) {
167 case FDT_END:
David Gibson9a9fdf52006-12-15 15:12:51 +1100168 err = -FDT_ERR_TRUNCATED;
David Gibsona7ee95d2006-12-15 15:12:49 +1100169 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100170
171 case FDT_BEGIN_NODE:
172 level++;
173 break;
174
175 case FDT_END_NODE:
176 level--;
177 break;
178
179 case FDT_PROP:
180 if (level != 0)
181 continue;
182
David Gibson9a9fdf52006-12-15 15:12:51 +1100183 err = -FDT_ERR_BADSTRUCTURE;
David Gibson94993f42006-12-11 16:15:34 +1100184 prop = fdt_offset_ptr_typed(fdt, offset, prop);
185 if (! prop)
David Gibsona7ee95d2006-12-15 15:12:49 +1100186 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100187 namestroff = fdt32_to_cpu(prop->nameoff);
188 if (streq(fdt_string(fdt, namestroff), name)) {
189 /* Found it! */
190 int len = fdt32_to_cpu(prop->len);
191 prop = fdt_offset_ptr(fdt, offset,
David Gibson9825f822006-12-14 15:29:25 +1100192 sizeof(*prop)+len);
David Gibson94993f42006-12-11 16:15:34 +1100193 if (! prop)
David Gibsona7ee95d2006-12-15 15:12:49 +1100194 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100195
196 if (lenp)
197 *lenp = len;
198
199 return prop;
200 }
201 break;
202
203 case FDT_NOP:
204 break;
205
206 default:
David Gibson9a9fdf52006-12-15 15:12:51 +1100207 err = -FDT_ERR_BADSTRUCTURE;
David Gibsona7ee95d2006-12-15 15:12:49 +1100208 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100209 }
210 } while (level >= 0);
211
David Gibson9a9fdf52006-12-15 15:12:51 +1100212 err = -FDT_ERR_NOTFOUND;
David Gibsona7ee95d2006-12-15 15:12:49 +1100213 fail:
214 if (lenp)
David Gibson9a9fdf52006-12-15 15:12:51 +1100215 *lenp = err;
David Gibsona7ee95d2006-12-15 15:12:49 +1100216 return NULL;
David Gibson3da0f9a2006-11-27 16:21:28 +1100217}
218
David Gibsona6c76f92007-06-13 14:18:10 +1000219const void *fdt_getprop(const void *fdt, int nodeoffset,
David Gibson3da0f9a2006-11-27 16:21:28 +1100220 const char *name, int *lenp)
221{
222 const struct fdt_property *prop;
David Gibson3da0f9a2006-11-27 16:21:28 +1100223
David Gibson94993f42006-12-11 16:15:34 +1100224 prop = fdt_get_property(fdt, nodeoffset, name, lenp);
David Gibsona7ee95d2006-12-15 15:12:49 +1100225 if (! prop)
226 return NULL;
David Gibson3da0f9a2006-11-27 16:21:28 +1100227
228 return prop->data;
229}