Home | History | Annotate | Line # | Download | only in fdt
fdt_openfirm.c revision 1.1
      1 /* $NetBSD: fdt_openfirm.c,v 1.1 2015/12/13 17:30:40 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.1 2015/12/13 17:30:40 jmcneill Exp $");
     31 
     32 #include <sys/param.h>
     33 
     34 #include <libfdt.h>
     35 #include <dev/ofw/openfirm.h>
     36 #include <dev/fdt/fdt_openfirm.h>
     37 
     38 static const void *fdt_data;
     39 
     40 bool
     41 fdt_openfirm_set_data(const void *data)
     42 {
     43 	KASSERT(fdt_data == NULL);
     44 	if (fdt_check_header(data) != 0) {
     45 		return false;
     46 	}
     47 	fdt_data = data;
     48 	return true;
     49 }
     50 
     51 const void *
     52 fdt_openfirm_get_data(void)
     53 {
     54 	return fdt_data;
     55 }
     56 
     57 int
     58 fdt_openfirm_get_phandle(int offset)
     59 {
     60 	if (offset < 0)
     61 		return 0;
     62 
     63 	return offset + fdt_off_dt_struct(fdt_data);
     64 }
     65 
     66 int
     67 fdt_openfirm_get_offset(int phandle)
     68 {
     69 	const int dtoff = fdt_off_dt_struct(fdt_data);
     70 
     71 	if (phandle == -1)
     72 		phandle = dtoff;
     73 
     74 	if (phandle < dtoff)
     75 		return -1;
     76 
     77 	return phandle - dtoff;
     78 }
     79 
     80 int
     81 OF_peer(int phandle)
     82 {
     83 	int off, depth;
     84 
     85 	if (fdt_data == NULL) {
     86 		return -1;
     87 	}
     88 
     89 	if (phandle == 0) {
     90 		return fdt_openfirm_get_phandle(0);
     91 	}
     92 
     93 	off = fdt_openfirm_get_offset(phandle);
     94 	if (off < 0) {
     95 		return 0;
     96 	}
     97 
     98 	depth = 1;
     99 	for (off = fdt_next_node(fdt_data, off, &depth);
    100 	     off >= 0 && depth >= 0;
    101 	     off = fdt_next_node(fdt_data, off, &depth)) {
    102 		if (depth == 1) {
    103 			return fdt_openfirm_get_phandle(off);
    104 		}
    105 	}
    106 
    107 	return 0;
    108 }
    109 
    110 int
    111 OF_child(int phandle)
    112 {
    113 	int off, depth;
    114 
    115 	if (fdt_data == NULL) {
    116 		return -1;
    117 	}
    118 
    119 	off = fdt_openfirm_get_offset(phandle);
    120 	if (off < 0) {
    121 		return 0;
    122 	}
    123 
    124 	depth = 0;
    125 	for (off = fdt_next_node(fdt_data, off, &depth);
    126 	     off >= 0 && depth > 0;
    127 	     off = fdt_next_node(fdt_data, off, &depth)) {
    128 		if (depth == 1) {
    129 			return fdt_openfirm_get_phandle(off);
    130 		}
    131 	}
    132 
    133 	return 0;
    134 }
    135 
    136 int
    137 OF_parent(int phandle)
    138 {
    139 	int off;
    140 
    141 	if (fdt_data == NULL) {
    142 		return -1;
    143 	}
    144 
    145 	off = fdt_openfirm_get_offset(phandle);
    146 	if (off < 0) {
    147 		return -1;
    148 	}
    149 
    150 	off = fdt_parent_offset(fdt_data, off);
    151 	if (off < 0) {
    152 		return -1;
    153 	}
    154 
    155 	return fdt_openfirm_get_phandle(off);
    156 }
    157 
    158 int
    159 OF_nextprop(int phandle, const char *prop, void *nextprop)
    160 {
    161 	const char *name;
    162 	const void *val;
    163 	int off, len;
    164 
    165 	if (fdt_data == NULL) {
    166 		return -1;
    167 	}
    168 
    169 	off = fdt_openfirm_get_offset(phandle);
    170 	if (off < 0) {
    171 		return -1;
    172 	}
    173 
    174 	if (*prop == '\0') {
    175 		name = "name";
    176 	} else {
    177 		off = fdt_first_property_offset(fdt_data, off);
    178 		if (off < 0) {
    179 			return 0;
    180 		}
    181 		if (strcmp(prop, "name") != 0) {
    182 			while (off >= 0) {
    183 				val = fdt_getprop_by_offset(fdt_data, off,
    184 				    &name, &len);
    185 				if (val == NULL) {
    186 					return -1;
    187 				}
    188 				off = fdt_next_property_offset(fdt_data, off);
    189 				if (off < 0) {
    190 					return 0;
    191 				}
    192 				if (strcmp(name, prop) == 0)
    193 					break;
    194 			}
    195 		}
    196 		val = fdt_getprop_by_offset(fdt_data, off, &name, &len);
    197 		if (val == NULL) {
    198 			return -1;
    199 		}
    200 	}
    201 
    202 	strlcpy(nextprop, name, 33);
    203 
    204 	return 1;
    205 }
    206 
    207 int
    208 OF_getprop(int phandle, const char *prop, void *buf, int buflen)
    209 {
    210 	const char *name;
    211 	const void *val;
    212 	int off, len;
    213 
    214 	if (fdt_data == NULL) {
    215 		return -1;
    216 	}
    217 
    218 	off = fdt_openfirm_get_offset(phandle);
    219 	if (off < 0) {
    220 		return -1;
    221 	}
    222 
    223 	if (strcmp(prop, "name") == 0) {
    224 		val = fdt_get_name(fdt_data, off, &len);
    225 		if (val) {
    226 			const char *p = strchr(val, '@');
    227 			if (p) {
    228 				len = (uintptr_t)p - (uintptr_t)val + 1;
    229 			} else {
    230 				len += 1;
    231 			}
    232 		}
    233 		if (val == NULL || len > buflen) {
    234 			return -1;
    235 		}
    236 		char *s = buf;
    237 		memcpy(buf, val, len - 1);
    238 		s[len - 1] = '\0';
    239 	} else {
    240 		off = fdt_first_property_offset(fdt_data, off);
    241 		if (off < 0) {
    242 			return -1;
    243 		}
    244 		while (off >= 0) {
    245 			val = fdt_getprop_by_offset(fdt_data, off, &name, &len);
    246 			if (val == NULL) {
    247 				return -1;
    248 			}
    249 			if (strcmp(name, prop) == 0) {
    250 				break;
    251 			}
    252 			off = fdt_next_property_offset(fdt_data, off);
    253 			if (off < 0) {
    254 				return -1;
    255 			}
    256 		}
    257 		if (val == NULL || len > buflen) {
    258 			return -1;
    259 		}
    260 		memcpy(buf, val, len);
    261 	}
    262 
    263 	return len;
    264 }
    265 
    266 int
    267 OF_getproplen(int phandle, const char *prop)
    268 {
    269 	const char *name;
    270 	const void *val;
    271 	int off, len;
    272 
    273 	if (fdt_data == NULL) {
    274 		return -1;
    275 	}
    276 
    277 	off = fdt_openfirm_get_offset(phandle);
    278 	if (off < 0) {
    279 		return -1;
    280 	}
    281 
    282 	if (strcmp(prop, "name") == 0) {
    283 		val = fdt_get_name(fdt_data, off, &len);
    284 		if (val) {
    285 			const char *p = strchr(val, '@');
    286 			if (p) {
    287 				len = (uintptr_t)p - (uintptr_t)val + 1;
    288 			} else {
    289 				len += 1;
    290 			}
    291 		}
    292 	} else {
    293 		off = fdt_first_property_offset(fdt_data, off);
    294 		if (off < 0) {
    295 			return -1;
    296 		}
    297 		while (off >= 0) {
    298 			val = fdt_getprop_by_offset(fdt_data, off, &name, &len);
    299 			if (val == NULL) {
    300 				return -1;
    301 			}
    302 			if (strcmp(name, prop) == 0) {
    303 				break;
    304 			}
    305 			off = fdt_next_property_offset(fdt_data, off);
    306 			if (off < 0) {
    307 				return -1;
    308 			}
    309 		}
    310 	}
    311 	if (val == NULL) {
    312 		return -1;
    313 	}
    314 
    315 	return len;
    316 }
    317 
    318 int
    319 OF_setprop(int phandle, const char *prop, const void *buf, int buflen)
    320 {
    321 	return -1;
    322 }
    323 
    324 int
    325 OF_finddevice(const char *name)
    326 {
    327 	int off;
    328 
    329 	if (fdt_data == NULL) {
    330 		return -1;
    331 	}
    332 
    333 	off = fdt_path_offset(fdt_data, name);
    334 	if (off < 0) {
    335 		return -1;
    336 	}
    337 
    338 	return fdt_openfirm_get_phandle(off);
    339 }
    340 
    341 int
    342 OF_package_to_path(int phandle, char *buf, int buflen)
    343 {
    344 	int off;
    345 
    346 	if (fdt_data == NULL) {
    347 		return -1;
    348 	}
    349 
    350 	off = fdt_openfirm_get_offset(phandle);
    351 	if (off < 0) {
    352 		return -1;
    353 	}
    354 
    355 	if (fdt_get_path(fdt_data, off, buf, buflen) != 0)
    356 		return -1;
    357 
    358 	return strlen(buf);
    359 }
    360