xref: /original-bsd/sys/sparc/sparc/openprom.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratory.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)openprom.c	8.1 (Berkeley) 06/11/93
17  *
18  * from: $Header: openprom.c,v 1.3 93/04/27 08:56:09 torek Exp $
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/errno.h>
24 #include <sys/fcntl.h>
25 #include <sys/ioctl.h>
26 #include <sys/malloc.h>
27 
28 #include <machine/bsd_openprom.h>
29 #include <machine/openpromio.h>
30 
31 static	int lastnode;			/* speed hack */
32 extern	int optionsnode;		/* node ID of ROM's options */
33 extern	int findroot();			/* returns node ID of top node */
34 extern	struct promvec *promvec;
35 
36 int
37 openpromopen(dev, flags, mode)
38 	dev_t dev;
39 	int flags, mode;
40 {
41 
42 	return (0);
43 }
44 
45 int
46 openpromclose(dev, flags, mode)
47 	dev_t dev;
48 	int flags, mode;
49 {
50 
51 	return (0);
52 }
53 
54 /*
55  * Verify target ID is valid (exists in the OPENPROM tree), as
56  * listed from node ID sid forward.
57  */
58 static int
59 openpromcheckid(sid, tid)
60 	register int sid, tid;
61 {
62 	register struct nodeops *no;
63 
64 	no = promvec->pv_nodeops;
65 	for (; sid != 0; sid = no->no_nextnode(sid))
66 		if (sid == tid || openpromcheckid(no->no_child(sid), tid))
67 			return (1);
68 
69 	return (0);
70 }
71 
72 static int
73 openpromgetstr(len, user, cpp)
74 	int len;
75 	char *user, **cpp;
76 {
77 	register int error;
78 	register char *cp;
79 
80 	/* Reject obvious bogus requests */
81 	if ((u_int)len > (8 * 1024) - 1)
82 		return (ENAMETOOLONG);
83 
84 	*cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK);
85 	error = copyin(user, cp, len);
86 	cp[len] = '\0';
87 	return (error);
88 }
89 
90 int
91 openpromioctl(dev, cmd, data, flags, p)
92 	dev_t dev;
93 	int cmd;
94 	caddr_t data;
95 	int flags;
96 	struct proc *p;
97 {
98 	register struct opiocdesc *op;
99 	register int node, len, ok, error, s;
100 	char *name, *value, *nextprop;
101 	register struct nodeops *no;
102 
103 	/* All too easy... */
104 	if (cmd == OPIOCGETOPTNODE) {
105 		*(int *)data = optionsnode;
106 		return (0);
107 	}
108 
109 	/* Verify node id */
110 	op = (struct opiocdesc *)data;
111 	node = op->op_nodeid;
112 	if (node != 0 && node != lastnode && node != optionsnode) {
113 		/* Not an easy one, must search for it */
114 		s = splhigh();
115 		ok = openpromcheckid(findroot(), node);
116 		splx(s);
117 		if (!ok)
118 			return (EINVAL);
119 		lastnode = node;
120 	}
121 
122 	name = value = NULL;
123 	no = promvec->pv_nodeops;
124 	error = 0;
125 	switch (cmd) {
126 
127 	case OPIOCGET:
128 		if ((flags & FREAD) == 0)
129 			return (EBADF);
130 		if (node == 0)
131 			return (EINVAL);
132 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
133 		if (error)
134 			break;
135 		s = splhigh();
136 		len = no->no_proplen(node, name);
137 		splx(s);
138 		if (len > op->op_buflen)
139 			len = op->op_buflen;
140 		else
141 			op->op_buflen = len;
142 		/* -1 means no entry; 0 means no value */
143 		if (len <= 0)
144 			break;
145 		value = malloc(len, M_TEMP, M_WAITOK);
146 		s = splhigh();
147 		(void)no->no_getprop(node, name, value);
148 		splx(s);
149 		error = copyout(value, op->op_buf, len);
150 		break;
151 
152 	case OPIOCSET:
153 		if ((flags & FWRITE) == 0)
154 			return (EBADF);
155 		if (node == 0)
156 			return (EINVAL);
157 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
158 		if (error)
159 			break;
160 		error = openpromgetstr(op->op_buflen, op->op_buf, &value);
161 		if (error)
162 			break;
163 		s = splhigh();
164 		len = no->no_setprop(node, name, value, op->op_buflen + 1);
165 		splx(s);
166 		if (len != op->op_buflen)
167 			error = EINVAL;
168 		break;
169 
170 	case OPIOCNEXTPROP:
171 		if ((flags & FREAD) == 0)
172 			return (EBADF);
173 		if (node == 0)
174 			return (EINVAL);
175 		error = openpromgetstr(op->op_namelen, op->op_name, &name);
176 		if (error)
177 			break;
178 		s = splhigh();
179 		nextprop = no->no_nextprop(node, name);
180 		splx(s);
181 		len = strlen(nextprop);
182 		if (len > op->op_buflen)
183 			len = op->op_buflen;
184 		else
185 			op->op_buflen = len;
186 		error = copyout(nextprop, op->op_buf, len);
187 		break;
188 
189 	case OPIOCGETNEXT:
190 		if ((flags & FREAD) == 0)
191 			return (EBADF);
192 		s = splhigh();
193 		node = no->no_nextnode(node);
194 		splx(s);
195 		*(int *)data = lastnode = node;
196 		break;
197 
198 	case OPIOCGETCHILD:
199 		if ((flags & FREAD) == 0)
200 			return (EBADF);
201 		if (node == 0)
202 			return (EINVAL);
203 		s = splhigh();
204 		node = no->no_child(node);
205 		splx(s);
206 		*(int *)data = lastnode = node;
207 		break;
208 
209 	default:
210 		return (ENOTTY);
211 	}
212 
213 	if (name)
214 		free(name, M_TEMP);
215 	if (value)
216 		free(value, M_TEMP);
217 
218 	return (error);
219 }
220