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
openpromopen(dev,flags,mode)37 openpromopen(dev, flags, mode)
38 dev_t dev;
39 int flags, mode;
40 {
41
42 return (0);
43 }
44
45 int
openpromclose(dev,flags,mode)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
openpromcheckid(sid,tid)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
openpromgetstr(len,user,cpp)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
openpromioctl(dev,cmd,data,flags,p)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