openfirmio.c revision 1.2 1 /* $NetBSD: openfirmio.c,v 1.2 2000/11/14 21:10:05 matt Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * @(#)openfirm.c 8.1 (Berkeley) 6/11/93
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/errno.h>
50 #include <sys/fcntl.h>
51 #include <sys/ioctl.h>
52 #include <sys/malloc.h>
53 #include <sys/conf.h>
54 #include <sys/device.h>
55
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/openfirmio.h>
58
59 static int lastnode; /* speed hack */
60
61 static int openfirmcheckid (int, int);
62 static int openfirmgetstr (int, char *, char **);
63
64 void openfirmattach (int);
65
66 void
67 openfirmattach(int num)
68 {
69 /* nothing */
70 }
71
72 int
73 openfirmopen(dev_t dev, int flags, int mode, struct proc *p)
74 {
75 return (0);
76 }
77
78 int
79 openfirmclose(dev_t dev, int flags, int mode, struct proc *p)
80 {
81
82 return (0);
83 }
84
85 /*
86 * Verify target ID is valid (exists in the OPENPROM tree), as
87 * listed from node ID sid forward.
88 */
89 static int
90 openfirmcheckid(int sid, int tid)
91 {
92
93 for (; sid != 0; sid = OF_peer(sid))
94 if (sid == tid || openfirmcheckid(OF_child(sid), tid))
95 return (1);
96
97 return (0);
98 }
99
100 static int
101 openfirmgetstr(int len, char *user, char **cpp)
102 {
103 int error;
104 char *cp;
105
106 /* Reject obvious bogus requests */
107 if ((u_int)len > (8 * 1024) - 1)
108 return (ENAMETOOLONG);
109
110 *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
111 error = copyin(user, cp, len);
112 cp[len] = '\0';
113 return (error);
114 }
115
116 int
117 openfirmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
118 {
119 struct ofiocdesc *of;
120 int node, len, ok, error, s;
121 char *name, *value;
122
123 if (cmd == OFIOCGETOPTNODE) {
124 s = splhigh();
125 *(int *) data = OF_finddevice("/options");
126 splx(s);
127 return (0);
128 }
129
130 /* Verify node id */
131 of = (struct ofiocdesc *)data;
132 node = of->of_nodeid;
133 if (node != 0 && node != lastnode) {
134 /* Not an easy one, must search for it */
135 s = splhigh();
136 ok = openfirmcheckid(OF_peer(0), node);
137 splx(s);
138 if (!ok)
139 return (EINVAL);
140 lastnode = node;
141 }
142
143 name = value = NULL;
144 error = 0;
145 switch (cmd) {
146
147 case OFIOCGET:
148 if ((flags & FREAD) == 0)
149 return (EBADF);
150 if (node == 0)
151 return (EINVAL);
152 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
153 if (error)
154 break;
155 s = splhigh();
156 len = OF_getproplen(node, name);
157 splx(s);
158 if (len > of->of_buflen) {
159 error = ENOMEM;
160 break;
161 }
162 of->of_buflen = len;
163 /* -1 means no entry; 0 means no value */
164 if (len <= 0)
165 break;
166 value = malloc(len, M_TEMP, M_WAITOK);
167 if (value == NULL) {
168 error = ENOMEM;
169 break;
170 }
171 s = splhigh();
172 len = OF_getprop(node, name, (void *)value, len);
173 splx(s);
174 error = copyout(value, of->of_buf, len);
175 break;
176
177 #if 0
178 case OFIOCSET:
179 if ((flags & FWRITE) == 0)
180 return (EBADF);
181 if (node == 0)
182 return (EINVAL);
183 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
184 if (error)
185 break;
186 error = openfirmgetstr(of->of_buflen, of->of_buf, &value);
187 if (error)
188 break;
189 s = splhigh();
190 len = OF_setprop(node, name, value, of->of_buflen + 1);
191 splx(s);
192 if (len != of->of_buflen)
193 error = EINVAL;
194 break;
195 #endif
196
197 case OFIOCNEXTPROP: {
198 char newname[32];
199 if ((flags & FREAD) == 0)
200 return (EBADF);
201 if (node == 0)
202 return (EINVAL);
203 if (of->of_namelen != 0) {
204 error = openfirmgetstr(of->of_namelen, of->of_name,
205 &name);
206 if (error)
207 break;
208 }
209 s = splhigh();
210 ok = OF_nextprop(node, name, newname);
211 splx(s);
212 if (ok == 0) {
213 error = ENOENT;
214 break;
215 }
216 if (ok == -1) {
217 error = EINVAL;
218 break;
219 }
220 len = strlen(newname);
221 if (len > of->of_buflen)
222 len = of->of_buflen;
223 else
224 of->of_buflen = len;
225 error = copyout(newname, of->of_buf, len);
226 break;
227 }
228
229 case OFIOCGETNEXT:
230 if ((flags & FREAD) == 0)
231 return (EBADF);
232 s = splhigh();
233 node = OF_peer(node);
234 splx(s);
235 *(int *)data = lastnode = node;
236 break;
237
238 case OFIOCGETCHILD:
239 if ((flags & FREAD) == 0)
240 return (EBADF);
241 if (node == 0)
242 return (EINVAL);
243 s = splhigh();
244 node = OF_child(node);
245 splx(s);
246 *(int *)data = lastnode = node;
247 break;
248
249 case OFIOCFINDDEVICE:
250 if ((flags & FREAD) == 0)
251 return (EBADF);
252 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
253 if (error)
254 break;
255 node = OF_finddevice(name);
256 if (node == 0 || node == -1) {
257 error = ENOENT;
258 break;
259 }
260 of->of_nodeid = lastnode = node;
261 break;
262
263 default:
264 return (ENOTTY);
265 }
266
267 if (name)
268 free(name, M_TEMP);
269 if (value)
270 free(value, M_TEMP);
271
272 return (error);
273 }
274