Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / ofw / openfirmio.c
blob480eb2ccad311c61541684d7a152852f17445301
1 /* $NetBSD: openfirmio.c,v 1.10 2007/02/28 20:33:50 macallan Exp $ */
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
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.
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.
40 * @(#)openfirm.c 8.1 (Berkeley) 6/11/93
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: openfirmio.c,v 1.10 2007/02/28 20:33:50 macallan Exp $");
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>
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/openfirmio.h>
59 static int lastnode; /* speed hack */
61 static int openfirmcheckid (int, int);
62 static int openfirmgetstr (int, char *, char **);
64 void openfirmattach (int);
66 dev_type_ioctl(openfirmioctl);
68 const struct cdevsw openfirm_cdevsw = {
69 nullopen, nullclose, noread, nowrite, openfirmioctl,
70 nostop, notty, nopoll, nommap, nokqfilter,
73 void
74 openfirmattach(int num)
76 /* nothing */
80 * Verify target ID is valid (exists in the OPENPROM tree), as
81 * listed from node ID sid forward.
83 static int
84 openfirmcheckid(int sid, int tid)
87 for (; sid != 0; sid = OF_peer(sid))
88 if (sid == tid || openfirmcheckid(OF_child(sid), tid))
89 return (1);
91 return (0);
94 static int
95 openfirmgetstr(int len, char *user, char **cpp)
97 int error;
98 char *cp;
100 /* Reject obvious bogus requests */
101 if ((u_int)len > (8 * 1024) - 1)
102 return (ENAMETOOLONG);
104 *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
105 error = copyin(user, cp, len);
106 cp[len] = '\0';
107 return (error);
111 openfirmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
113 struct ofiocdesc *of;
114 int node, len, ok, error, s;
115 char *name, *value;
117 if (cmd == OFIOCGETOPTNODE) {
118 s = splhigh();
119 *(int *) data = OF_finddevice("/options");
120 splx(s);
121 return (0);
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;
137 name = value = NULL;
138 error = 0;
139 switch (cmd) {
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;
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;
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;
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);
188 * XXX
189 * some OF implementations return the buffer length including
190 * the trailing zero ( like macppc ) and some without ( like
191 * FirmWorks OF used in Shark )
193 if ((len != (of->of_buflen + 1)) && (len != of->of_buflen))
194 error = EINVAL;
195 break;
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;
209 s = splhigh();
210 ok = OF_nextprop(node, name, newname);
211 splx(s);
212 if (ok == 0) {
213 error = ENOENT;
214 break;
216 if (ok == -1) {
217 error = EINVAL;
218 break;
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;
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;
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;
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;
260 of->of_nodeid = lastnode = node;
261 break;
263 default:
264 return (ENOTTY);
267 if (name)
268 free(name, M_TEMP);
269 if (value)
270 free(value, M_TEMP);
272 return (error);