1 /* $NetBSD: openfirmio.c,v 1.3 2001/11/13 07:26:29 lukem 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/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: openfirmio.c,v 1.3 2001/11/13 07:26:29 lukem Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/errno.h> 53 #include <sys/fcntl.h> 54 #include <sys/ioctl.h> 55 #include <sys/malloc.h> 56 #include <sys/conf.h> 57 #include <sys/device.h> 58 59 #include <dev/ofw/openfirm.h> 60 #include <dev/ofw/openfirmio.h> 61 62 static int lastnode; /* speed hack */ 63 64 static int openfirmcheckid (int, int); 65 static int openfirmgetstr (int, char *, char **); 66 67 void openfirmattach (int); 68 69 void 70 openfirmattach(int num) 71 { 72 /* nothing */ 73 } 74 75 int 76 openfirmopen(dev_t dev, int flags, int mode, struct proc *p) 77 { 78 return (0); 79 } 80 81 int 82 openfirmclose(dev_t dev, int flags, int mode, struct proc *p) 83 { 84 85 return (0); 86 } 87 88 /* 89 * Verify target ID is valid (exists in the OPENPROM tree), as 90 * listed from node ID sid forward. 91 */ 92 static int 93 openfirmcheckid(int sid, int tid) 94 { 95 96 for (; sid != 0; sid = OF_peer(sid)) 97 if (sid == tid || openfirmcheckid(OF_child(sid), tid)) 98 return (1); 99 100 return (0); 101 } 102 103 static int 104 openfirmgetstr(int len, char *user, char **cpp) 105 { 106 int error; 107 char *cp; 108 109 /* Reject obvious bogus requests */ 110 if ((u_int)len > (8 * 1024) - 1) 111 return (ENAMETOOLONG); 112 113 *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK); 114 error = copyin(user, cp, len); 115 cp[len] = '\0'; 116 return (error); 117 } 118 119 int 120 openfirmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 121 { 122 struct ofiocdesc *of; 123 int node, len, ok, error, s; 124 char *name, *value; 125 126 if (cmd == OFIOCGETOPTNODE) { 127 s = splhigh(); 128 *(int *) data = OF_finddevice("/options"); 129 splx(s); 130 return (0); 131 } 132 133 /* Verify node id */ 134 of = (struct ofiocdesc *)data; 135 node = of->of_nodeid; 136 if (node != 0 && node != lastnode) { 137 /* Not an easy one, must search for it */ 138 s = splhigh(); 139 ok = openfirmcheckid(OF_peer(0), node); 140 splx(s); 141 if (!ok) 142 return (EINVAL); 143 lastnode = node; 144 } 145 146 name = value = NULL; 147 error = 0; 148 switch (cmd) { 149 150 case OFIOCGET: 151 if ((flags & FREAD) == 0) 152 return (EBADF); 153 if (node == 0) 154 return (EINVAL); 155 error = openfirmgetstr(of->of_namelen, of->of_name, &name); 156 if (error) 157 break; 158 s = splhigh(); 159 len = OF_getproplen(node, name); 160 splx(s); 161 if (len > of->of_buflen) { 162 error = ENOMEM; 163 break; 164 } 165 of->of_buflen = len; 166 /* -1 means no entry; 0 means no value */ 167 if (len <= 0) 168 break; 169 value = malloc(len, M_TEMP, M_WAITOK); 170 if (value == NULL) { 171 error = ENOMEM; 172 break; 173 } 174 s = splhigh(); 175 len = OF_getprop(node, name, (void *)value, len); 176 splx(s); 177 error = copyout(value, of->of_buf, len); 178 break; 179 180 #if 0 181 case OFIOCSET: 182 if ((flags & FWRITE) == 0) 183 return (EBADF); 184 if (node == 0) 185 return (EINVAL); 186 error = openfirmgetstr(of->of_namelen, of->of_name, &name); 187 if (error) 188 break; 189 error = openfirmgetstr(of->of_buflen, of->of_buf, &value); 190 if (error) 191 break; 192 s = splhigh(); 193 len = OF_setprop(node, name, value, of->of_buflen + 1); 194 splx(s); 195 if (len != of->of_buflen) 196 error = EINVAL; 197 break; 198 #endif 199 200 case OFIOCNEXTPROP: { 201 char newname[32]; 202 if ((flags & FREAD) == 0) 203 return (EBADF); 204 if (node == 0) 205 return (EINVAL); 206 if (of->of_namelen != 0) { 207 error = openfirmgetstr(of->of_namelen, of->of_name, 208 &name); 209 if (error) 210 break; 211 } 212 s = splhigh(); 213 ok = OF_nextprop(node, name, newname); 214 splx(s); 215 if (ok == 0) { 216 error = ENOENT; 217 break; 218 } 219 if (ok == -1) { 220 error = EINVAL; 221 break; 222 } 223 len = strlen(newname); 224 if (len > of->of_buflen) 225 len = of->of_buflen; 226 else 227 of->of_buflen = len; 228 error = copyout(newname, of->of_buf, len); 229 break; 230 } 231 232 case OFIOCGETNEXT: 233 if ((flags & FREAD) == 0) 234 return (EBADF); 235 s = splhigh(); 236 node = OF_peer(node); 237 splx(s); 238 *(int *)data = lastnode = node; 239 break; 240 241 case OFIOCGETCHILD: 242 if ((flags & FREAD) == 0) 243 return (EBADF); 244 if (node == 0) 245 return (EINVAL); 246 s = splhigh(); 247 node = OF_child(node); 248 splx(s); 249 *(int *)data = lastnode = node; 250 break; 251 252 case OFIOCFINDDEVICE: 253 if ((flags & FREAD) == 0) 254 return (EBADF); 255 error = openfirmgetstr(of->of_namelen, of->of_name, &name); 256 if (error) 257 break; 258 node = OF_finddevice(name); 259 if (node == 0 || node == -1) { 260 error = ENOENT; 261 break; 262 } 263 of->of_nodeid = lastnode = node; 264 break; 265 266 default: 267 return (ENOTTY); 268 } 269 270 if (name) 271 free(name, M_TEMP); 272 if (value) 273 free(value, M_TEMP); 274 275 return (error); 276 } 277