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 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 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 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 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