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
48 int
ofw_open(int mode)49 ofw_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
58 void
ofw_close(int fd)59 ofw_close(int fd)
60 {
61
62 close(fd);
63 }
64
65 phandle_t
ofw_root(int fd)66 ofw_root(int fd)
67 {
68
69 return (ofw_peer(fd, 0));
70 }
71
72 phandle_t
ofw_optnode(int fd)73 ofw_optnode(int fd)
74 {
75 phandle_t rv;
76
77 OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv);
78 return (rv);
79 }
80
81 phandle_t
ofw_peer(int fd,phandle_t node)82 ofw_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
91 phandle_t
ofw_child(int fd,phandle_t node)92 ofw_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
101 phandle_t
ofw_finddevice(int fd,const char * name)102 ofw_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
121 int
ofw_firstprop(int fd,phandle_t node,char * buf,int buflen)122 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
123 {
124
125 return (ofw_nextprop(fd, node, NULL, buf, buflen));
126 }
127
128 int
ofw_nextprop(int fd,phandle_t node,const char * prev,char * buf,int buflen)129 ofw_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
147 static void *
ofw_malloc(int size)148 ofw_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
157 int
ofw_getprop(int fd,phandle_t node,const char * name,void * buf,int buflen)158 ofw_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
171 int
ofw_setprop(int fd,phandle_t node,const char * name,const void * buf,int buflen)172 ofw_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
188 int
ofw_getproplen(int fd,phandle_t node,const char * name)189 ofw_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
200 int
ofw_getprop_alloc(int fd,phandle_t node,const char * name,void ** buf,int * buflen,int reserve)201 ofw_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