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/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include <sys/types.h>
30#include <sys/ioctl.h>
31
32#include <dev/ofw/openfirmio.h>
33
34#include <err.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sysexits.h>
41#include <unistd.h>
42
43#include "pathnames.h"
44#include "ofw_util.h"
45
46#define	OFW_IOCTL(fd, cmd, val)	do {					\
47	if (ioctl(fd, cmd, val) == -1)					\
48		err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed");	\
49} while (0)
50
51int
52ofw_open(int mode)
53{
54	int fd;
55
56	if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1)
57		err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM);
58	return (fd);
59}
60
61void
62ofw_close(int fd)
63{
64
65	close(fd);
66}
67
68phandle_t
69ofw_root(int fd)
70{
71
72	return (ofw_peer(fd, 0));
73}
74
75phandle_t
76ofw_optnode(int fd)
77{
78	phandle_t rv;
79
80	OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv);
81	return (rv);
82}
83
84phandle_t
85ofw_peer(int fd, phandle_t node)
86{
87	phandle_t rv;
88
89	rv = node;
90	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
91	return (rv);
92}
93
94phandle_t
95ofw_child(int fd, phandle_t node)
96{
97	phandle_t rv;
98
99	rv = node;
100	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
101	return (rv);
102}
103
104phandle_t
105ofw_finddevice(int fd, const char *name)
106{
107	struct ofiocdesc d;
108
109	d.of_nodeid = 0;
110	d.of_namelen = strlen(name);
111	d.of_name = name;
112	d.of_buflen = 0;
113	d.of_buf = NULL;
114	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
115		if (errno == ENOENT)
116			err(EX_UNAVAILABLE, "Node '%s' not found", name);
117		else
118			err(EX_IOERR,
119			    "ioctl(..., OFIOCFINDDEVICE, ...) failed");
120	}
121	return (d.of_nodeid);
122}
123
124int
125ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
126{
127
128	return (ofw_nextprop(fd, node, NULL, buf, buflen));
129}
130
131int
132ofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen)
133{
134	struct ofiocdesc d;
135
136	d.of_nodeid = node;
137	d.of_namelen = prev != NULL ? strlen(prev) : 0;
138	d.of_name = prev;
139	d.of_buflen = buflen;
140	d.of_buf = buf;
141	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
142		if (errno == ENOENT)
143			return (0);
144		else
145			err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed");
146	}
147	return (d.of_buflen);
148}
149
150static void *
151ofw_malloc(int size)
152{
153	void *p;
154
155	if ((p = malloc(size)) == NULL)
156		err(EX_OSERR, "malloc() failed");
157	return (p);
158}
159
160int
161ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
162{
163	struct ofiocdesc d;
164
165	d.of_nodeid = node;
166	d.of_namelen = strlen(name);
167	d.of_name = name;
168	d.of_buflen = buflen;
169	d.of_buf = buf;
170	OFW_IOCTL(fd, OFIOCGET, &d);
171	return (d.of_buflen);
172}
173
174int
175ofw_setprop(int fd, phandle_t node, const char *name, const void *buf,
176    int buflen)
177{
178	struct ofiocdesc d;
179
180	d.of_nodeid = node;
181	d.of_namelen = strlen(name);
182	d.of_name = name;
183	d.of_buflen = buflen;
184	d.of_buf = ofw_malloc(buflen);
185	memcpy(d.of_buf, buf, buflen);
186	OFW_IOCTL(fd, OFIOCSET, &d);
187	free(d.of_buf);
188	return (d.of_buflen);
189}
190
191int
192ofw_getproplen(int fd, phandle_t node, const char *name)
193{
194	struct ofiocdesc d;
195
196	d.of_nodeid = node;
197	d.of_namelen = strlen(name);
198	d.of_name = name;
199	OFW_IOCTL(fd, OFIOCGETPROPLEN, &d);
200	return (d.of_buflen);
201}
202
203int
204ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf,
205    int *buflen, int reserve)
206{
207	struct ofiocdesc d;
208	int len, rv;
209
210	do {
211		len = ofw_getproplen(fd, node, name);
212		if (len < 0)
213			return (len);
214		if (*buflen < len + reserve) {
215			if (*buf != NULL)
216				free(*buf);
217			*buflen = len + reserve + OFIOCMAXVALUE;
218			*buf = ofw_malloc(*buflen);
219		}
220		d.of_nodeid = node;
221		d.of_namelen = strlen(name);
222		d.of_name = name;
223		d.of_buflen = *buflen - reserve;
224		d.of_buf = *buf;
225		rv = ioctl(fd, OFIOCGET, &d);
226	} while (rv == -1 && errno == ENOMEM);
227	if (rv == -1)
228		err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed");
229	return (d.of_buflen);
230}
231