Home | History | Annotate | Line # | Download | only in sparc
      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