]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ofw/openpromio.c
Fix TDP_WAKEUP/thr_wake(curthread->td_tid) after r366428.
[FreeBSD/FreeBSD.git] / sys / dev / ofw / openpromio.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2003 Jake Burkholder.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/conf.h>
36 #include <sys/errno.h>
37 #include <sys/fcntl.h>
38 #include <sys/ioccom.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/openpromio.h>
45
46 /*
47  * This provides a Solaris compatible character device interface to
48  * Open Firmware.  It exists entirely for compatibility with software
49  * like X11, and only the features that are actually needed for that
50  * are implemented.  The interface sucks too much to actually use,
51  * new code should use the /dev/openfirm device.
52  */
53
54 static d_open_t openprom_open;
55 static d_close_t openprom_close;
56 static d_ioctl_t openprom_ioctl;
57
58 static int openprom_modevent(module_t mode, int type, void *data);
59 static int openprom_node_valid(phandle_t node);
60 static int openprom_node_search(phandle_t root, phandle_t node);
61
62 static struct cdevsw openprom_cdevsw = {
63         .d_version =    D_VERSION,
64         .d_flags =      D_NEEDGIANT,
65         .d_open =       openprom_open,
66         .d_close =      openprom_close,
67         .d_ioctl =      openprom_ioctl,
68         .d_name =       "openprom",
69 };
70
71 static int openprom_is_open;
72 static struct cdev *openprom_dev;
73 static phandle_t openprom_node;
74
75 static int
76 openprom_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
77 {
78
79         if (openprom_is_open != 0)
80                 return (EBUSY);
81         openprom_is_open = 1;
82         return (0);
83 }
84
85 static int
86 openprom_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
87 {
88
89         openprom_is_open = 0;
90         return (0);
91 }
92
93 static int
94 openprom_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
95     struct thread *td)
96 {
97         struct openpromio *oprom;
98         phandle_t node;
99         uint32_t len;
100         size_t done;
101         int proplen;
102         char *prop;
103         char *buf;
104         int error;
105
106         if ((flags & FREAD) == 0)
107                 return (EPERM);
108
109         prop = buf = NULL;
110         error = 0;
111         switch (cmd) {
112         case OPROMCHILD:
113         case OPROMNEXT:
114                 if (data == NULL || *(void **)data == NULL)
115                         return (EINVAL);
116                 oprom = *(void **)data;
117                 error = copyin(&oprom->oprom_size, &len, sizeof(len));
118                 if (error != 0)
119                         break;
120                 if (len != sizeof(node)) {
121                         error = EINVAL;
122                         break;
123                 }
124                 error = copyin(&oprom->oprom_array, &node, sizeof(node));
125                 if (error != 0)
126                         break;
127                 error = openprom_node_valid(node);
128                 if (error != 0)
129                         break;
130                 switch (cmd) {
131                 case OPROMCHILD:
132                         node = OF_child(node);
133                         break;
134                 case OPROMNEXT:
135                         node = OF_peer(node);
136                         break;
137                 }
138                 error = copyout(&node, &oprom->oprom_array, sizeof(node));
139                 if (error != 0)
140                         break;
141                 openprom_node = node;
142                 break;
143         case OPROMGETPROP:
144         case OPROMNXTPROP:
145                 if (data == NULL || *(void **)data == NULL)
146                         return (EINVAL);
147                 oprom = *(void **)data;
148                 error = copyin(&oprom->oprom_size, &len, sizeof(len));
149                 if (error != 0)
150                         break;
151                 if (len > OPROMMAXPARAM) {
152                         error = EINVAL;
153                         break;
154                 }
155                 prop = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
156                 error = copyinstr(&oprom->oprom_array, prop, len, &done);
157                 if (error != 0)
158                         break;
159                 buf = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK | M_ZERO);
160                 node = openprom_node;
161                 switch (cmd) {
162                 case OPROMGETPROP:
163                         proplen = OF_getproplen(node, prop);
164                         if (proplen > OPROMMAXPARAM) {
165                                 error = EINVAL;
166                                 break;
167                         }
168                         error = OF_getprop(node, prop, buf, proplen);
169                         break;
170                 case OPROMNXTPROP:
171                         error = OF_nextprop(node, prop, buf, OPROMMAXPARAM);
172                         proplen = strlen(buf);
173                         break;
174                 }
175                 if (error != -1) {
176                         error = copyout(&proplen, &oprom->oprom_size,
177                             sizeof(proplen));
178                         if (error == 0)
179                                 error = copyout(buf, &oprom->oprom_array,
180                                     proplen + 1);
181                 } else
182                         error = EINVAL;
183                 break;
184         default:
185                 error = ENOIOCTL;
186                 break;
187         }
188
189         if (prop != NULL)
190                 free(prop, M_TEMP);
191         if (buf != NULL)
192                 free(buf, M_TEMP);
193
194         return (error);
195 }
196
197 static int
198 openprom_node_valid(phandle_t node)
199 {
200
201         if (node == 0)
202                 return (0);
203         return (openprom_node_search(OF_peer(0), node));
204 }
205
206 static int
207 openprom_node_search(phandle_t root, phandle_t node)
208 {
209         phandle_t child;
210
211         if (root == node)
212                 return (0);
213         for (child = OF_child(root); child != 0 && child != -1;
214             child = OF_peer(child))
215                 if (openprom_node_search(child, node) == 0)
216                         return (0);
217         return (EINVAL);
218 }
219
220 static int
221 openprom_modevent(module_t mode, int type, void *data)
222 {
223
224         switch (type) {
225         case MOD_LOAD:
226                 openprom_dev = make_dev(&openprom_cdevsw, 0, UID_ROOT,
227                     GID_WHEEL, 0600, "openprom");
228                 return (0);
229         case MOD_UNLOAD:
230                 destroy_dev(openprom_dev);
231                 return (0);
232         default:
233                 return (EOPNOTSUPP);
234         }
235 }
236
237 DEV_MODULE(openprom, openprom_modevent, NULL);