openfirmio.c revision 1.1 1 /* $NetBSD: openfirmio.c,v 1.1 2000/11/14 06:45:54 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 /* Verify node id */
124 of = (struct ofiocdesc *)data;
125 node = of->of_nodeid;
126 if (node != 0 && node != lastnode) {
127 /* Not an easy one, must search for it */
128 s = splhigh();
129 ok = openfirmcheckid(OF_peer(0), node);
130 splx(s);
131 if (!ok)
132 return (EINVAL);
133 lastnode = node;
134 }
135
136 name = value = NULL;
137 error = 0;
138 switch (cmd) {
139
140 case OFIOCGET:
141 if ((flags & FREAD) == 0)
142 return (EBADF);
143 if (node == 0)
144 return (EINVAL);
145 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
146 if (error)
147 break;
148 s = splhigh();
149 len = OF_getproplen(node, name);
150 splx(s);
151 if (len > of->of_buflen) {
152 error = ENOMEM;
153 break;
154 }
155 of->of_buflen = len;
156 /* -1 means no entry; 0 means no value */
157 if (len <= 0)
158 break;
159 value = malloc(len, M_TEMP, M_WAITOK);
160 if (value == NULL) {
161 error = ENOMEM;
162 break;
163 }
164 s = splhigh();
165 len = OF_getprop(node, name, (void *)value, len);
166 splx(s);
167 error = copyout(value, of->of_buf, len);
168 break;
169
170 #if 0
171 case OFIOCSET:
172 if ((flags & FWRITE) == 0)
173 return (EBADF);
174 if (node == 0)
175 return (EINVAL);
176 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
177 if (error)
178 break;
179 error = openfirmgetstr(of->of_buflen, of->of_buf, &value);
180 if (error)
181 break;
182 s = splhigh();
183 len = OF_setprop(node, name, value, of->of_buflen + 1);
184 splx(s);
185 if (len != of->of_buflen)
186 error = EINVAL;
187 break;
188 #endif
189
190 case OFIOCNEXTPROP: {
191 char newname[33];
192 if ((flags & FREAD) == 0)
193 return (EBADF);
194 if (node == 0)
195 return (EINVAL);
196 if (of->of_namelen != 0 || of->of_name != NULL) {
197 error = openfirmgetstr(of->of_namelen, of->of_name,
198 &name);
199 if (error)
200 break;
201 }
202 s = splhigh();
203 ok = OF_nextprop(node, name, newname);
204 splx(s);
205 if (ok == -1) {
206 error = EINVAL;
207 break;
208 }
209 len = strlen(newname);
210 if (len > of->of_buflen)
211 len = of->of_buflen;
212 else
213 of->of_buflen = len;
214 error = copyout(newname, of->of_buf, len);
215 break;
216 }
217
218 case OFIOCGETNEXT:
219 if ((flags & FREAD) == 0)
220 return (EBADF);
221 s = splhigh();
222 node = OF_peer(node);
223 splx(s);
224 *(int *)data = lastnode = node;
225 break;
226
227 case OFIOCGETCHILD:
228 if ((flags & FREAD) == 0)
229 return (EBADF);
230 if (node == 0)
231 return (EINVAL);
232 s = splhigh();
233 node = OF_child(node);
234 splx(s);
235 *(int *)data = lastnode = node;
236 break;
237
238 case OFIOCFINDDEVICE:
239 if ((flags & FREAD) == 0)
240 return (EBADF);
241 error = openfirmgetstr(of->of_namelen, of->of_name, &name);
242 if (error)
243 break;
244 node = OF_finddevice(name);
245 if (node == 0 || node == -1) {
246 error = ENOENT;
247 break;
248 }
249 of->of_nodeid = node;
250 break;
251
252 default:
253 return (ENOTTY);
254 }
255
256 if (name)
257 free(name, M_TEMP);
258 if (value)
259 free(value, M_TEMP);
260
261 return (error);
262 }
263