]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - libfdt/fdt_ro.c
9112c6a63935e78b5418af233d16b5b8e9d280fe
[karo-tx-uboot.git] / libfdt / fdt_ro.c
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
21 #include <fdt.h>
22 #include <libfdt.h>
23
24 #include "libfdt_internal.h"
25
26 #define CHECK_HEADER(fdt) \
27         { \
28                 int err; \
29                 if ((err = _fdt_check_header(fdt)) != 0) \
30                         return err; \
31         }
32
33 static int offset_streq(const void *fdt, int offset,
34                         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
51 char *fdt_string(const void *fdt, int stroffset)
52 {
53         return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
54 }
55
56 int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
57                                const char *name, int namelen)
58 {
59         int level = 0;
60         uint32_t tag;
61         int offset, nextoffset;
62
63         CHECK_HEADER(fdt);
64
65         tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
66         if (tag != FDT_BEGIN_NODE)
67                 return -FDT_ERR_BADOFFSET;
68
69         do {
70                 offset = nextoffset;
71                 tag = _fdt_next_tag(fdt, offset, &nextoffset);
72
73                 switch (tag) {
74                 case FDT_END:
75                         return -FDT_ERR_TRUNCATED;
76
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:
95                         return -FDT_ERR_BADSTRUCTURE;
96                 }
97         } while (level >= 0);
98
99         return -FDT_ERR_NOTFOUND;
100 }
101
102 int fdt_subnode_offset(const void *fdt, int parentoffset,
103                        const char *name)
104 {
105         return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
106 }
107
108 int fdt_path_offset(const void *fdt, const char *path)
109 {
110         const char *end = path + strlen(path);
111         const char *p = path;
112         int offset = 0;
113
114         CHECK_HEADER(fdt);
115
116         if (*path != '/')
117                 return -FDT_ERR_BADPATH;
118
119         while (*p) {
120                 const char *q;
121
122                 while (*p == '/')
123                         p++;
124                 if (! *p)
125                         return -FDT_ERR_BADPATH;
126                 q = strchr(p, '/');
127                 if (! q)
128                         q = end;
129
130                 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
131                 if (offset < 0)
132                         return offset;
133
134                 p = q;
135         }
136
137         return offset;  
138 }
139
140 struct fdt_property *fdt_get_property(const void *fdt,
141                                       int nodeoffset,
142                                       const char *name, int *lenp)
143 {
144         int level = 0;
145         uint32_t tag;
146         struct fdt_property *prop;
147         int namestroff;
148         int offset, nextoffset;
149         int err;
150
151         if ((err = _fdt_check_header(fdt)) != 0)
152                 goto fail;
153
154         err = -FDT_ERR_BADOFFSET;
155         if (nodeoffset % FDT_TAGSIZE)
156                 goto fail;
157
158         tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
159         if (tag != FDT_BEGIN_NODE)
160                 goto fail;
161
162         do {
163                 offset = nextoffset;
164
165                 tag = _fdt_next_tag(fdt, offset, &nextoffset);
166                 switch (tag) {
167                 case FDT_END:
168                         err = -FDT_ERR_TRUNCATED;
169                         goto fail;
170
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
183                         err = -FDT_ERR_BADSTRUCTURE;
184                         prop = fdt_offset_ptr_typed(fdt, offset, prop);
185                         if (! prop)
186                                 goto fail;
187                         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,
192                                                       sizeof(*prop)+len);
193                                 if (! prop)
194                                         goto fail;
195
196                                 if (lenp)
197                                         *lenp = len;
198                                 
199                                 return prop;
200                         }
201                         break;
202
203                 case FDT_NOP:
204                         break;
205
206                 default:
207                         err = -FDT_ERR_BADSTRUCTURE;
208                         goto fail;
209                 }
210         } while (level >= 0);
211
212         err = -FDT_ERR_NOTFOUND;
213  fail:
214         if (lenp)
215                 *lenp = err;
216         return NULL;
217 }
218
219 void *fdt_getprop(const void *fdt, int nodeoffset,
220                   const char *name, int *lenp)
221 {
222         const struct fdt_property *prop;
223
224         prop = fdt_get_property(fdt, nodeoffset, name, lenp);
225         if (! prop)
226                 return NULL;
227
228         return prop->data;
229 }