xref: /openbsd-src/sys/arch/sparc64/sparc64/openfirm.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: openfirm.c,v 1.19 2016/05/19 09:15:28 kettenis Exp $	*/
2 /*	$NetBSD: openfirm.c,v 1.13 2001/06/21 00:08:02 eeh Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6  * Copyright (C) 1995, 1996 TooLs GmbH.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by TooLs GmbH.
20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/stdarg.h>
37 #include <machine/psl.h>
38 
39 #include <machine/openfirm.h>
40 
41 #define min(x,y)	((x<y)?(x):(y))
42 
43 int
44 OF_peer(phandle)
45 	int phandle;
46 {
47 	struct {
48 		cell_t name;
49 		cell_t nargs;
50 		cell_t nreturns;
51 		cell_t phandle;
52 		cell_t sibling;
53 	} args;
54 
55 	args.name = ADR2CELL("peer");
56 	args.nargs = 1;
57 	args.nreturns = 1;
58 	args.phandle = HDL2CELL(phandle);
59 	if (openfirmware(&args) == -1)
60 		return 0;
61 	return args.sibling;
62 }
63 
64 int
65 OF_child(phandle)
66 	int phandle;
67 {
68 	struct {
69 		cell_t name;
70 		cell_t nargs;
71 		cell_t nreturns;
72 		cell_t phandle;
73 		cell_t child;
74 	} args;
75 
76 	args.name = ADR2CELL("child");
77 	args.nargs = 1;
78 	args.nreturns = 1;
79 	args.phandle = HDL2CELL(phandle);
80 	if (openfirmware(&args) == -1)
81 		return 0;
82 	return args.child;
83 }
84 
85 int
86 OF_parent(phandle)
87 	int phandle;
88 {
89 	struct {
90 		cell_t name;
91 		cell_t nargs;
92 		cell_t nreturns;
93 		cell_t phandle;
94 		cell_t parent;
95 	} args;
96 
97 	args.name = ADR2CELL("parent");
98 	args.nargs = 1;
99 	args.nreturns = 1;
100 	args.phandle = HDL2CELL(phandle);
101 	if (openfirmware(&args) == -1)
102 		return 0;
103 	return args.parent;
104 }
105 
106 int
107 OF_instance_to_package(ihandle)
108 	int ihandle;
109 {
110 	static struct {
111 		cell_t name;
112 		cell_t nargs;
113 		cell_t nreturns;
114 		cell_t ihandle;
115 		cell_t phandle;
116 	} args;
117 
118 	args.name = ADR2CELL("instance-to-package");
119 	args.nargs = 1;
120 	args.nreturns = 1;
121 	args.ihandle = HDL2CELL(ihandle);
122 	if (openfirmware(&args) == -1)
123 		return -1;
124 	return args.phandle;
125 }
126 
127 /* Should really return a `long' */
128 int
129 OF_getproplen(handle, prop)
130 	int handle;
131 	char *prop;
132 {
133 	struct {
134 		cell_t name;
135 		cell_t nargs;
136 		cell_t nreturns;
137 		cell_t phandle;
138 		cell_t prop;
139 		cell_t size;
140 	} args;
141 
142 	args.name = ADR2CELL("getproplen");
143 	args.nargs = 2;
144 	args.nreturns = 1;
145 	args.phandle = HDL2CELL(handle);
146 	args.prop = ADR2CELL(prop);
147 	if (openfirmware(&args) == -1)
148 		return -1;
149 	return args.size;
150 }
151 
152 int
153 OF_getprop(handle, prop, buf, buflen)
154 	int handle;
155 	char *prop;
156 	void *buf;
157 	int buflen;
158 {
159 	struct {
160 		cell_t name;
161 		cell_t nargs;
162 		cell_t nreturns;
163 		cell_t phandle;
164 		cell_t prop;
165 		cell_t buf;
166 		cell_t buflen;
167 		cell_t size;
168 	} args;
169 
170 	if (buflen > NBPG)
171 		return -1;
172 	args.name = ADR2CELL("getprop");
173 	args.nargs = 4;
174 	args.nreturns = 1;
175 	args.phandle = HDL2CELL(handle);
176 	args.prop = ADR2CELL(prop);
177 	args.buf = ADR2CELL(buf);
178 	args.buflen = buflen;
179 	if (openfirmware(&args) == -1)
180 		return -1;
181 	return args.size;
182 }
183 
184 int
185 OF_setprop(handle, prop, buf, buflen)
186 	int handle;
187 	char *prop;
188 	const void *buf;
189 	int buflen;
190 {
191 	struct {
192 		cell_t name;
193 		cell_t nargs;
194 		cell_t nreturns;
195 		cell_t phandle;
196 		cell_t prop;
197 		cell_t buf;
198 		cell_t buflen;
199 		cell_t size;
200 	} args;
201 
202 	if (buflen > NBPG)
203 		return -1;
204 	args.name = ADR2CELL("setprop");
205 	args.nargs = 4;
206 	args.nreturns = 1;
207 	args.phandle = HDL2CELL(handle);
208 	args.prop = ADR2CELL(prop);
209 	args.buf = ADR2CELL(buf);
210 	args.buflen = buflen;
211 	if (openfirmware(&args) == -1)
212 		return -1;
213 	return args.size;
214 }
215 
216 int
217 OF_nextprop(handle, prop, buf)
218 	int handle;
219 	char *prop;
220 	void *buf;
221 {
222 	struct {
223 		cell_t name;
224 		cell_t nargs;
225 		cell_t nreturns;
226 		cell_t phandle;
227 		cell_t prev;
228 		cell_t buf;
229 		cell_t next;
230 	} args;
231 
232 	args.name = ADR2CELL("nextprop");
233 	args.nargs = 3;
234 	args.nreturns = 1;
235 	args.phandle = HDL2CELL(handle);
236 	args.prev = ADR2CELL(prop);
237 	args.buf = ADR2CELL(buf);
238 	if (openfirmware(&args) == -1)
239 		return -1;
240 	return args.next;
241 }
242 
243 int
244 OF_finddevice(name)
245 char *name;
246 {
247 	struct {
248 		cell_t name;
249 		cell_t nargs;
250 		cell_t nreturns;
251 		cell_t device;
252 		cell_t phandle;
253 	} args;
254 
255 	args.name = ADR2CELL("finddevice");
256 	args.nargs = 1;
257 	args.nreturns = 1;
258 	args.device = ADR2CELL(name);
259 	if (openfirmware(&args) == -1)
260 		return -1;
261 	return args.phandle;
262 }
263 
264 int
265 OF_instance_to_path(ihandle, buf, buflen)
266 	int ihandle;
267 	char *buf;
268 	int buflen;
269 {
270 	struct {
271 		cell_t name;
272 		cell_t nargs;
273 		cell_t nreturns;
274 		cell_t ihandle;
275 		cell_t buf;
276 		cell_t buflen;
277 		cell_t length;
278 	} args;
279 
280 	if (buflen > NBPG)
281 		return -1;
282 	args.name = ADR2CELL("instance-to-path");
283 	args.nargs = 3;
284 	args.nreturns = 1;
285 	args.ihandle = HDL2CELL(ihandle);
286 	args.buf = ADR2CELL(buf);
287 	args.buflen = buflen;
288 	if (openfirmware(&args) < 0)
289 		return -1;
290 	return args.length;
291 }
292 
293 int
294 OF_package_to_path(phandle, buf, buflen)
295 	int phandle;
296 	char *buf;
297 	int buflen;
298 {
299 	struct {
300 		cell_t name;
301 		cell_t nargs;
302 		cell_t nreturns;
303 		cell_t phandle;
304 		cell_t buf;
305 		cell_t buflen;
306 		cell_t length;
307 	} args;
308 
309 	if (buflen > NBPG)
310 		return -1;
311 	args.name = ADR2CELL("package-to-path");
312 	args.nargs = 3;
313 	args.nreturns = 1;
314 	args.phandle = HDL2CELL(phandle);
315 	args.buf = ADR2CELL(buf);
316 	args.buflen = buflen;
317 	if (openfirmware(&args) < 0)
318 		return -1;
319 	return args.length;
320 }
321 
322 /*
323  * The following two functions may need to be re-worked to be 64-bit clean.
324  */
325 int
326 OF_call_method(char *method, int ihandle, int nargs, int nreturns, ...)
327 {
328 	va_list ap;
329 	struct {
330 		cell_t name;
331 		cell_t nargs;
332 		cell_t nreturns;
333 		cell_t method;
334 		cell_t ihandle;
335 		cell_t args_n_results[12];
336 	} args;
337 	long *ip, n;
338 
339 	if (nargs > 6)
340 		return -1;
341 	args.name = ADR2CELL("call-method");
342 	args.nargs = nargs + 2;
343 	args.nreturns = nreturns + 1;
344 	args.method = ADR2CELL(method);
345 	args.ihandle = HDL2CELL(ihandle);
346 	va_start(ap, nreturns);
347 	for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;)
348 		*--ip = va_arg(ap, unsigned long);
349 	if (openfirmware(&args) == -1) {
350 		va_end(ap);
351 		return -1;
352 	}
353 	if (args.args_n_results[nargs]) {
354 		va_end(ap);
355 		return args.args_n_results[nargs];
356 	}
357 	for (ip = (long *)(args.args_n_results + nargs + (n = args.nreturns)); --n > 0;)
358 		*va_arg(ap, unsigned long *) = *--ip;
359 	va_end(ap);
360 	return 0;
361 }
362 
363 int
364 OF_call_method_1(char *method, int ihandle, int nargs, ...)
365 {
366 	va_list ap;
367 	struct {
368 		cell_t name;
369 		cell_t nargs;
370 		cell_t nreturns;
371 		cell_t method;
372 		cell_t ihandle;
373 		cell_t args_n_results[16];
374 	} args;
375 	long *ip, n;
376 
377 	if (nargs > 6)
378 		return -1;
379 	args.name = ADR2CELL("call-method");
380 	args.nargs = nargs + 2;
381 	args.nreturns = 1;
382 	args.method = ADR2CELL(method);
383 	args.ihandle = HDL2CELL(ihandle);
384 	va_start(ap, nargs);
385 	for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;)
386 		*--ip = va_arg(ap, unsigned long);
387 	va_end(ap);
388 	if (openfirmware(&args) == -1)
389 		return -1;
390 	if (args.args_n_results[nargs])
391 		return -1;
392 	return args.args_n_results[nargs + 1];
393 }
394 
395 int
396 OF_open(dname)
397 	char *dname;
398 {
399 	struct {
400 		cell_t name;
401 		cell_t nargs;
402 		cell_t nreturns;
403 		cell_t dname;
404 		cell_t handle;
405 	} args;
406 	int l;
407 
408 	if ((l = strlen(dname)) >= NBPG)
409 		return -1;
410 	args.name = ADR2CELL("open");
411 	args.nargs = 1;
412 	args.nreturns = 1;
413 	args.dname = ADR2CELL(dname);
414 	if (openfirmware(&args) == -1)
415 		return -1;
416 	return args.handle;
417 }
418 
419 void
420 OF_close(handle)
421 	int handle;
422 {
423 	struct {
424 		cell_t name;
425 		cell_t nargs;
426 		cell_t nreturns;
427 		cell_t handle;
428 	} args;
429 
430 	args.name = ADR2CELL("close");
431 	args.nargs = 1;
432 	args.nreturns = 0;
433 	args.handle = HDL2CELL(handle);
434 	openfirmware(&args);
435 }
436 
437 int
438 OF_test(service)
439 	char *service;
440 {
441 	struct {
442 		cell_t name;
443 		cell_t nargs;
444 		cell_t nreturns;
445 		cell_t service;
446 		cell_t status;
447 	} args;
448 
449 	args.name = ADR2CELL("test");
450 	args.nargs = 1;
451 	args.nreturns = 1;
452 	args.service = ADR2CELL(service);
453 	if (openfirmware(&args) == -1)
454 		return -1;
455 	return args.status;
456 }
457 
458 int
459 OF_test_method(service, method)
460 	int service;
461 	char *method;
462 {
463 	struct {
464 		cell_t name;
465 		cell_t nargs;
466 		cell_t nreturns;
467 		cell_t service;
468 		cell_t method;
469 		cell_t status;
470 	} args;
471 
472 	args.name = ADR2CELL("test-method");
473 	args.nargs = 2;
474 	args.nreturns = 1;
475 	args.service = HDL2CELL(service);
476 	args.method = ADR2CELL(method);
477 	if (openfirmware(&args) == -1)
478 		return -1;
479 	return args.status;
480 }
481 
482 
483 /*
484  * This assumes that character devices don't read in multiples of NBPG.
485  */
486 int
487 OF_read(handle, addr, len)
488 	int handle;
489 	void *addr;
490 	int len;
491 {
492 	struct {
493 		cell_t name;
494 		cell_t nargs;
495 		cell_t nreturns;
496 		cell_t ihandle;
497 		cell_t addr;
498 		cell_t len;
499 		cell_t actual;
500 	} args;
501 	int l, act = 0;
502 
503 	args.name = ADR2CELL("read");
504 	args.nargs = 3;
505 	args.nreturns = 1;
506 	args.ihandle = HDL2CELL(handle);
507 	args.addr = ADR2CELL(addr);
508 	for (; len > 0; len -= l) {
509 		l = min(NBPG, len);
510 		args.len = l;
511 		if (openfirmware(&args) == -1)
512 			return -1;
513 		if (args.actual > 0) {
514 			act += args.actual;
515 		}
516 		if (args.actual < l) {
517 			if (act)
518 				return act;
519 			else
520 				return args.actual;
521 		}
522 	}
523 	return act;
524 }
525 
526 void prom_printf(const char *fmt, ...);	/* XXX for below */
527 
528 int
529 OF_write(handle, addr, len)
530 	int handle;
531 	void *addr;
532 	int len;
533 {
534 	struct {
535 		cell_t name;
536 		cell_t nargs;
537 		cell_t nreturns;
538 		cell_t ihandle;
539 		cell_t addr;
540 		cell_t len;
541 		cell_t actual;
542 	} args;
543 	int l, act = 0;
544 
545 	if (len > 1024) {
546 		panic("OF_write(len=%d)", len);
547 	}
548 	args.name = ADR2CELL("write");
549 	args.nargs = 3;
550 	args.nreturns = 1;
551 	args.ihandle = HDL2CELL(handle);
552 	args.addr = ADR2CELL(addr);
553 	for (; len > 0; len -= l) {
554 		l = min(NBPG, len);
555 		args.len = l;
556 		if (openfirmware(&args) == -1)
557 			return -1;
558 		l = args.actual;
559 		act += l;
560 	}
561 	return act;
562 }
563 
564 
565 int
566 OF_seek(handle, pos)
567 	int handle;
568 	u_quad_t pos;
569 {
570 	struct {
571 		cell_t name;
572 		cell_t nargs;
573 		cell_t nreturns;
574 		cell_t handle;
575 		cell_t poshi;
576 		cell_t poslo;
577 		cell_t status;
578 	} args;
579 
580 	args.name = ADR2CELL("seek");
581 	args.nargs = 3;
582 	args.nreturns = 1;
583 	args.handle = HDL2CELL(handle);
584 	args.poshi = HDQ2CELL_HI(pos);
585 	args.poslo = HDQ2CELL_LO(pos);
586 	if (openfirmware(&args) == -1)
587 		return -1;
588 	return args.status;
589 }
590 
591 void
592 OF_boot(bootspec)
593 	char *bootspec;
594 {
595 	struct {
596 		cell_t name;
597 		cell_t nargs;
598 		cell_t nreturns;
599 		cell_t bootspec;
600 	} args;
601 	int l;
602 
603 	if ((l = strlen(bootspec)) >= NBPG)
604 		panic("OF_boot");
605 	args.name = ADR2CELL("boot");
606 	args.nargs = 1;
607 	args.nreturns = 0;
608 	args.bootspec = ADR2CELL(bootspec);
609 	openfirmware(&args);
610 	panic("OF_boot failed");
611 }
612 
613 void
614 OF_enter(void)
615 {
616 	struct {
617 		cell_t name;
618 		cell_t nargs;
619 		cell_t nreturns;
620 	} args;
621 
622 	args.name = ADR2CELL("enter");
623 	args.nargs = 0;
624 	args.nreturns = 0;
625 	openfirmware(&args);
626 }
627 
628 void
629 OF_exit(void)
630 {
631 	struct {
632 		cell_t name;
633 		cell_t nargs;
634 		cell_t nreturns;
635 	} args;
636 
637 	args.name = ADR2CELL("exit");
638 	args.nargs = 0;
639 	args.nreturns = 0;
640 	openfirmware(&args);
641 	panic("OF_exit failed");
642 }
643 
644 void
645 OF_poweroff(void)
646 {
647 	struct {
648 		cell_t name;
649 		cell_t nargs;
650 		cell_t nreturns;
651 	} args;
652 
653 	args.name = ADR2CELL("SUNW,power-off");
654 	args.nargs = 0;
655 	args.nreturns = 0;
656 	openfirmware(&args);
657 }
658 
659 void
660 (*OF_set_callback(newfunc))(void *)
661 	void (*newfunc)(void *);
662 {
663 	struct {
664 		cell_t name;
665 		cell_t nargs;
666 		cell_t nreturns;
667 		cell_t newfunc;
668 		cell_t oldfunc;
669 	} args;
670 
671 	args.name = ADR2CELL("set-callback");
672 	args.nargs = 1;
673 	args.nreturns = 1;
674 	args.newfunc = ADR2CELL(newfunc);
675 	if (openfirmware(&args) == -1)
676 		return (void *)(long)-1;
677 	return (void *)(long)args.oldfunc;
678 }
679 
680 void
681 OF_set_symbol_lookup(s2v, v2s)
682 	void (*s2v)(void *);
683 	void (*v2s)(void *);
684 {
685 	struct {
686 		cell_t name;
687 		cell_t nargs;
688 		cell_t nreturns;
689 		cell_t sym2val;
690 		cell_t val2sym;
691 	} args;
692 
693 	args.name = ADR2CELL("set-symbol-lookup");
694 	args.nargs = 2;
695 	args.nreturns = 0;
696 	args.sym2val = ADR2CELL(s2v);
697 	args.val2sym = ADR2CELL(v2s);
698 
699 	(void)openfirmware(&args);
700 }
701 
702 int
703 OF_interpret(char *cmd, int nreturns, ...)
704 {
705 	va_list ap;
706 	struct {
707 		cell_t name;
708 		cell_t nargs;
709 		cell_t nreturns;
710 		cell_t slot[16];
711 	} args;
712 	cell_t status;
713 	int i = 0;
714 
715 	args.name = ADR2CELL("interpret");
716 	args.nargs = 1;
717 	args.nreturns = ++nreturns;
718 	args.slot[i++] = ADR2CELL(cmd);
719 	va_start(ap, nreturns);
720 	while (i < 1)
721 		args.slot[i++] = va_arg(ap, cell_t);
722 	if (openfirmware(&args) == -1) {
723 		va_end(ap);
724 		return (-1);
725 	}
726 	status = args.slot[i++];
727 	while (i < 1 + nreturns)
728 		*va_arg(ap, cell_t *) = args.slot[i++];
729 	va_end(ap);
730 	return (status);
731 }
732 
733 int
734 OF_milliseconds(void)
735 {
736 	struct {
737 		cell_t name;
738 		cell_t nargs;
739 		cell_t nreturns;
740 		cell_t nticks;
741 	} args;
742 
743 	args.name = ADR2CELL("milliseconds");
744 	args.nargs = 0;
745 	args.nreturns = 1;
746 	if (openfirmware(&args) == -1)
747 		return -1;
748 	return (args.nticks);
749 }
750 
751 #ifdef DDB
752 #include <machine/db_machdep.h>
753 #include <ddb/db_sym.h>
754 #include <ddb/db_extern.h>
755 
756 int obp_symbol_debug = 0;
757 
758 void OF_sym2val(cells)
759 	void *cells;
760 {
761 	struct args {
762 		cell_t service;
763 		cell_t nargs;
764 		cell_t nreturns;
765 		cell_t symbol;
766 		cell_t result;
767 		cell_t value;
768 	} *args = (struct args*)cells;
769 	char *symbol;
770 	db_expr_t value;
771 
772 	/* Set data segment pointer */
773 	__asm volatile("clr %%g4" : :);
774 
775 	/* No args?  Nothing to do. */
776 	if (!args->nargs ||
777 	    !args->nreturns) return;
778 
779 	/* Do we have a place for the value? */
780 	if (args->nreturns != 2) {
781 		args->nreturns = 1;
782 		args->result = -1;
783 		return;
784 	}
785 	symbol = (char *)(u_long)args->symbol;
786 	if (obp_symbol_debug)
787 		prom_printf("looking up symbol %s\r\n", symbol);
788 	args->result = (db_value_of_name(symbol, &value) == TRUE) ? 0 : -1;
789 	if (obp_symbol_debug)
790 		prom_printf("%s is %lx\r\n", symbol, value);
791 	args->value = ADR2CELL(value);
792 }
793 
794 void OF_val2sym(cells)
795 	void *cells;
796 {
797 	struct args {
798 		cell_t service;
799 		cell_t nargs;
800 		cell_t nreturns;
801 		cell_t value;
802 		cell_t offset;
803 		cell_t symbol;
804 	} *args = (struct args*)cells;
805 	db_sym_t symbol;
806 	db_expr_t value;
807 	db_expr_t offset;
808 
809 	/* Set data segment pointer */
810 	__asm volatile("clr %%g4" : :);
811 
812 	if (obp_symbol_debug)
813 		prom_printf("OF_val2sym: nargs %lx nreturns %lx\r\n",
814 			args->nargs, args->nreturns);
815 	/* No args?  Nothing to do. */
816 	if (!args->nargs ||
817 	    !args->nreturns) return;
818 
819 	/* Do we have a place for the value? */
820 	if (args->nreturns != 2) {
821 		args->nreturns = 1;
822 		args->offset = -1;
823 		return;
824 	}
825 
826 	value = args->value;
827 	if (obp_symbol_debug)
828 		prom_printf("looking up value %ld\r\n", value);
829 	symbol = db_search_symbol(value, 0, &offset);
830 	if (symbol == NULL) {
831 		if (obp_symbol_debug)
832 			prom_printf("OF_val2sym: not found\r\n");
833 		args->nreturns = 1;
834 		args->offset = -1;
835 		return;
836 	}
837 	args->offset = offset;
838 	args->symbol = ADR2CELL(symbol);
839 
840 }
841 #endif
842 
843 int
844 OF_is_compatible(int handle, const char *name)
845 {
846 	char compat[256];
847 	char *str;
848 	int len;
849 
850 	len = OF_getprop(handle, "compatible", &compat, sizeof(compat));
851 	if (len <= 0)
852 		return 0;
853 
854 	/* Guarantee that the buffer is null-terminated. */
855 	compat[sizeof(compat) - 1] = 0;
856 
857 	str = compat;
858 	while (len > 0) {
859 		if (strcmp(str, name) == 0)
860 			return 1;
861 		len -= strlen(str) + 1;
862 		str += strlen(str) + 1;
863 	}
864 
865 	return 0;
866 }
867