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