xref: /freebsd/sys/dev/ofw/openfirm.c (revision 718cf2ccb9956613756ab15d7a0e28f2c8e91cab)
1 /*	$NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-4-Clause
5  *
6  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7  * Copyright (C) 1995, 1996 TooLs GmbH.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by TooLs GmbH.
21  * 4. The name of TooLs GmbH may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /*-
36  * Copyright (C) 2000 Benno Rice.
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  *
48  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
49  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
53  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
54  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
56  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
57  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 #include <sys/cdefs.h>
61 __FBSDID("$FreeBSD$");
62 
63 #include "opt_platform.h"
64 
65 #include <sys/param.h>
66 #include <sys/kernel.h>
67 #include <sys/lock.h>
68 #include <sys/malloc.h>
69 #include <sys/mutex.h>
70 #include <sys/queue.h>
71 #include <sys/systm.h>
72 #include <sys/endian.h>
73 
74 #include <machine/stdarg.h>
75 
76 #include <dev/ofw/ofwvar.h>
77 #include <dev/ofw/openfirm.h>
78 
79 #include "ofw_if.h"
80 
81 static void OF_putchar(int c, void *arg);
82 
83 MALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties");
84 
85 static ihandle_t stdout;
86 
87 static ofw_def_t	*ofw_def_impl = NULL;
88 static ofw_t		ofw_obj;
89 static struct ofw_kobj	ofw_kernel_obj;
90 static struct kobj_ops	ofw_kernel_kops;
91 
92 struct xrefinfo {
93 	phandle_t	xref;
94 	phandle_t 	node;
95 	device_t  	dev;
96 	SLIST_ENTRY(xrefinfo) next_entry;
97 };
98 
99 static SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist);
100 static struct mtx xreflist_lock;
101 static boolean_t xref_init_done;
102 
103 #define	FIND_BY_XREF	0
104 #define	FIND_BY_NODE	1
105 #define	FIND_BY_DEV	2
106 
107 /*
108  * xref-phandle-device lookup helper routines.
109  *
110  * As soon as we are able to use malloc(), walk the node tree and build a list
111  * of info that cross-references node handles, xref handles, and device_t
112  * instances.  This list exists primarily to allow association of a device_t
113  * with an xref handle, but it is also used to speed up translation between xref
114  * and node handles.  Before malloc() is available we have to recursively search
115  * the node tree each time we want to translate between a node and xref handle.
116  * Afterwards we can do the translations by searching this much shorter list.
117  */
118 static void
119 xrefinfo_create(phandle_t node)
120 {
121 	struct xrefinfo * xi;
122 	phandle_t child, xref;
123 
124 	/*
125 	 * Recursively descend from parent, looking for nodes with a property
126 	 * named either "phandle", "ibm,phandle", or "linux,phandle".  For each
127 	 * such node found create an entry in the xreflist.
128 	 */
129 	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
130 		xrefinfo_create(child);
131 		if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) ==
132 		    -1 && OF_getencprop(child, "ibm,phandle", &xref,
133 		    sizeof(xref)) == -1 && OF_getencprop(child,
134 		    "linux,phandle", &xref, sizeof(xref)) == -1)
135 			continue;
136 		xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO);
137 		xi->node = child;
138 		xi->xref = xref;
139 		SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
140 	}
141 }
142 
143 static void
144 xrefinfo_init(void *unsed)
145 {
146 
147 	/*
148 	 * There is no locking during this init because it runs much earlier
149 	 * than any of the clients/consumers of the xref list data, but we do
150 	 * initialize the mutex that will be used for access later.
151 	 */
152 	mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF);
153 	xrefinfo_create(OF_peer(0));
154 	xref_init_done = true;
155 }
156 SYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL);
157 
158 static struct xrefinfo *
159 xrefinfo_find(uintptr_t key, int find_by)
160 {
161 	struct xrefinfo *rv, *xi;
162 
163 	rv = NULL;
164 	mtx_lock(&xreflist_lock);
165 	SLIST_FOREACH(xi, &xreflist, next_entry) {
166 		if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) ||
167 		    (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) ||
168 		    (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) {
169 			rv = xi;
170 			break;
171 		}
172 	}
173 	mtx_unlock(&xreflist_lock);
174 	return (rv);
175 }
176 
177 static struct xrefinfo *
178 xrefinfo_add(phandle_t node, phandle_t xref, device_t dev)
179 {
180 	struct xrefinfo *xi;
181 
182 	xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK);
183 	xi->node = node;
184 	xi->xref = xref;
185 	xi->dev  = dev;
186 	mtx_lock(&xreflist_lock);
187 	SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
188 	mtx_unlock(&xreflist_lock);
189 	return (xi);
190 }
191 
192 /*
193  * OFW install routines.  Highest priority wins, equal priority also
194  * overrides allowing last-set to win.
195  */
196 SET_DECLARE(ofw_set, ofw_def_t);
197 
198 boolean_t
199 OF_install(char *name, int prio)
200 {
201 	ofw_def_t *ofwp, **ofwpp;
202 	static int curr_prio = 0;
203 
204 	/*
205 	 * Try and locate the OFW kobj corresponding to the name.
206 	 */
207 	SET_FOREACH(ofwpp, ofw_set) {
208 		ofwp = *ofwpp;
209 
210 		if (ofwp->name &&
211 		    !strcmp(ofwp->name, name) &&
212 		    prio >= curr_prio) {
213 			curr_prio = prio;
214 			ofw_def_impl = ofwp;
215 			return (TRUE);
216 		}
217 	}
218 
219 	return (FALSE);
220 }
221 
222 /* Initializer */
223 int
224 OF_init(void *cookie)
225 {
226 	phandle_t chosen;
227 	int rv;
228 
229 	if (ofw_def_impl == NULL)
230 		return (-1);
231 
232 	ofw_obj = &ofw_kernel_obj;
233 	/*
234 	 * Take care of compiling the selected class, and
235 	 * then statically initialize the OFW object.
236 	 */
237 	kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops);
238 	kobj_init_static((kobj_t)ofw_obj, ofw_def_impl);
239 
240 	rv = OFW_INIT(ofw_obj, cookie);
241 
242 	if ((chosen = OF_finddevice("/chosen")) != -1)
243 		if (OF_getencprop(chosen, "stdout", &stdout,
244 		    sizeof(stdout)) == -1)
245 			stdout = -1;
246 
247 	return (rv);
248 }
249 
250 static void
251 OF_putchar(int c, void *arg __unused)
252 {
253 	char cbuf;
254 
255 	if (c == '\n') {
256 		cbuf = '\r';
257 		OF_write(stdout, &cbuf, 1);
258 	}
259 
260 	cbuf = c;
261 	OF_write(stdout, &cbuf, 1);
262 }
263 
264 void
265 OF_printf(const char *fmt, ...)
266 {
267 	va_list	va;
268 
269 	va_start(va, fmt);
270 	(void)kvprintf(fmt, OF_putchar, NULL, 10, va);
271 	va_end(va);
272 }
273 
274 /*
275  * Generic functions
276  */
277 
278 /* Test to see if a service exists. */
279 int
280 OF_test(const char *name)
281 {
282 
283 	if (ofw_def_impl == NULL)
284 		return (-1);
285 
286 	return (OFW_TEST(ofw_obj, name));
287 }
288 
289 int
290 OF_interpret(const char *cmd, int nreturns, ...)
291 {
292 	va_list ap;
293 	cell_t slots[16];
294 	int i = 0;
295 	int status;
296 
297 	if (ofw_def_impl == NULL)
298 		return (-1);
299 
300 	status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots);
301 	if (status == -1)
302 		return (status);
303 
304 	va_start(ap, nreturns);
305 	while (i < nreturns)
306 		*va_arg(ap, cell_t *) = slots[i++];
307 	va_end(ap);
308 
309 	return (status);
310 }
311 
312 /*
313  * Device tree functions
314  */
315 
316 /* Return the next sibling of this node or 0. */
317 phandle_t
318 OF_peer(phandle_t node)
319 {
320 
321 	if (ofw_def_impl == NULL)
322 		return (0);
323 
324 	return (OFW_PEER(ofw_obj, node));
325 }
326 
327 /* Return the first child of this node or 0. */
328 phandle_t
329 OF_child(phandle_t node)
330 {
331 
332 	if (ofw_def_impl == NULL)
333 		return (0);
334 
335 	return (OFW_CHILD(ofw_obj, node));
336 }
337 
338 /* Return the parent of this node or 0. */
339 phandle_t
340 OF_parent(phandle_t node)
341 {
342 
343 	if (ofw_def_impl == NULL)
344 		return (0);
345 
346 	return (OFW_PARENT(ofw_obj, node));
347 }
348 
349 /* Return the package handle that corresponds to an instance handle. */
350 phandle_t
351 OF_instance_to_package(ihandle_t instance)
352 {
353 
354 	if (ofw_def_impl == NULL)
355 		return (-1);
356 
357 	return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance));
358 }
359 
360 /* Get the length of a property of a package. */
361 ssize_t
362 OF_getproplen(phandle_t package, const char *propname)
363 {
364 
365 	if (ofw_def_impl == NULL)
366 		return (-1);
367 
368 	return (OFW_GETPROPLEN(ofw_obj, package, propname));
369 }
370 
371 /* Check existence of a property of a package. */
372 int
373 OF_hasprop(phandle_t package, const char *propname)
374 {
375 
376 	return (OF_getproplen(package, propname) >= 0 ? 1 : 0);
377 }
378 
379 /* Get the value of a property of a package. */
380 ssize_t
381 OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
382 {
383 
384 	if (ofw_def_impl == NULL)
385 		return (-1);
386 
387 	return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen));
388 }
389 
390 ssize_t
391 OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
392 {
393 	ssize_t retval;
394 	int i;
395 
396 	KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes"));
397 
398 	retval = OF_getprop(node, propname, buf, len);
399 	if (retval <= 0)
400 		return (retval);
401 
402 	for (i = 0; i < len/4; i++)
403 		buf[i] = be32toh(buf[i]);
404 
405 	return (retval);
406 }
407 
408 /*
409  * Recursively search the node and its parent for the given property, working
410  * downward from the node to the device tree root.  Returns the value of the
411  * first match.
412  */
413 ssize_t
414 OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len)
415 {
416 	ssize_t rv;
417 
418 	for (; node != 0; node = OF_parent(node))
419 		if ((rv = OF_getprop(node, propname, buf, len)) != -1)
420 			return (rv);
421 	return (-1);
422 }
423 
424 ssize_t
425 OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len)
426 {
427 	ssize_t rv;
428 
429 	for (; node != 0; node = OF_parent(node))
430 		if ((rv = OF_getencprop(node, propname, buf, len)) != -1)
431 			return (rv);
432 	return (-1);
433 }
434 
435 /*
436  * Store the value of a property of a package into newly allocated memory
437  * (using the M_OFWPROP malloc pool and M_WAITOK).  elsz is the size of a
438  * single element, the number of elements is return in number.
439  */
440 ssize_t
441 OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf)
442 {
443 	int len;
444 
445 	*buf = NULL;
446 	if ((len = OF_getproplen(package, propname)) == -1 ||
447 	    len % elsz != 0)
448 		return (-1);
449 
450 	*buf = malloc(len, M_OFWPROP, M_WAITOK);
451 	if (OF_getprop(package, propname, *buf, len) == -1) {
452 		free(*buf, M_OFWPROP);
453 		*buf = NULL;
454 		return (-1);
455 	}
456 	return (len / elsz);
457 }
458 
459 ssize_t
460 OF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf)
461 {
462 	ssize_t retval;
463 	pcell_t *cell;
464 	int i;
465 
466 	retval = OF_getprop_alloc(package, name, elsz, buf);
467 	if (retval == -1)
468 		return (-1);
469  	if (retval * elsz % 4 != 0) {
470 		free(*buf, M_OFWPROP);
471 		*buf = NULL;
472 		return (-1);
473 	}
474 
475 	cell = *buf;
476 	for (i = 0; i < retval * elsz / 4; i++)
477 		cell[i] = be32toh(cell[i]);
478 
479 	return (retval);
480 }
481 
482 /* Free buffer allocated by OF_getencprop_alloc or OF_getprop_alloc */
483 void OF_prop_free(void *buf)
484 {
485 
486 	free(buf, M_OFWPROP);
487 }
488 
489 /* Get the next property of a package. */
490 int
491 OF_nextprop(phandle_t package, const char *previous, char *buf, size_t size)
492 {
493 
494 	if (ofw_def_impl == NULL)
495 		return (-1);
496 
497 	return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size));
498 }
499 
500 /* Set the value of a property of a package. */
501 int
502 OF_setprop(phandle_t package, const char *propname, const void *buf, size_t len)
503 {
504 
505 	if (ofw_def_impl == NULL)
506 		return (-1);
507 
508 	return (OFW_SETPROP(ofw_obj, package, propname, buf,len));
509 }
510 
511 /* Convert a device specifier to a fully qualified pathname. */
512 ssize_t
513 OF_canon(const char *device, char *buf, size_t len)
514 {
515 
516 	if (ofw_def_impl == NULL)
517 		return (-1);
518 
519 	return (OFW_CANON(ofw_obj, device, buf, len));
520 }
521 
522 /* Return a package handle for the specified device. */
523 phandle_t
524 OF_finddevice(const char *device)
525 {
526 
527 	if (ofw_def_impl == NULL)
528 		return (-1);
529 
530 	return (OFW_FINDDEVICE(ofw_obj, device));
531 }
532 
533 /* Return the fully qualified pathname corresponding to an instance. */
534 ssize_t
535 OF_instance_to_path(ihandle_t instance, char *buf, size_t len)
536 {
537 
538 	if (ofw_def_impl == NULL)
539 		return (-1);
540 
541 	return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len));
542 }
543 
544 /* Return the fully qualified pathname corresponding to a package. */
545 ssize_t
546 OF_package_to_path(phandle_t package, char *buf, size_t len)
547 {
548 
549 	if (ofw_def_impl == NULL)
550 		return (-1);
551 
552 	return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len));
553 }
554 
555 /* Look up effective phandle (see FDT/PAPR spec) */
556 static phandle_t
557 OF_child_xref_phandle(phandle_t parent, phandle_t xref)
558 {
559 	phandle_t child, rxref;
560 
561 	/*
562 	 * Recursively descend from parent, looking for a node with a property
563 	 * named either "phandle", "ibm,phandle", or "linux,phandle" that
564 	 * matches the xref we are looking for.
565 	 */
566 
567 	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
568 		rxref = OF_child_xref_phandle(child, xref);
569 		if (rxref != -1)
570 			return (rxref);
571 
572 		if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) ==
573 		    -1 && OF_getencprop(child, "ibm,phandle", &rxref,
574 		    sizeof(rxref)) == -1 && OF_getencprop(child,
575 		    "linux,phandle", &rxref, sizeof(rxref)) == -1)
576 			continue;
577 
578 		if (rxref == xref)
579 			return (child);
580 	}
581 
582 	return (-1);
583 }
584 
585 phandle_t
586 OF_node_from_xref(phandle_t xref)
587 {
588 	struct xrefinfo *xi;
589 	phandle_t node;
590 
591 	if (xref_init_done) {
592 		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
593 			return (xref);
594 		return (xi->node);
595 	}
596 
597 	if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1)
598 		return (xref);
599 	return (node);
600 }
601 
602 phandle_t
603 OF_xref_from_node(phandle_t node)
604 {
605 	struct xrefinfo *xi;
606 	phandle_t xref;
607 
608 	if (xref_init_done) {
609 		if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL)
610 			return (node);
611 		return (xi->xref);
612 	}
613 
614 	if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 &&
615 	    OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 &&
616 	    OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1)
617 		return (node);
618 	return (xref);
619 }
620 
621 device_t
622 OF_device_from_xref(phandle_t xref)
623 {
624 	struct xrefinfo *xi;
625 
626 	if (xref_init_done) {
627 		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
628 			return (NULL);
629 		return (xi->dev);
630 	}
631 	panic("Attempt to find device before xreflist_init");
632 }
633 
634 phandle_t
635 OF_xref_from_device(device_t dev)
636 {
637 	struct xrefinfo *xi;
638 
639 	if (xref_init_done) {
640 		if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL)
641 			return (0);
642 		return (xi->xref);
643 	}
644 	panic("Attempt to find xref before xreflist_init");
645 }
646 
647 int
648 OF_device_register_xref(phandle_t xref, device_t dev)
649 {
650 	struct xrefinfo *xi;
651 
652 	/*
653 	 * If the given xref handle doesn't already exist in the list then we
654 	 * add a list entry.  In theory this can only happen on a system where
655 	 * nodes don't contain phandle properties and xref and node handles are
656 	 * synonymous, so the xref handle is added as the node handle as well.
657 	 */
658 	if (xref_init_done) {
659 		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
660 			xrefinfo_add(xref, xref, dev);
661 		else
662 			xi->dev = dev;
663 		return (0);
664 	}
665 	panic("Attempt to register device before xreflist_init");
666 }
667 
668 /*  Call the method in the scope of a given instance. */
669 int
670 OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns,
671     ...)
672 {
673 	va_list ap;
674 	cell_t args_n_results[12];
675 	int n, status;
676 
677 	if (nargs > 6 || ofw_def_impl == NULL)
678 		return (-1);
679 	va_start(ap, nreturns);
680 	for (n = 0; n < nargs; n++)
681 		args_n_results[n] = va_arg(ap, cell_t);
682 
683 	status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns,
684 	    args_n_results);
685 	if (status != 0)
686 		return (status);
687 
688 	for (; n < nargs + nreturns; n++)
689 		*va_arg(ap, cell_t *) = args_n_results[n];
690 	va_end(ap);
691 	return (0);
692 }
693 
694 /*
695  * Device I/O functions
696  */
697 
698 /* Open an instance for a device. */
699 ihandle_t
700 OF_open(const char *device)
701 {
702 
703 	if (ofw_def_impl == NULL)
704 		return (0);
705 
706 	return (OFW_OPEN(ofw_obj, device));
707 }
708 
709 /* Close an instance. */
710 void
711 OF_close(ihandle_t instance)
712 {
713 
714 	if (ofw_def_impl == NULL)
715 		return;
716 
717 	OFW_CLOSE(ofw_obj, instance);
718 }
719 
720 /* Read from an instance. */
721 ssize_t
722 OF_read(ihandle_t instance, void *addr, size_t len)
723 {
724 
725 	if (ofw_def_impl == NULL)
726 		return (-1);
727 
728 	return (OFW_READ(ofw_obj, instance, addr, len));
729 }
730 
731 /* Write to an instance. */
732 ssize_t
733 OF_write(ihandle_t instance, const void *addr, size_t len)
734 {
735 
736 	if (ofw_def_impl == NULL)
737 		return (-1);
738 
739 	return (OFW_WRITE(ofw_obj, instance, addr, len));
740 }
741 
742 /* Seek to a position. */
743 int
744 OF_seek(ihandle_t instance, uint64_t pos)
745 {
746 
747 	if (ofw_def_impl == NULL)
748 		return (-1);
749 
750 	return (OFW_SEEK(ofw_obj, instance, pos));
751 }
752 
753 /*
754  * Memory functions
755  */
756 
757 /* Claim an area of memory. */
758 void *
759 OF_claim(void *virt, size_t size, u_int align)
760 {
761 
762 	if (ofw_def_impl == NULL)
763 		return ((void *)-1);
764 
765 	return (OFW_CLAIM(ofw_obj, virt, size, align));
766 }
767 
768 /* Release an area of memory. */
769 void
770 OF_release(void *virt, size_t size)
771 {
772 
773 	if (ofw_def_impl == NULL)
774 		return;
775 
776 	OFW_RELEASE(ofw_obj, virt, size);
777 }
778 
779 /*
780  * Control transfer functions
781  */
782 
783 /* Suspend and drop back to the Open Firmware interface. */
784 void
785 OF_enter()
786 {
787 
788 	if (ofw_def_impl == NULL)
789 		return;
790 
791 	OFW_ENTER(ofw_obj);
792 }
793 
794 /* Shut down and drop back to the Open Firmware interface. */
795 void
796 OF_exit()
797 {
798 
799 	if (ofw_def_impl == NULL)
800 		panic("OF_exit: Open Firmware not available");
801 
802 	/* Should not return */
803 	OFW_EXIT(ofw_obj);
804 
805 	for (;;)			/* just in case */
806 		;
807 }
808