1 1.15 mrg /* $NetBSD: openfirmio.c,v 1.15 2019/12/06 06:38:39 mrg Exp $ */ 2 1.1 matt 3 1.1 matt /* 4 1.1 matt * Copyright (c) 1992, 1993 5 1.1 matt * The Regents of the University of California. All rights reserved. 6 1.1 matt * 7 1.1 matt * This software was developed by the Computer Systems Engineering group 8 1.1 matt * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 matt * contributed to Berkeley. 10 1.1 matt * 11 1.1 matt * All advertising materials mentioning features or use of this software 12 1.1 matt * must display the following acknowledgement: 13 1.1 matt * This product includes software developed by the University of 14 1.1 matt * California, Lawrence Berkeley Laboratory. 15 1.1 matt * 16 1.1 matt * Redistribution and use in source and binary forms, with or without 17 1.1 matt * modification, are permitted provided that the following conditions 18 1.1 matt * are met: 19 1.1 matt * 1. Redistributions of source code must retain the above copyright 20 1.1 matt * notice, this list of conditions and the following disclaimer. 21 1.1 matt * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 matt * notice, this list of conditions and the following disclaimer in the 23 1.1 matt * documentation and/or other materials provided with the distribution. 24 1.8 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 matt * may be used to endorse or promote products derived from this software 26 1.1 matt * without specific prior written permission. 27 1.1 matt * 28 1.1 matt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 matt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 matt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 matt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 matt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 matt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 matt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 matt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 matt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 matt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 matt * SUCH DAMAGE. 39 1.1 matt * 40 1.1 matt * @(#)openfirm.c 8.1 (Berkeley) 6/11/93 41 1.1 matt */ 42 1.3 lukem 43 1.3 lukem #include <sys/cdefs.h> 44 1.15 mrg __KERNEL_RCSID(0, "$NetBSD: openfirmio.c,v 1.15 2019/12/06 06:38:39 mrg Exp $"); 45 1.1 matt 46 1.1 matt #include <sys/param.h> 47 1.1 matt #include <sys/systm.h> 48 1.1 matt #include <sys/errno.h> 49 1.1 matt #include <sys/fcntl.h> 50 1.1 matt #include <sys/ioctl.h> 51 1.1 matt #include <sys/malloc.h> 52 1.1 matt #include <sys/conf.h> 53 1.1 matt #include <sys/device.h> 54 1.5 jdolecek #include <sys/event.h> 55 1.1 matt 56 1.1 matt #include <dev/ofw/openfirm.h> 57 1.1 matt #include <dev/ofw/openfirmio.h> 58 1.1 matt 59 1.1 matt static int lastnode; /* speed hack */ 60 1.1 matt 61 1.1 matt static int openfirmcheckid (int, int); 62 1.1 matt static int openfirmgetstr (int, char *, char **); 63 1.1 matt 64 1.1 matt void openfirmattach (int); 65 1.1 matt 66 1.14 mrg static dev_type_open(openfirmopen); 67 1.14 mrg static dev_type_ioctl(openfirmioctl); 68 1.4 gehenna 69 1.4 gehenna const struct cdevsw openfirm_cdevsw = { 70 1.14 mrg .d_open = openfirmopen, 71 1.12 dholland .d_close = nullclose, 72 1.12 dholland .d_read = noread, 73 1.12 dholland .d_write = nowrite, 74 1.12 dholland .d_ioctl = openfirmioctl, 75 1.12 dholland .d_stop = nostop, 76 1.12 dholland .d_tty = notty, 77 1.12 dholland .d_poll = nopoll, 78 1.12 dholland .d_mmap = nommap, 79 1.12 dholland .d_kqfilter = nokqfilter, 80 1.13 dholland .d_discard = nodiscard, 81 1.12 dholland .d_flag = 0 82 1.4 gehenna }; 83 1.4 gehenna 84 1.1 matt void 85 1.1 matt openfirmattach(int num) 86 1.1 matt { 87 1.1 matt /* nothing */ 88 1.1 matt } 89 1.1 matt 90 1.1 matt /* 91 1.1 matt * Verify target ID is valid (exists in the OPENPROM tree), as 92 1.1 matt * listed from node ID sid forward. 93 1.1 matt */ 94 1.1 matt static int 95 1.1 matt openfirmcheckid(int sid, int tid) 96 1.1 matt { 97 1.1 matt 98 1.1 matt for (; sid != 0; sid = OF_peer(sid)) 99 1.1 matt if (sid == tid || openfirmcheckid(OF_child(sid), tid)) 100 1.1 matt return (1); 101 1.1 matt 102 1.1 matt return (0); 103 1.1 matt } 104 1.1 matt 105 1.1 matt static int 106 1.1 matt openfirmgetstr(int len, char *user, char **cpp) 107 1.1 matt { 108 1.1 matt int error; 109 1.1 matt char *cp; 110 1.1 matt 111 1.1 matt /* Reject obvious bogus requests */ 112 1.1 matt if ((u_int)len > (8 * 1024) - 1) 113 1.1 matt return (ENAMETOOLONG); 114 1.1 matt 115 1.1 matt *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK); 116 1.1 matt error = copyin(user, cp, len); 117 1.1 matt cp[len] = '\0'; 118 1.1 matt return (error); 119 1.1 matt } 120 1.1 matt 121 1.14 mrg static int 122 1.14 mrg openfirmopen(dev_t dev, int flag, int mode, struct lwp *l) 123 1.14 mrg { 124 1.14 mrg 125 1.14 mrg return 0; 126 1.14 mrg } 127 1.14 mrg 128 1.14 mrg static int 129 1.11 christos openfirmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 130 1.1 matt { 131 1.1 matt struct ofiocdesc *of; 132 1.1 matt int node, len, ok, error, s; 133 1.1 matt char *name, *value; 134 1.1 matt 135 1.2 matt if (cmd == OFIOCGETOPTNODE) { 136 1.2 matt s = splhigh(); 137 1.2 matt *(int *) data = OF_finddevice("/options"); 138 1.2 matt splx(s); 139 1.2 matt return (0); 140 1.2 matt } 141 1.2 matt 142 1.1 matt /* Verify node id */ 143 1.1 matt of = (struct ofiocdesc *)data; 144 1.1 matt node = of->of_nodeid; 145 1.1 matt if (node != 0 && node != lastnode) { 146 1.1 matt /* Not an easy one, must search for it */ 147 1.1 matt s = splhigh(); 148 1.1 matt ok = openfirmcheckid(OF_peer(0), node); 149 1.1 matt splx(s); 150 1.1 matt if (!ok) 151 1.1 matt return (EINVAL); 152 1.1 matt lastnode = node; 153 1.1 matt } 154 1.1 matt 155 1.1 matt name = value = NULL; 156 1.1 matt error = 0; 157 1.1 matt switch (cmd) { 158 1.1 matt 159 1.1 matt case OFIOCGET: 160 1.1 matt if ((flags & FREAD) == 0) 161 1.1 matt return (EBADF); 162 1.1 matt if (node == 0) 163 1.1 matt return (EINVAL); 164 1.1 matt error = openfirmgetstr(of->of_namelen, of->of_name, &name); 165 1.1 matt if (error) 166 1.1 matt break; 167 1.1 matt s = splhigh(); 168 1.1 matt len = OF_getproplen(node, name); 169 1.1 matt splx(s); 170 1.1 matt if (len > of->of_buflen) { 171 1.1 matt error = ENOMEM; 172 1.1 matt break; 173 1.1 matt } 174 1.1 matt of->of_buflen = len; 175 1.1 matt /* -1 means no entry; 0 means no value */ 176 1.1 matt if (len <= 0) 177 1.1 matt break; 178 1.1 matt value = malloc(len, M_TEMP, M_WAITOK); 179 1.1 matt if (value == NULL) { 180 1.1 matt error = ENOMEM; 181 1.1 matt break; 182 1.1 matt } 183 1.1 matt s = splhigh(); 184 1.1 matt len = OF_getprop(node, name, (void *)value, len); 185 1.1 matt splx(s); 186 1.1 matt error = copyout(value, of->of_buf, len); 187 1.1 matt break; 188 1.1 matt 189 1.10 macallan 190 1.1 matt case OFIOCSET: 191 1.1 matt if ((flags & FWRITE) == 0) 192 1.1 matt return (EBADF); 193 1.1 matt if (node == 0) 194 1.1 matt return (EINVAL); 195 1.1 matt error = openfirmgetstr(of->of_namelen, of->of_name, &name); 196 1.1 matt if (error) 197 1.1 matt break; 198 1.1 matt error = openfirmgetstr(of->of_buflen, of->of_buf, &value); 199 1.1 matt if (error) 200 1.1 matt break; 201 1.1 matt s = splhigh(); 202 1.1 matt len = OF_setprop(node, name, value, of->of_buflen + 1); 203 1.1 matt splx(s); 204 1.10 macallan 205 1.10 macallan /* 206 1.10 macallan * XXX 207 1.10 macallan * some OF implementations return the buffer length including 208 1.10 macallan * the trailing zero ( like macppc ) and some without ( like 209 1.10 macallan * FirmWorks OF used in Shark ) 210 1.10 macallan */ 211 1.10 macallan if ((len != (of->of_buflen + 1)) && (len != of->of_buflen)) 212 1.1 matt error = EINVAL; 213 1.1 matt break; 214 1.1 matt 215 1.1 matt case OFIOCNEXTPROP: { 216 1.2 matt char newname[32]; 217 1.1 matt if ((flags & FREAD) == 0) 218 1.1 matt return (EBADF); 219 1.1 matt if (node == 0) 220 1.1 matt return (EINVAL); 221 1.2 matt if (of->of_namelen != 0) { 222 1.1 matt error = openfirmgetstr(of->of_namelen, of->of_name, 223 1.1 matt &name); 224 1.1 matt if (error) 225 1.1 matt break; 226 1.1 matt } 227 1.1 matt s = splhigh(); 228 1.1 matt ok = OF_nextprop(node, name, newname); 229 1.1 matt splx(s); 230 1.2 matt if (ok == 0) { 231 1.2 matt error = ENOENT; 232 1.2 matt break; 233 1.2 matt } 234 1.1 matt if (ok == -1) { 235 1.1 matt error = EINVAL; 236 1.1 matt break; 237 1.1 matt } 238 1.1 matt len = strlen(newname); 239 1.1 matt if (len > of->of_buflen) 240 1.1 matt len = of->of_buflen; 241 1.1 matt else 242 1.1 matt of->of_buflen = len; 243 1.1 matt error = copyout(newname, of->of_buf, len); 244 1.1 matt break; 245 1.1 matt } 246 1.1 matt 247 1.1 matt case OFIOCGETNEXT: 248 1.1 matt if ((flags & FREAD) == 0) 249 1.1 matt return (EBADF); 250 1.1 matt s = splhigh(); 251 1.1 matt node = OF_peer(node); 252 1.1 matt splx(s); 253 1.1 matt *(int *)data = lastnode = node; 254 1.1 matt break; 255 1.1 matt 256 1.1 matt case OFIOCGETCHILD: 257 1.1 matt if ((flags & FREAD) == 0) 258 1.1 matt return (EBADF); 259 1.1 matt if (node == 0) 260 1.1 matt return (EINVAL); 261 1.1 matt s = splhigh(); 262 1.1 matt node = OF_child(node); 263 1.1 matt splx(s); 264 1.1 matt *(int *)data = lastnode = node; 265 1.1 matt break; 266 1.1 matt 267 1.1 matt case OFIOCFINDDEVICE: 268 1.1 matt if ((flags & FREAD) == 0) 269 1.1 matt return (EBADF); 270 1.1 matt error = openfirmgetstr(of->of_namelen, of->of_name, &name); 271 1.1 matt if (error) 272 1.1 matt break; 273 1.1 matt node = OF_finddevice(name); 274 1.1 matt if (node == 0 || node == -1) { 275 1.1 matt error = ENOENT; 276 1.1 matt break; 277 1.1 matt } 278 1.2 matt of->of_nodeid = lastnode = node; 279 1.1 matt break; 280 1.1 matt 281 1.1 matt default: 282 1.1 matt return (ENOTTY); 283 1.1 matt } 284 1.1 matt 285 1.1 matt if (name) 286 1.1 matt free(name, M_TEMP); 287 1.1 matt if (value) 288 1.1 matt free(value, M_TEMP); 289 1.1 matt 290 1.1 matt return (error); 291 1.1 matt } 292