Line data Source code
1 : /* $OpenBSD: wsdisplay_compat_usl.c,v 1.32 2017/01/23 04:43:46 deraadt Exp $ */
2 : /* $NetBSD: wsdisplay_compat_usl.c,v 1.12 2000/03/23 07:01:47 thorpej Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1998
6 : * Matthias Drochner. All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : *
28 : */
29 :
30 : #include <sys/param.h>
31 : #include <sys/systm.h>
32 : #include <sys/timeout.h>
33 : #include <sys/kernel.h>
34 : #include <sys/proc.h>
35 : #include <sys/signalvar.h>
36 : #include <sys/malloc.h>
37 : #include <sys/errno.h>
38 : #include <sys/fcntl.h>
39 :
40 : #include <dev/wscons/wsconsio.h>
41 : #include <dev/wscons/wsdisplayvar.h>
42 : #include <dev/wscons/wscons_callbacks.h>
43 : #include <dev/wscons/wsdisplay_usl_io.h>
44 :
45 : #ifdef WSDISPLAY_DEBUG
46 : #define DPRINTF(x) if (wsdisplaydebug) printf x
47 : int wsdisplaydebug = 0;
48 : #else
49 : #define DPRINTF(x)
50 : #endif
51 :
52 : struct usl_syncdata {
53 : struct wsscreen *s_scr;
54 : struct process *s_process;
55 : pid_t s_pid;
56 : int s_flags;
57 : #define SF_DETACHPENDING 1
58 : #define SF_ATTACHPENDING 2
59 : int s_acqsig, s_relsig;
60 : int s_frsig; /* unused */
61 : void (*s_callback)(void *, int, int);
62 : void *s_cbarg;
63 : struct timeout s_attach_ch;
64 : struct timeout s_detach_ch;
65 : };
66 :
67 : int usl_sync_init(struct wsscreen *, struct usl_syncdata **,
68 : struct process *, int, int, int);
69 : void usl_sync_done(struct usl_syncdata *);
70 : int usl_sync_check(struct usl_syncdata *);
71 : struct usl_syncdata *usl_sync_get(struct wsscreen *);
72 :
73 : int usl_detachproc(void *, int, void (*)(void *, int, int), void *);
74 : int usl_detachack(struct usl_syncdata *, int);
75 : void usl_detachtimeout(void *);
76 : int usl_attachproc(void *, int, void (*)(void *, int, int), void *);
77 : int usl_attachack(struct usl_syncdata *, int);
78 : void usl_attachtimeout(void *);
79 :
80 : static const struct wscons_syncops usl_syncops = {
81 : usl_detachproc,
82 : usl_attachproc,
83 : #define _usl_sync_check ((int (*)(void *))usl_sync_check)
84 : _usl_sync_check,
85 : #define _usl_sync_destroy ((void (*)(void *))usl_sync_done)
86 : _usl_sync_destroy
87 : };
88 :
89 : #ifndef WSCOMPAT_USL_SYNCTIMEOUT
90 : #define WSCOMPAT_USL_SYNCTIMEOUT 5 /* seconds */
91 : #endif
92 : static int wscompat_usl_synctimeout = WSCOMPAT_USL_SYNCTIMEOUT;
93 :
94 : int
95 0 : usl_sync_init(struct wsscreen *scr, struct usl_syncdata **sdp,
96 : struct process *pr, int acqsig, int relsig, int frsig)
97 : {
98 : struct usl_syncdata *sd;
99 : int res;
100 :
101 0 : if (acqsig <= 0 || acqsig >= NSIG || relsig <= 0 || relsig >= NSIG ||
102 0 : frsig <= 0 || frsig >= NSIG)
103 0 : return (EINVAL);
104 0 : sd = malloc(sizeof(*sd), M_DEVBUF, M_NOWAIT);
105 0 : if (!sd)
106 0 : return (ENOMEM);
107 0 : sd->s_scr = scr;
108 0 : sd->s_process = pr;
109 0 : sd->s_pid = pr->ps_pid;
110 0 : sd->s_flags = 0;
111 0 : sd->s_acqsig = acqsig;
112 0 : sd->s_relsig = relsig;
113 0 : sd->s_frsig = frsig;
114 0 : timeout_set(&sd->s_attach_ch, usl_attachtimeout, sd);
115 0 : timeout_set(&sd->s_detach_ch, usl_detachtimeout, sd);
116 0 : res = wsscreen_attach_sync(scr, &usl_syncops, sd);
117 0 : if (res) {
118 0 : free(sd, M_DEVBUF, sizeof(*sd));
119 0 : return (res);
120 : }
121 0 : *sdp = sd;
122 0 : return (0);
123 0 : }
124 :
125 : void
126 0 : usl_sync_done(struct usl_syncdata *sd)
127 : {
128 0 : if (sd->s_flags & SF_DETACHPENDING) {
129 0 : timeout_del(&sd->s_detach_ch);
130 0 : (*sd->s_callback)(sd->s_cbarg, 0, 0);
131 0 : }
132 0 : if (sd->s_flags & SF_ATTACHPENDING) {
133 0 : timeout_del(&sd->s_attach_ch);
134 0 : (*sd->s_callback)(sd->s_cbarg, ENXIO, 0);
135 0 : }
136 0 : wsscreen_detach_sync(sd->s_scr);
137 0 : free(sd, M_DEVBUF, sizeof(*sd));
138 0 : }
139 :
140 : int
141 0 : usl_sync_check(struct usl_syncdata *sd)
142 : {
143 0 : if (sd->s_process == prfind(sd->s_pid))
144 0 : return (1);
145 : DPRINTF(("usl_sync_check: process %d died\n", sd->s_pid));
146 0 : usl_sync_done(sd);
147 0 : return (0);
148 0 : }
149 :
150 : struct usl_syncdata *
151 0 : usl_sync_get(struct wsscreen *scr)
152 : {
153 0 : struct usl_syncdata *sd;
154 :
155 0 : if (wsscreen_lookup_sync(scr, &usl_syncops, (void **)&sd))
156 0 : return (0);
157 0 : return (sd);
158 0 : }
159 :
160 : int
161 0 : usl_detachproc(void *cookie, int waitok, void (*callback)(void *, int, int),
162 : void *cbarg)
163 : {
164 0 : struct usl_syncdata *sd = cookie;
165 :
166 0 : if (!usl_sync_check(sd))
167 0 : return (0);
168 :
169 : /* we really need a callback */
170 0 : if (!callback)
171 0 : return (EINVAL);
172 :
173 : /*
174 : * Normally, this is called from the controlling process.
175 : * It is supposed to reply with a VT_RELDISP ioctl(), so
176 : * it is not useful to tsleep() here.
177 : */
178 0 : sd->s_callback = callback;
179 0 : sd->s_cbarg = cbarg;
180 0 : sd->s_flags |= SF_DETACHPENDING;
181 0 : prsignal(sd->s_process, sd->s_relsig);
182 0 : timeout_add_sec(&sd->s_detach_ch, wscompat_usl_synctimeout);
183 :
184 0 : return (EAGAIN);
185 0 : }
186 :
187 : int
188 0 : usl_detachack(struct usl_syncdata *sd, int ack)
189 : {
190 0 : if (!(sd->s_flags & SF_DETACHPENDING)) {
191 : DPRINTF(("usl_detachack: not detaching\n"));
192 0 : return (EINVAL);
193 : }
194 :
195 0 : timeout_del(&sd->s_detach_ch);
196 0 : sd->s_flags &= ~SF_DETACHPENDING;
197 :
198 0 : if (sd->s_callback)
199 0 : (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
200 :
201 0 : return (0);
202 0 : }
203 :
204 : void
205 0 : usl_detachtimeout(void *arg)
206 : {
207 0 : struct usl_syncdata *sd = arg;
208 :
209 : DPRINTF(("usl_detachtimeout\n"));
210 :
211 0 : if (!(sd->s_flags & SF_DETACHPENDING)) {
212 : DPRINTF(("usl_detachtimeout: not detaching\n"));
213 0 : return;
214 : }
215 :
216 0 : sd->s_flags &= ~SF_DETACHPENDING;
217 :
218 0 : if (sd->s_callback)
219 0 : (*sd->s_callback)(sd->s_cbarg, EIO, 0);
220 :
221 0 : (void) usl_sync_check(sd);
222 0 : }
223 :
224 : int
225 0 : usl_attachproc(void *cookie, int waitok, void (*callback)(void *, int, int),
226 : void *cbarg)
227 : {
228 0 : struct usl_syncdata *sd = cookie;
229 :
230 0 : if (!usl_sync_check(sd))
231 0 : return (0);
232 :
233 : /* we really need a callback */
234 0 : if (!callback)
235 0 : return (EINVAL);
236 :
237 0 : sd->s_callback = callback;
238 0 : sd->s_cbarg = cbarg;
239 0 : sd->s_flags |= SF_ATTACHPENDING;
240 0 : prsignal(sd->s_process, sd->s_acqsig);
241 0 : timeout_add_sec(&sd->s_attach_ch, wscompat_usl_synctimeout);
242 :
243 0 : return (EAGAIN);
244 0 : }
245 :
246 : int
247 0 : usl_attachack(struct usl_syncdata *sd, int ack)
248 : {
249 0 : if (!(sd->s_flags & SF_ATTACHPENDING)) {
250 : DPRINTF(("usl_attachack: not attaching\n"));
251 0 : return (EINVAL);
252 : }
253 :
254 0 : timeout_del(&sd->s_attach_ch);
255 0 : sd->s_flags &= ~SF_ATTACHPENDING;
256 :
257 0 : if (sd->s_callback)
258 0 : (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
259 :
260 0 : return (0);
261 0 : }
262 :
263 : void
264 0 : usl_attachtimeout(void *arg)
265 : {
266 0 : struct usl_syncdata *sd = arg;
267 :
268 : DPRINTF(("usl_attachtimeout\n"));
269 :
270 0 : if (!(sd->s_flags & SF_ATTACHPENDING)) {
271 : DPRINTF(("usl_attachtimeout: not attaching\n"));
272 0 : return;
273 : }
274 :
275 0 : sd->s_flags &= ~SF_ATTACHPENDING;
276 :
277 0 : if (sd->s_callback)
278 0 : (*sd->s_callback)(sd->s_cbarg, EIO, 0);
279 :
280 0 : (void) usl_sync_check(sd);
281 0 : }
282 :
283 : int
284 0 : wsdisplay_usl_ioctl1(struct wsdisplay_softc *sc, u_long cmd, caddr_t data,
285 : int flag, struct proc *p)
286 : {
287 : int idx, maxidx;
288 :
289 0 : switch (cmd) {
290 : case VT_OPENQRY:
291 0 : maxidx = wsdisplay_maxscreenidx(sc);
292 0 : for (idx = 0; idx <= maxidx; idx++) {
293 0 : if (wsdisplay_screenstate(sc, idx) == 0) {
294 0 : *(int *)data = idx + 1;
295 0 : return (0);
296 : }
297 : }
298 0 : return (ENXIO);
299 : case VT_GETACTIVE:
300 0 : idx = wsdisplay_getactivescreen(sc);
301 0 : *(int *)data = idx + 1;
302 0 : return (0);
303 : case VT_ACTIVATE:
304 0 : if ((flag & FWRITE) == 0)
305 0 : return (EACCES);
306 0 : idx = *(int *)data - 1;
307 0 : if (idx < 0)
308 0 : return (EINVAL);
309 0 : return (wsdisplay_switch((struct device *)sc, idx, 1));
310 : case VT_WAITACTIVE:
311 0 : if ((flag & FWRITE) == 0)
312 0 : return (EACCES);
313 0 : idx = *(int *)data - 1;
314 0 : if (idx < 0)
315 0 : return (EINVAL);
316 0 : return (wsscreen_switchwait(sc, idx));
317 : case VT_GETSTATE:
318 : #define ss ((struct vt_stat *)data)
319 0 : idx = wsdisplay_getactivescreen(sc);
320 0 : ss->v_active = idx + 1;
321 0 : ss->v_state = 0;
322 0 : maxidx = wsdisplay_maxscreenidx(sc);
323 0 : for (idx = 0; idx <= maxidx; idx++)
324 0 : if (wsdisplay_screenstate(sc, idx) == EBUSY)
325 0 : ss->v_state |= (1 << (idx + 1));
326 : #undef ss
327 0 : return (0);
328 :
329 : default:
330 0 : return (-1);
331 : }
332 :
333 : return (0);
334 0 : }
335 :
336 : int
337 0 : wsdisplay_usl_ioctl2(struct wsdisplay_softc *sc, struct wsscreen *scr,
338 : u_long cmd, caddr_t data, int flag, struct proc *p)
339 : {
340 0 : int intarg, res;
341 : u_long req;
342 : void *arg;
343 0 : struct usl_syncdata *sd;
344 0 : struct wskbd_bell_data bd;
345 :
346 0 : switch (cmd) {
347 : case VT_SETMODE:
348 0 : if ((flag & FWRITE) == 0)
349 0 : return (EACCES);
350 : #define newmode ((struct vt_mode *)data)
351 0 : if (newmode->mode == VT_PROCESS) {
352 0 : res = usl_sync_init(scr, &sd, p->p_p, newmode->acqsig,
353 0 : newmode->relsig, newmode->frsig);
354 0 : if (res)
355 0 : return (res);
356 : } else {
357 0 : sd = usl_sync_get(scr);
358 0 : if (sd)
359 0 : usl_sync_done(sd);
360 : }
361 : #undef newmode
362 0 : return (0);
363 : case VT_GETMODE:
364 : #define cmode ((struct vt_mode *)data)
365 0 : sd = usl_sync_get(scr);
366 0 : if (sd) {
367 0 : cmode->mode = VT_PROCESS;
368 0 : cmode->relsig = sd->s_relsig;
369 0 : cmode->acqsig = sd->s_acqsig;
370 0 : cmode->frsig = sd->s_frsig;
371 0 : } else
372 0 : cmode->mode = VT_AUTO;
373 : #undef cmode
374 0 : return (0);
375 : case VT_RELDISP:
376 0 : if ((flag & FWRITE) == 0)
377 0 : return (EACCES);
378 : #define d (*(int *)data)
379 0 : sd = usl_sync_get(scr);
380 0 : if (!sd)
381 0 : return (EINVAL);
382 0 : switch (d) {
383 : case VT_FALSE:
384 : case VT_TRUE:
385 0 : return (usl_detachack(sd, (d == VT_TRUE)));
386 : case VT_ACKACQ:
387 0 : return (usl_attachack(sd, 1));
388 : default:
389 0 : return (EINVAL);
390 : }
391 : #undef d
392 : return (0);
393 :
394 : case KDENABIO:
395 : case KDDISABIO:
396 0 : if ((flag & FWRITE) == 0)
397 0 : return (EACCES);
398 : /*
399 : * This is a lie, but non-x86 platforms are not supposed to
400 : * issue these ioctls anyway.
401 : */
402 0 : return (0);
403 :
404 : case KDSETRAD:
405 0 : if ((flag & FWRITE) == 0)
406 0 : return (EACCES);
407 : /* XXX ignore for now */
408 0 : return (0);
409 :
410 : default:
411 0 : return (-1);
412 :
413 : /*
414 : * the following are converted to wsdisplay ioctls
415 : */
416 : case KDSETMODE:
417 0 : if ((flag & FWRITE) == 0)
418 0 : return (EACCES);
419 : req = WSDISPLAYIO_SMODE;
420 : #define d (*(int *)data)
421 0 : switch (d) {
422 : case KD_GRAPHICS:
423 0 : intarg = WSDISPLAYIO_MODE_MAPPED;
424 0 : break;
425 : case KD_TEXT:
426 0 : intarg = WSDISPLAYIO_MODE_EMUL;
427 0 : break;
428 : default:
429 0 : return (EINVAL);
430 : }
431 : #undef d
432 : arg = &intarg;
433 0 : break;
434 : case KDMKTONE:
435 0 : if ((flag & FWRITE) == 0)
436 0 : return (EACCES);
437 : req = WSKBDIO_COMPLEXBELL;
438 : #define d (*(int *)data)
439 0 : if (d) {
440 : #define PCVT_SYSBEEPF 1193182
441 0 : if (d >> 16) {
442 0 : bd.which = WSKBD_BELL_DOPERIOD;
443 0 : bd.period = d >> 16; /* ms */
444 0 : }
445 : else
446 0 : bd.which = 0;
447 0 : if (d & 0xffff) {
448 0 : bd.which |= WSKBD_BELL_DOPITCH;
449 0 : bd.pitch = PCVT_SYSBEEPF/(d & 0xffff); /* Hz */
450 0 : }
451 : } else
452 0 : bd.which = 0; /* default */
453 : #undef d
454 : arg = &bd;
455 0 : break;
456 : case KDSETLED:
457 0 : if ((flag & FWRITE) == 0)
458 0 : return (EACCES);
459 : req = WSKBDIO_SETLEDS;
460 0 : intarg = 0;
461 : #define d (*(int *)data)
462 0 : if (d & LED_CAP)
463 0 : intarg |= WSKBD_LED_CAPS;
464 0 : if (d & LED_NUM)
465 0 : intarg |= WSKBD_LED_NUM;
466 0 : if (d & LED_SCR)
467 0 : intarg |= WSKBD_LED_SCROLL;
468 : #undef d
469 : arg = &intarg;
470 0 : break;
471 : case KDGETLED:
472 : req = WSKBDIO_GETLEDS;
473 : arg = &intarg;
474 0 : break;
475 : #ifdef WSDISPLAY_COMPAT_RAWKBD
476 : case KDSKBMODE:
477 0 : if ((flag & FWRITE) == 0)
478 0 : return (EACCES);
479 : req = WSKBDIO_SETMODE;
480 0 : switch (*(int *)data) {
481 : case K_RAW:
482 0 : intarg = WSKBD_RAW;
483 0 : break;
484 : case K_XLATE:
485 0 : intarg = WSKBD_TRANSLATED;
486 0 : break;
487 : default:
488 0 : return (EINVAL);
489 : }
490 : arg = &intarg;
491 0 : break;
492 : case KDGKBMODE:
493 : req = WSKBDIO_GETMODE;
494 : arg = &intarg;
495 0 : break;
496 : #endif
497 : }
498 :
499 0 : res = wsdisplay_internal_ioctl(sc, scr, req, arg, flag, p);
500 0 : if (res)
501 0 : return (res);
502 :
503 0 : switch (cmd) {
504 : case KDGETLED:
505 : #define d (*(int *)data)
506 0 : d = 0;
507 0 : if (intarg & WSKBD_LED_CAPS)
508 0 : d |= LED_CAP;
509 0 : if (intarg & WSKBD_LED_NUM)
510 0 : d |= LED_NUM;
511 0 : if (intarg & WSKBD_LED_SCROLL)
512 0 : d |= LED_SCR;
513 : #undef d
514 : break;
515 : #ifdef WSDISPLAY_COMPAT_RAWKBD
516 : case KDGKBMODE:
517 0 : *(int *)data = (intarg == WSKBD_RAW ? K_RAW : K_XLATE);
518 0 : break;
519 : #endif
520 : }
521 :
522 0 : return (0);
523 0 : }
|