1/*-
2 * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/types.h>
27#include <sys/ioctl.h>
28
29#include <dev/ofw/openfirmio.h>
30
31#include <err.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sysexits.h>
38#include <unistd.h>
39
40#include "pathnames.h"
41#include "ofw_util.h"
42
43#define	OFW_IOCTL(fd, cmd, val)	do {					\
44	if (ioctl(fd, cmd, val) == -1)					\
45		err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed");	\
46} while (0)
47
48int
49ofw_open(int mode)
50{
51	int fd;
52
53	if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1)
54		err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM);
55	return (fd);
56}
57
58void
59ofw_close(int fd)
60{
61
62	close(fd);
63}
64
65phandle_t
66ofw_root(int fd)
67{
68
69	return (ofw_peer(fd, 0));
70}
71
72phandle_t
73ofw_optnode(int fd)
74{
75	phandle_t rv;
76
77	OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv);
78	return (rv);
79}
80
81phandle_t
82ofw_peer(int fd, phandle_t node)
83{
84	phandle_t rv;
85
86	rv = node;
87	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
88	return (rv);
89}
90
91phandle_t
92ofw_child(int fd, phandle_t node)
93{
94	phandle_t rv;
95
96	rv = node;
97	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
98	return (rv);
99}
100
101phandle_t
102ofw_finddevice(int fd, const char *name)
103{
104	struct ofiocdesc d;
105
106	d.of_nodeid = 0;
107	d.of_namelen = strlen(name);
108	d.of_name = name;
109	d.of_buflen = 0;
110	d.of_buf = NULL;
111	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
112		if (errno == ENOENT)
113			err(EX_UNAVAILABLE, "Node '%s' not found", name);
114		else
115			err(EX_IOERR,
116			    "ioctl(..., OFIOCFINDDEVICE, ...) failed");
117	}
118	return (d.of_nodeid);
119}
120
121int
122ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
123{
124
125	return (ofw_nextprop(fd, node, NULL, buf, buflen));
126}
127
128int
129ofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen)
130{
131	struct ofiocdesc d;
132
133	d.of_nodeid = node;
134	d.of_namelen = prev != NULL ? strlen(prev) : 0;
135	d.of_name = prev;
136	d.of_buflen = buflen;
137	d.of_buf = buf;
138	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
139		if (errno == ENOENT)
140			return (0);
141		else
142			err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed");
143	}
144	return (d.of_buflen);
145}
146
147static void *
148ofw_malloc(int size)
149{
150	void *p;
151
152	if ((p = malloc(size)) == NULL)
153		err(EX_OSERR, "malloc() failed");
154	return (p);
155}
156
157int
158ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
159{
160	struct ofiocdesc d;
161
162	d.of_nodeid = node;
163	d.of_namelen = strlen(name);
164	d.of_name = name;
165	d.of_buflen = buflen;
166	d.of_buf = buf;
167	OFW_IOCTL(fd, OFIOCGET, &d);
168	return (d.of_buflen);
169}
170
171int
172ofw_setprop(int fd, phandle_t node, const char *name, const void *buf,
173    int buflen)
174{
175	struct ofiocdesc d;
176
177	d.of_nodeid = node;
178	d.of_namelen = strlen(name);
179	d.of_name = name;
180	d.of_buflen = buflen;
181	d.of_buf = ofw_malloc(buflen);
182	memcpy(d.of_buf, buf, buflen);
183	OFW_IOCTL(fd, OFIOCSET, &d);
184	free(d.of_buf);
185	return (d.of_buflen);
186}
187
188int
189ofw_getproplen(int fd, phandle_t node, const char *name)
190{
191	struct ofiocdesc d;
192
193	d.of_nodeid = node;
194	d.of_namelen = strlen(name);
195	d.of_name = name;
196	OFW_IOCTL(fd, OFIOCGETPROPLEN, &d);
197	return (d.of_buflen);
198}
199
200int
201ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf,
202    int *buflen, int reserve)
203{
204	struct ofiocdesc d;
205	int len, rv;
206
207	do {
208		len = ofw_getproplen(fd, node, name);
209		if (len < 0)
210			return (len);
211		if (*buflen < len + reserve) {
212			if (*buf != NULL)
213				free(*buf);
214			*buflen = len + reserve + OFIOCMAXVALUE;
215			*buf = ofw_malloc(*buflen);
216		}
217		d.of_nodeid = node;
218		d.of_namelen = strlen(name);
219		d.of_name = name;
220		d.of_buflen = *buflen - reserve;
221		d.of_buf = *buf;
222		rv = ioctl(fd, OFIOCGET, &d);
223	} while (rv == -1 && errno == ENOMEM);
224	if (rv == -1)
225		err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed");
226	return (d.of_buflen);
227}
228