1 /* $NetBSD: openprom.c,v 1.28 2014/07/25 08:10:35 dholland 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 * @(#)openprom.c 8.1 (Berkeley) 6/11/93
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: openprom.c,v 1.28 2014/07/25 08:10:35 dholland Exp $");
45
46 #include "opt_sparc_arch.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/errno.h>
51 #include <sys/fcntl.h>
52 #include <sys/ioctl.h>
53 #include <sys/malloc.h>
54 #include <sys/conf.h>
55 #include <sys/device.h>
56 #include <sys/event.h>
57
58 #include <machine/bsd_openprom.h>
59 #include <machine/promlib.h>
60 #include <machine/openpromio.h>
61
62 dev_type_open(openpromopen);
63 dev_type_ioctl(openpromioctl);
64
65 const struct cdevsw openprom_cdevsw = {
66 .d_open = openpromopen,
67 .d_close = nullclose,
68 .d_read = noread,
69 .d_write = nowrite,
70 .d_ioctl = openpromioctl,
71 .d_stop = nostop,
72 .d_tty = notty,
73 .d_poll = nopoll,
74 .d_mmap = nommap,
75 .d_kqfilter = nokqfilter,
76 .d_discard = nodiscard,
77 .d_flag = D_OTHER
78 };
79
80 static int lastnode; /* speed hack */
81
82 static int openpromcheckid(int, int);
83 static int openpromgetstr(int, char *, char **);
84
85 int
openpromopen(dev_t dev,int flags,int mode,struct lwp * l)86 openpromopen(dev_t dev, int flags, int mode, struct lwp *l)
87 {
88
89 #if defined(SUN4)
90 if (cputyp==CPU_SUN4)
91 return (ENODEV);
92 #endif
93
94 return (0);
95 }
96
97 /*
98 * Verify target ID is valid (exists in the OPENPROM tree), as
99 * listed from node ID sid forward.
100 */
101 static int
openpromcheckid(int sid,int tid)102 openpromcheckid(int sid, int tid)
103 {
104
105 for (; sid != 0; sid = nextsibling(sid))
106 if (sid == tid || openpromcheckid(firstchild(sid), tid))
107 return (1);
108
109 return (0);
110 }
111
112 static int
openpromgetstr(int len,char * user,char ** cpp)113 openpromgetstr(int len, char *user, char **cpp)
114 {
115 int error;
116 char *cp;
117
118 /* Reject obvious bogus requests */
119 if ((u_int)len > (8 * 1024) - 1)
120 return (ENAMETOOLONG);
121
122 *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
123 error = copyin(user, cp, len);
124 cp[len] = '\0';
125 return (error);
126 }
127
128 int
openpromioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)129 openpromioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
130 {
131 struct opiocdesc *op;
132 int node, optionsnode, len, ok, error, s;
133 char *name, *value, *nextprop;
134
135 optionsnode = prom_getoptionsnode();
136
137 /* All too easy... */
138 if (cmd == OPIOCGETOPTNODE) {
139 *(int *)data = optionsnode;
140 return (0);
141 }
142
143 /* Verify node id */
144 op = (struct opiocdesc *)data;
145 node = op->op_nodeid;
146 if (node != 0 && node != lastnode && node != optionsnode) {
147 /* Not an easy one, must search for it */
148 s = splhigh();
149 ok = openpromcheckid(findroot(), node);
150 splx(s);
151 if (!ok)
152 return (EINVAL);
153 lastnode = node;
154 }
155
156 name = value = NULL;
157 error = 0;
158 switch (cmd) {
159
160 case OPIOCGET:
161 if ((flags & FREAD) == 0)
162 return (EBADF);
163 if (node == 0)
164 return (EINVAL);
165 error = openpromgetstr(op->op_namelen, op->op_name, &name);
166 if (error)
167 break;
168 s = splhigh();
169 len = prom_proplen(node, name);
170 splx(s);
171 if (len > op->op_buflen) {
172 error = ENOMEM;
173 break;
174 }
175 op->op_buflen = len;
176 /* -1 means no entry; 0 means no value */
177 if (len <= 0)
178 break;
179 value = malloc(len, M_TEMP, M_WAITOK);
180 s = splhigh();
181 error = prom_getprop(node, name, 1, &len, &value);
182 splx(s);
183 if (error != 0)
184 break;
185 error = copyout(value, op->op_buf, len);
186 break;
187
188 case OPIOCSET:
189 if ((flags & FWRITE) == 0)
190 return (EBADF);
191 if (node == 0)
192 return (EINVAL);
193 error = openpromgetstr(op->op_namelen, op->op_name, &name);
194 if (error)
195 break;
196 error = openpromgetstr(op->op_buflen, op->op_buf, &value);
197 if (error)
198 break;
199 s = splhigh();
200 len = prom_setprop(node, name, value, op->op_buflen + 1);
201 splx(s);
202 if (len != op->op_buflen)
203 error = EINVAL;
204 break;
205
206 case OPIOCNEXTPROP:
207 if ((flags & FREAD) == 0)
208 return (EBADF);
209 if (node == 0)
210 return (EINVAL);
211 error = openpromgetstr(op->op_namelen, op->op_name, &name);
212 if (error)
213 break;
214 s = splhigh();
215 nextprop = prom_nextprop(node, name);
216 splx(s);
217 len = strlen(nextprop);
218 if (len > op->op_buflen)
219 len = op->op_buflen;
220 else
221 op->op_buflen = len;
222 error = copyout(nextprop, op->op_buf, len);
223 break;
224
225 case OPIOCGETNEXT:
226 if ((flags & FREAD) == 0)
227 return (EBADF);
228 s = splhigh();
229 node = nextsibling(node);
230 splx(s);
231 *(int *)data = lastnode = node;
232 break;
233
234 case OPIOCGETCHILD:
235 if ((flags & FREAD) == 0)
236 return (EBADF);
237 if (node == 0)
238 return (EINVAL);
239 s = splhigh();
240 node = firstchild(node);
241 splx(s);
242 *(int *)data = lastnode = node;
243 break;
244
245 case OPIOCFINDDEVICE:
246 if ((flags & FREAD) == 0)
247 return (EBADF);
248 error = openpromgetstr(op->op_namelen, op->op_name, &name);
249 if (error)
250 break;
251 node = prom_finddevice(name);
252 if (node == 0 || node == -1) {
253 error = ENOENT;
254 break;
255 }
256 op->op_nodeid = lastnode = node;
257 break;
258
259 default:
260 return (ENOTTY);
261 }
262
263 if (name)
264 free(name, M_TEMP);
265 if (value)
266 free(value, M_TEMP);
267
268 return (error);
269 }
270