1105401Stmm/*-
2105401Stmm * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
3105401Stmm * All rights reserved.
4105401Stmm *
5105401Stmm * Redistribution and use in source and binary forms, with or without
6105401Stmm * modification, are permitted provided that the following conditions
7105401Stmm * are met:
8105401Stmm * 1. Redistributions of source code must retain the above copyright
9105401Stmm *    notice, this list of conditions and the following disclaimer.
10105401Stmm * 2. Redistributions in binary form must reproduce the above copyright
11105401Stmm *    notice, this list of conditions and the following disclaimer in the
12105401Stmm *    documentation and/or other materials provided with the distribution.
13105401Stmm *
14105401Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15105401Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16105401Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17105401Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18105401Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19105401Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20105401Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21105401Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22105401Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23105401Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24105401Stmm */
25105401Stmm
26105401Stmm#include <sys/cdefs.h>
27105401Stmm__FBSDID("$FreeBSD$");
28105401Stmm
29105401Stmm#include <sys/types.h>
30105401Stmm#include <sys/ioctl.h>
31105401Stmm
32105401Stmm#include <dev/ofw/openfirmio.h>
33105401Stmm
34105401Stmm#include <err.h>
35105401Stmm#include <errno.h>
36105401Stmm#include <fcntl.h>
37105401Stmm#include <stdio.h>
38116212Stmm#include <stdlib.h>
39105401Stmm#include <string.h>
40129589Smarius#include <sysexits.h>
41105401Stmm#include <unistd.h>
42105401Stmm
43105401Stmm#include "pathnames.h"
44105401Stmm#include "ofw_util.h"
45105401Stmm
46105401Stmm#define	OFW_IOCTL(fd, cmd, val)	do {					\
47105401Stmm	if (ioctl(fd, cmd, val) == -1)					\
48129589Smarius		err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed");	\
49105401Stmm} while (0)
50105401Stmm
51105401Stmmint
52129589Smariusofw_open(int mode)
53105401Stmm{
54105401Stmm	int fd;
55105401Stmm
56129589Smarius	if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1)
57129589Smarius		err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM);
58105401Stmm	return (fd);
59105401Stmm}
60105401Stmm
61105401Stmmvoid
62105401Stmmofw_close(int fd)
63105401Stmm{
64105401Stmm
65105401Stmm	close(fd);
66105401Stmm}
67105401Stmm
68105401Stmmphandle_t
69105401Stmmofw_root(int fd)
70105401Stmm{
71105401Stmm
72105401Stmm	return (ofw_peer(fd, 0));
73105401Stmm}
74105401Stmm
75105401Stmmphandle_t
76129589Smariusofw_optnode(int fd)
77129589Smarius{
78129589Smarius	phandle_t rv;
79129589Smarius
80129589Smarius	OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv);
81129589Smarius	return (rv);
82129589Smarius}
83129589Smarius
84129589Smariusphandle_t
85105401Stmmofw_peer(int fd, phandle_t node)
86105401Stmm{
87105401Stmm	phandle_t rv;
88105401Stmm
89105401Stmm	rv = node;
90105401Stmm	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
91105401Stmm	return (rv);
92105401Stmm}
93105401Stmm
94105401Stmmphandle_t
95105401Stmmofw_child(int fd, phandle_t node)
96105401Stmm{
97105401Stmm	phandle_t rv;
98105401Stmm
99105401Stmm	rv = node;
100105401Stmm	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
101105401Stmm	return (rv);
102105401Stmm}
103105401Stmm
104105401Stmmphandle_t
105129589Smariusofw_finddevice(int fd, const char *name)
106105401Stmm{
107105401Stmm	struct ofiocdesc d;
108105401Stmm
109105401Stmm	d.of_nodeid = 0;
110105401Stmm	d.of_namelen = strlen(name);
111105401Stmm	d.of_name = name;
112105401Stmm	d.of_buflen = 0;
113105401Stmm	d.of_buf = NULL;
114105401Stmm	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
115105401Stmm		if (errno == ENOENT)
116129589Smarius			err(EX_UNAVAILABLE, "Node '%s' not found", name);
117105401Stmm		else
118129589Smarius			err(EX_IOERR,
119129589Smarius			    "ioctl(..., OFIOCFINDDEVICE, ...) failed");
120105401Stmm	}
121105401Stmm	return (d.of_nodeid);
122105401Stmm}
123105401Stmm
124105401Stmmint
125105401Stmmofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
126105401Stmm{
127105401Stmm
128105401Stmm	return (ofw_nextprop(fd, node, NULL, buf, buflen));
129105401Stmm}
130105401Stmm
131105401Stmmint
132129589Smariusofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen)
133105401Stmm{
134105401Stmm	struct ofiocdesc d;
135105401Stmm
136105401Stmm	d.of_nodeid = node;
137105401Stmm	d.of_namelen = prev != NULL ? strlen(prev) : 0;
138105401Stmm	d.of_name = prev;
139105401Stmm	d.of_buflen = buflen;
140105401Stmm	d.of_buf = buf;
141105401Stmm	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
142105401Stmm		if (errno == ENOENT)
143105401Stmm			return (0);
144105401Stmm		else
145129589Smarius			err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed");
146105401Stmm	}
147105401Stmm	return (d.of_buflen);
148105401Stmm}
149105401Stmm
150116212Stmmstatic void *
151116212Stmmofw_malloc(int size)
152116212Stmm{
153116212Stmm	void *p;
154116212Stmm
155116212Stmm	if ((p = malloc(size)) == NULL)
156129589Smarius		err(EX_OSERR, "malloc() failed");
157116212Stmm	return (p);
158116212Stmm}
159116212Stmm
160105401Stmmint
161105401Stmmofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
162105401Stmm{
163105401Stmm	struct ofiocdesc d;
164105401Stmm
165105401Stmm	d.of_nodeid = node;
166105401Stmm	d.of_namelen = strlen(name);
167105401Stmm	d.of_name = name;
168105401Stmm	d.of_buflen = buflen;
169105401Stmm	d.of_buf = buf;
170105401Stmm	OFW_IOCTL(fd, OFIOCGET, &d);
171105401Stmm	return (d.of_buflen);
172105401Stmm}
173105401Stmm
174116212Stmmint
175129589Smariusofw_setprop(int fd, phandle_t node, const char *name, const void *buf,
176129589Smarius    int buflen)
177129589Smarius{
178129589Smarius	struct ofiocdesc d;
179129589Smarius
180129589Smarius	d.of_nodeid = node;
181129589Smarius	d.of_namelen = strlen(name);
182129589Smarius	d.of_name = name;
183129589Smarius	d.of_buflen = buflen;
184129589Smarius	d.of_buf = ofw_malloc(buflen);
185129589Smarius	memcpy(d.of_buf, buf, buflen);
186129589Smarius	OFW_IOCTL(fd, OFIOCSET, &d);
187129589Smarius	free(d.of_buf);
188129589Smarius	return (d.of_buflen);
189129589Smarius}
190129589Smarius
191129589Smariusint
192116212Stmmofw_getproplen(int fd, phandle_t node, const char *name)
193116212Stmm{
194116212Stmm	struct ofiocdesc d;
195116212Stmm
196116212Stmm	d.of_nodeid = node;
197116212Stmm	d.of_namelen = strlen(name);
198116212Stmm	d.of_name = name;
199116212Stmm	OFW_IOCTL(fd, OFIOCGETPROPLEN, &d);
200116212Stmm	return (d.of_buflen);
201116212Stmm}
202116212Stmm
203116212Stmmint
204116212Stmmofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf,
205116212Stmm    int *buflen, int reserve)
206116212Stmm{
207116212Stmm	struct ofiocdesc d;
208116212Stmm	int len, rv;
209116212Stmm
210116212Stmm	do {
211116212Stmm		len = ofw_getproplen(fd, node, name);
212116212Stmm		if (len < 0)
213116212Stmm			return (len);
214116212Stmm		if (*buflen < len + reserve) {
215116212Stmm			if (*buf != NULL)
216116212Stmm				free(*buf);
217129589Smarius			*buflen = len + reserve + OFIOCMAXVALUE;
218116212Stmm			*buf = ofw_malloc(*buflen);
219116212Stmm		}
220116212Stmm		d.of_nodeid = node;
221116212Stmm		d.of_namelen = strlen(name);
222116212Stmm		d.of_name = name;
223116212Stmm		d.of_buflen = *buflen - reserve;
224116212Stmm		d.of_buf = *buf;
225116212Stmm		rv = ioctl(fd, OFIOCGET, &d);
226116212Stmm	} while (rv == -1 && errno == ENOMEM);
227116212Stmm	if (rv == -1)
228129589Smarius		err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed");
229116212Stmm	return (d.of_buflen);
230116212Stmm}
231