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