1 /* $NetBSD: openfirmio.c,v 1.8 2003/08/07 16:31:10 agc 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. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)openfirm.c 8.1 (Berkeley) 6/11/93
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: openfirmio.c,v 1.8 2003/08/07 16:31:10 agc Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/errno.h>
49 #include <sys/fcntl.h>
50 #include <sys/ioctl.h>
51 #include <sys/malloc.h>
52 #include <sys/conf.h>
53 #include <sys/device.h>
54 #include <sys/event.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 dev_type_ioctl(openfirmioctl);
67
68 const struct cdevsw openfirm_cdevsw = {
69 nullopen, nullclose, noread, nowrite, openfirmioctl,
70 nostop, notty, nopoll, nommap, nokqfilter,
71 };
72
73 void
74 openfirmattach(int num)
75 {
76 /* nothing */
77 }
78
79 /*
80 * Verify target ID is valid (exists in the OPENPROM tree), as
81 * listed from node ID sid forward.
82 */
83 static int
84 openfirmcheckid(int sid, int tid)
85 {
86
87 for (; sid != 0; sid = OF_peer(sid))
88 if (sid == tid || openfirmcheckid(OF_child(sid), tid))
89 return (1);
90
91 return (0);
92 }
93
94 static int
95 openfirmgetstr(int len, char *user, char **cpp)
96 {
97 int error;
98 char *cp;
99
100 /* Reject obvious bogus requests */
101 if ((u_int)len > (8 * 1024) - 1)
102 return (ENAMETOOLONG);
103
104 *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
105 error = copyin(user, cp, len);
106 cp[len] = '\0';
107 return (error);
108 }
109
110 int
111 openfirmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
112 {
113 struct ofiocdesc *of;
114 int node, len, ok, error, s;
115 char *name, *value;
116
117 if (cmd == OFIOCGETOPTNODE) {
118 s = splhigh();
119 *(int *) data = OF_finddevice("/options");
120 splx(s);
121 return (0);
122 }
123
124 /* Verify node id */
125 of = (struct ofiocdesc *)data;
126 node = of->of_nodeid;
127 if (node != 0 && node != lastnode) {
128 /* Not an easy one, must search for it */
129 s = splhigh();
130 ok = openfirmcheckid(OF_peer(0), node);
131 splx(s);
132 if (!ok)
133 return (EINVAL);
134 lastnode = node;
135 }
136
137 name = value = NULL;
138 error = 0;
139 switch (cmd) {
140
141 case OFIOCGET:
142 if ((flags & FREAD) == 0)
143 return (EBADF);
144 if (node == 0)
145 return (EINVAL);
146 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
147 if (error)
148 break;
149 s = splhigh();
150 len = OF_getproplen(node, name);
151 splx(s);
152 if (len > of->of_buflen) {
153 error = ENOMEM;
154 break;
155 }
156 of->of_buflen = len;
157 /* -1 means no entry; 0 means no value */
158 if (len <= 0)
159 break;
160 value = malloc(len, M_TEMP, M_WAITOK);
161 if (value == NULL) {
162 error = ENOMEM;
163 break;
164 }
165 s = splhigh();
166 len = OF_getprop(node, name, (void *)value, len);
167 splx(s);
168 error = copyout(value, of->of_buf, len);
169 break;
170
171 #if 0
172 case OFIOCSET:
173 if ((flags & FWRITE) == 0)
174 return (EBADF);
175 if (node == 0)
176 return (EINVAL);
177 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
178 if (error)
179 break;
180 error = openfirmgetstr(of->of_buflen, of->of_buf, &value);
181 if (error)
182 break;
183 s = splhigh();
184 len = OF_setprop(node, name, value, of->of_buflen + 1);
185 splx(s);
186 if (len != of->of_buflen)
187 error = EINVAL;
188 break;
189 #endif
190
191 case OFIOCNEXTPROP: {
192 char newname[32];
193 if ((flags & FREAD) == 0)
194 return (EBADF);
195 if (node == 0)
196 return (EINVAL);
197 if (of->of_namelen != 0) {
198 error = openfirmgetstr(of->of_namelen, of->of_name,
199 &name);
200 if (error)
201 break;
202 }
203 s = splhigh();
204 ok = OF_nextprop(node, name, newname);
205 splx(s);
206 if (ok == 0) {
207 error = ENOENT;
208 break;
209 }
210 if (ok == -1) {
211 error = EINVAL;
212 break;
213 }
214 len = strlen(newname);
215 if (len > of->of_buflen)
216 len = of->of_buflen;
217 else
218 of->of_buflen = len;
219 error = copyout(newname, of->of_buf, len);
220 break;
221 }
222
223 case OFIOCGETNEXT:
224 if ((flags & FREAD) == 0)
225 return (EBADF);
226 s = splhigh();
227 node = OF_peer(node);
228 splx(s);
229 *(int *)data = lastnode = node;
230 break;
231
232 case OFIOCGETCHILD:
233 if ((flags & FREAD) == 0)
234 return (EBADF);
235 if (node == 0)
236 return (EINVAL);
237 s = splhigh();
238 node = OF_child(node);
239 splx(s);
240 *(int *)data = lastnode = node;
241 break;
242
243 case OFIOCFINDDEVICE:
244 if ((flags & FREAD) == 0)
245 return (EBADF);
246 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
247 if (error)
248 break;
249 node = OF_finddevice(name);
250 if (node == 0 || node == -1) {
251 error = ENOENT;
252 break;
253 }
254 of->of_nodeid = lastnode = node;
255 break;
256
257 default:
258 return (ENOTTY);
259 }
260
261 if (name)
262 free(name, M_TEMP);
263 if (value)
264 free(value, M_TEMP);
265
266 return (error);
267 }
Cache object: 8947bfe67c5c4e7f1f71ce41ce26acd3
|