1/* $NetBSD: fdt_openfirm.c,v 1.2 2015/12/16 12:17:45 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: fdt_openfirm.c,v 1.2 2015/12/16 12:17:45 jmcneill Exp $"); 31 32#include <sys/param.h> 33 34#include <libfdt.h> 35#include <dev/fdt/fdtvar.h> 36 37int 38OF_peer(int phandle) 39{ 40 const void *fdt_data = fdtbus_get_data(); 41 int off, depth; 42 43 if (fdt_data == NULL) { 44 return -1; 45 } 46 47 if (phandle == 0) { 48 return fdtbus_offset2phandle(0); 49 } 50 51 off = fdtbus_phandle2offset(phandle); 52 if (off < 0) { 53 return 0; 54 } 55 56 depth = 1; 57 for (off = fdt_next_node(fdt_data, off, &depth); 58 off >= 0 && depth >= 0; 59 off = fdt_next_node(fdt_data, off, &depth)) { 60 if (depth == 1) { 61 return fdtbus_offset2phandle(off); 62 } 63 } 64 65 return 0; 66} 67 68int 69OF_child(int phandle) 70{ 71 const void *fdt_data = fdtbus_get_data(); 72 int off, depth; 73 74 if (fdt_data == NULL) { 75 return -1; 76 } 77 78 off = fdtbus_phandle2offset(phandle); 79 if (off < 0) { 80 return 0; 81 } 82 83 depth = 0; 84 for (off = fdt_next_node(fdt_data, off, &depth); 85 off >= 0 && depth > 0; 86 off = fdt_next_node(fdt_data, off, &depth)) { 87 if (depth == 1) { 88 return fdtbus_offset2phandle(off); 89 } 90 } 91 92 return 0; 93} 94 95int 96OF_parent(int phandle) 97{ 98 const void *fdt_data = fdtbus_get_data(); 99 int off; 100 101 if (fdt_data == NULL) { 102 return -1; 103 } 104 105 off = fdtbus_phandle2offset(phandle); 106 if (off < 0) { 107 return -1; 108 } 109 110 off = fdt_parent_offset(fdt_data, off); 111 if (off < 0) { 112 return -1; 113 } 114 115 return fdtbus_offset2phandle(off); 116} 117 118int 119OF_nextprop(int phandle, const char *prop, void *nextprop) 120{ 121 const void *fdt_data = fdtbus_get_data(); 122 const char *name; 123 const void *val; 124 int off, len; 125 126 if (fdt_data == NULL) { 127 return -1; 128 } 129 130 off = fdtbus_phandle2offset(phandle); 131 if (off < 0) { 132 return -1; 133 } 134 135 if (*prop == '\0') { 136 name = "name"; 137 } else { 138 off = fdt_first_property_offset(fdt_data, off); 139 if (off < 0) { 140 return 0; 141 } 142 if (strcmp(prop, "name") != 0) { 143 while (off >= 0) { 144 val = fdt_getprop_by_offset(fdt_data, off, 145 &name, &len); 146 if (val == NULL) { 147 return -1; 148 } 149 off = fdt_next_property_offset(fdt_data, off); 150 if (off < 0) { 151 return 0; 152 } 153 if (strcmp(name, prop) == 0) 154 break; 155 } 156 } 157 val = fdt_getprop_by_offset(fdt_data, off, &name, &len); 158 if (val == NULL) { 159 return -1; 160 } 161 } 162 163 strlcpy(nextprop, name, 33); 164 165 return 1; 166} 167 168int 169OF_getprop(int phandle, const char *prop, void *buf, int buflen) 170{ 171 const void *fdt_data = fdtbus_get_data(); 172 const char *name; 173 const void *val; 174 int off, len; 175 176 if (fdt_data == NULL) { 177 return -1; 178 } 179 180 off = fdtbus_phandle2offset(phandle); 181 if (off < 0) { 182 return -1; 183 } 184 185 if (strcmp(prop, "name") == 0) { 186 val = fdt_get_name(fdt_data, off, &len); 187 if (val) { 188 const char *p = strchr(val, '@'); 189 if (p) { 190 len = (uintptr_t)p - (uintptr_t)val + 1; 191 } else { 192 len += 1; 193 } 194 } 195 if (val == NULL || len > buflen) { 196 return -1; 197 } 198 char *s = buf; 199 memcpy(buf, val, len - 1); 200 s[len - 1] = '\0'; 201 } else { 202 off = fdt_first_property_offset(fdt_data, off); 203 if (off < 0) { 204 return -1; 205 } 206 while (off >= 0) { 207 val = fdt_getprop_by_offset(fdt_data, off, &name, &len); 208 if (val == NULL) { 209 return -1; 210 } 211 if (strcmp(name, prop) == 0) { 212 break; 213 } 214 off = fdt_next_property_offset(fdt_data, off); 215 if (off < 0) { 216 return -1; 217 } 218 } 219 if (val == NULL || len > buflen) { 220 return -1; 221 } 222 memcpy(buf, val, len); 223 } 224 225 return len; 226} 227 228int 229OF_getproplen(int phandle, const char *prop) 230{ 231 const void *fdt_data = fdtbus_get_data(); 232 const char *name; 233 const void *val; 234 int off, len; 235 236 if (fdt_data == NULL) { 237 return -1; 238 } 239 240 off = fdtbus_phandle2offset(phandle); 241 if (off < 0) { 242 return -1; 243 } 244 245 if (strcmp(prop, "name") == 0) { 246 val = fdt_get_name(fdt_data, off, &len); 247 if (val) { 248 const char *p = strchr(val, '@'); 249 if (p) { 250 len = (uintptr_t)p - (uintptr_t)val + 1; 251 } else { 252 len += 1; 253 } 254 } 255 } else { 256 off = fdt_first_property_offset(fdt_data, off); 257 if (off < 0) { 258 return -1; 259 } 260 while (off >= 0) { 261 val = fdt_getprop_by_offset(fdt_data, off, &name, &len); 262 if (val == NULL) { 263 return -1; 264 } 265 if (strcmp(name, prop) == 0) { 266 break; 267 } 268 off = fdt_next_property_offset(fdt_data, off); 269 if (off < 0) { 270 return -1; 271 } 272 } 273 } 274 if (val == NULL) { 275 return -1; 276 } 277 278 return len; 279} 280 281int 282OF_setprop(int phandle, const char *prop, const void *buf, int buflen) 283{ 284 return -1; 285} 286 287int 288OF_finddevice(const char *name) 289{ 290 const void *fdt_data = fdtbus_get_data(); 291 int off; 292 293 if (fdt_data == NULL) { 294 return -1; 295 } 296 297 off = fdt_path_offset(fdt_data, name); 298 if (off < 0) { 299 return -1; 300 } 301 302 return fdtbus_offset2phandle(off); 303} 304 305int 306OF_package_to_path(int phandle, char *buf, int buflen) 307{ 308 const void *fdt_data = fdtbus_get_data(); 309 int off; 310 311 if (fdt_data == NULL) { 312 return -1; 313 } 314 315 off = fdtbus_phandle2offset(phandle); 316 if (off < 0) { 317 return -1; 318 } 319 320 if (fdt_get_path(fdt_data, off, buf, buflen) != 0) 321 return -1; 322 323 return strlen(buf); 324} 325