blob: 7db7f12280b58b83fff5fa66831854e1c4c90e3d [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 Gibson73d60922006-12-15 15:12:47 +1100140struct fdt_property *fdt_get_property(const void *fdt,
David Gibson94993f42006-12-11 16:15:34 +1100141 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 Gibson3da0f9a2006-11-27 16:21:28 +1100146 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 Gibson9a9fdf52006-12-15 15:12:51 +1100164 err = -FDT_ERR_INTERNAL;
David Gibson94993f42006-12-11 16:15:34 +1100165 if (offset % FDT_TAGSIZE)
David Gibsona7ee95d2006-12-15 15:12:49 +1100166 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100167
168 tag = _fdt_next_tag(fdt, offset, &nextoffset);
169 switch (tag) {
170 case FDT_END:
David Gibson9a9fdf52006-12-15 15:12:51 +1100171 err = -FDT_ERR_TRUNCATED;
David Gibsona7ee95d2006-12-15 15:12:49 +1100172 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100173
174 case FDT_BEGIN_NODE:
175 level++;
176 break;
177
178 case FDT_END_NODE:
179 level--;
180 break;
181
182 case FDT_PROP:
183 if (level != 0)
184 continue;
185
David Gibson9a9fdf52006-12-15 15:12:51 +1100186 err = -FDT_ERR_BADSTRUCTURE;
David Gibson94993f42006-12-11 16:15:34 +1100187 prop = fdt_offset_ptr_typed(fdt, offset, prop);
188 if (! prop)
David Gibsona7ee95d2006-12-15 15:12:49 +1100189 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100190 namestroff = fdt32_to_cpu(prop->nameoff);
191 if (streq(fdt_string(fdt, namestroff), name)) {
192 /* Found it! */
193 int len = fdt32_to_cpu(prop->len);
194 prop = fdt_offset_ptr(fdt, offset,
David Gibson9825f822006-12-14 15:29:25 +1100195 sizeof(*prop)+len);
David Gibson94993f42006-12-11 16:15:34 +1100196 if (! prop)
David Gibsona7ee95d2006-12-15 15:12:49 +1100197 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100198
199 if (lenp)
200 *lenp = len;
201
202 return prop;
203 }
204 break;
205
206 case FDT_NOP:
207 break;
208
209 default:
David Gibson9a9fdf52006-12-15 15:12:51 +1100210 err = -FDT_ERR_BADSTRUCTURE;
David Gibsona7ee95d2006-12-15 15:12:49 +1100211 goto fail;
David Gibson94993f42006-12-11 16:15:34 +1100212 }
213 } while (level >= 0);
214
David Gibson9a9fdf52006-12-15 15:12:51 +1100215 err = -FDT_ERR_NOTFOUND;
David Gibsona7ee95d2006-12-15 15:12:49 +1100216 fail:
217 if (lenp)
David Gibson9a9fdf52006-12-15 15:12:51 +1100218 *lenp = err;
David Gibsona7ee95d2006-12-15 15:12:49 +1100219 return NULL;
David Gibson3da0f9a2006-11-27 16:21:28 +1100220}
221
David Gibson73d60922006-12-15 15:12:47 +1100222void *fdt_getprop(const void *fdt, int nodeoffset,
David Gibson3da0f9a2006-11-27 16:21:28 +1100223 const char *name, int *lenp)
224{
225 const struct fdt_property *prop;
David Gibson3da0f9a2006-11-27 16:21:28 +1100226
David Gibson94993f42006-12-11 16:15:34 +1100227 prop = fdt_get_property(fdt, nodeoffset, name, lenp);
David Gibsona7ee95d2006-12-15 15:12:49 +1100228 if (! prop)
229 return NULL;
David Gibson3da0f9a2006-11-27 16:21:28 +1100230
231 return prop->data;
232}