Home | History | Annotate | Line # | Download | only in fdt
      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 (at) 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 
     37 int
     38 OF_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 
     68 int
     69 OF_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 
     95 int
     96 OF_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 
    118 int
    119 OF_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 
    168 int
    169 OF_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 
    228 int
    229 OF_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 
    281 int
    282 OF_setprop(int phandle, const char *prop, const void *buf, int buflen)
    283 {
    284 	return -1;
    285 }
    286 
    287 int
    288 OF_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 
    305 int
    306 OF_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