wsdisplay_compat_usl.c revision 1.9.2.1 1 /* $NetBSD: wsdisplay_compat_usl.c,v 1.9.2.1 1999/10/20 22:56:01 thorpej 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 /*
176 * Normally, this is called from the controlling process.
177 * Is is supposed to reply with a VT_RELDISP ioctl(), so
178 * it is not useful to tsleep() here.
179 */
180 sd->s_callback = callback;
181 sd->s_cbarg = cbarg;
182 sd->s_flags |= SF_DETACHPENDING;
183 psignal(sd->s_proc, sd->s_relsig);
184 timeout(usl_detachtimeout, sd, wscompat_usl_synctimeout * hz);
185
186 return (EAGAIN);
187 }
188
189 static int
190 usl_detachack(sd, ack)
191 struct usl_syncdata *sd;
192 int ack;
193 {
194 if (!(sd->s_flags & SF_DETACHPENDING)) {
195 printf("usl_detachack: not detaching\n");
196 return (EINVAL);
197 }
198
199 untimeout(usl_detachtimeout, sd);
200 sd->s_flags &= ~SF_DETACHPENDING;
201
202 if (sd->s_callback)
203 (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
204
205 return (0);
206 }
207
208 static void
209 usl_detachtimeout(arg)
210 void *arg;
211 {
212 struct usl_syncdata *sd = arg;
213
214 printf("usl_detachtimeout\n");
215
216 if (!(sd->s_flags & SF_DETACHPENDING)) {
217 printf("usl_detachtimeout: not detaching\n");
218 return;
219 }
220
221 sd->s_flags &= ~SF_DETACHPENDING;
222
223 if (sd->s_callback)
224 (*sd->s_callback)(sd->s_cbarg, EIO, 0);
225
226 (void) usl_sync_check(sd);
227 }
228
229 static int
230 usl_attachproc(cookie, waitok, callback, cbarg)
231 void *cookie;
232 int waitok;
233 void (*callback) __P((void *, int, int));
234 void *cbarg;
235 {
236 struct usl_syncdata *sd = cookie;
237
238 if (!usl_sync_check(sd))
239 return (0);
240
241 sd->s_callback = callback;
242 sd->s_cbarg = cbarg;
243 sd->s_flags |= SF_ATTACHPENDING;
244 psignal(sd->s_proc, sd->s_acqsig);
245 timeout(usl_attachtimeout, sd, wscompat_usl_synctimeout * hz);
246
247 return (EAGAIN);
248 }
249
250 static int
251 usl_attachack(sd, ack)
252 struct usl_syncdata *sd;
253 int ack;
254 {
255 if (!(sd->s_flags & SF_ATTACHPENDING)) {
256 printf("usl_attachack: not attaching\n");
257 return (EINVAL);
258 }
259
260 untimeout(usl_attachtimeout, sd);
261 sd->s_flags &= ~SF_ATTACHPENDING;
262
263 if (sd->s_callback)
264 (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
265
266 return (0);
267 }
268
269 static void
270 usl_attachtimeout(arg)
271 void *arg;
272 {
273 struct usl_syncdata *sd = arg;
274
275 printf("usl_attachtimeout\n");
276
277 if (!(sd->s_flags & SF_ATTACHPENDING)) {
278 printf("usl_attachtimeout: not attaching\n");
279 return;
280 }
281
282 sd->s_flags &= ~SF_ATTACHPENDING;
283
284 if (sd->s_callback)
285 (*sd->s_callback)(sd->s_cbarg, EIO, 0);
286
287 (void) usl_sync_check(sd);
288 }
289
290 int
291 wsdisplay_usl_ioctl1(sc, cmd, data, flag, p)
292 struct wsdisplay_softc *sc;
293 u_long cmd;
294 caddr_t data;
295 int flag;
296 struct proc *p;
297 {
298 int idx, maxidx;
299
300 switch (cmd) {
301 case VT_OPENQRY:
302 maxidx = wsdisplay_maxscreenidx(sc);
303 for (idx = 0; idx <= maxidx; idx++) {
304 if (wsdisplay_screenstate(sc, idx) == 0) {
305 *(int *)data = idx + 1;
306 return (0);
307 }
308 }
309 return (ENXIO);
310 case VT_GETACTIVE:
311 idx = wsdisplay_getactivescreen(sc);
312 *(int *)data = idx + 1;
313 return (0);
314 case VT_ACTIVATE:
315 idx = *(int *)data - 1;
316 return (wsdisplay_switch((struct device *)sc, idx, 1));
317 case VT_WAITACTIVE:
318 idx = *(int *)data - 1;
319 return (wsscreen_switchwait(sc, idx));
320 case VT_GETSTATE:
321 #define ss ((struct vt_stat *)data)
322 idx = wsdisplay_getactivescreen(sc);
323 ss->v_active = idx + 1;
324 ss->v_state = 0;
325 maxidx = wsdisplay_maxscreenidx(sc);
326 for (idx = 0; idx <= maxidx; idx++)
327 if (wsdisplay_screenstate(sc, idx) == EBUSY)
328 ss->v_state |= (1 << (idx + 1));
329 #undef s
330 return (0);
331
332 #ifdef WSDISPLAY_COMPAT_PCVT
333 case VGAPCVTID:
334 #define id ((struct pcvtid *)data)
335 strcpy(id->name, "pcvt");
336 id->rmajor = 3;
337 id->rminor = 32;
338 #undef id
339 return (0);
340 #endif
341 #ifdef WSDISPLAY_COMPAT_SYSCONS
342 case CONS_GETVERS:
343 *(int *)data = 0x200; /* version 2.0 */
344 return (0);
345 #endif
346
347 default:
348 return (-1);
349 }
350
351 return (0);
352 }
353
354 int
355 wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p)
356 struct wsdisplay_softc *sc;
357 struct wsscreen *scr;
358 u_long cmd;
359 caddr_t data;
360 int flag;
361 struct proc *p;
362 {
363 int res;
364 struct usl_syncdata *sd;
365 int req, intarg;
366 struct wskbd_bell_data bd;
367 void *arg;
368
369 switch (cmd) {
370 case VT_SETMODE:
371 #define newmode ((struct vt_mode *)data)
372 if (newmode->mode == VT_PROCESS) {
373 res = usl_sync_init(scr, &sd, p, newmode->acqsig,
374 newmode->relsig, newmode->frsig);
375 if (res)
376 return (res);
377 } else {
378 sd = usl_sync_get(scr);
379 if (sd)
380 usl_sync_done(sd);
381 }
382 #undef newmode
383 return (0);
384 case VT_GETMODE:
385 #define cmode ((struct vt_mode *)data)
386 sd = usl_sync_get(scr);
387 if (sd) {
388 cmode->mode = VT_PROCESS;
389 cmode->relsig = sd->s_relsig;
390 cmode->acqsig = sd->s_acqsig;
391 cmode->frsig = sd->s_frsig;
392 } else
393 cmode->mode = VT_AUTO;
394 #undef cmode
395 return (0);
396 case VT_RELDISP:
397 #define d (*(int *)data)
398 sd = usl_sync_get(scr);
399 if (!sd)
400 return (EINVAL);
401 switch (d) {
402 case VT_FALSE:
403 case VT_TRUE:
404 return (usl_detachack(sd, (d == VT_TRUE)));
405 case VT_ACKACQ:
406 return (usl_attachack(sd, 1));
407 default:
408 return (EINVAL);
409 }
410 #undef d
411 return (0);
412
413 case KDENABIO:
414 if (suser(p->p_ucred, &p->p_acflag) || securelevel > 1)
415 return (EPERM);
416 /* FALLTHRU */
417 case KDDISABIO:
418 #if defined(__i386__)
419 #if defined(COMPAT_10) || defined(COMPAT_11) || defined(COMPAT_FREEBSD)
420 {
421 struct trapframe *fp = (struct trapframe *)p->p_md.md_regs;
422 if (cmd == KDENABIO)
423 fp->tf_eflags |= PSL_IOPL;
424 else
425 fp->tf_eflags &= ~PSL_IOPL;
426 }
427 #endif
428 #endif
429 return (0);
430 case KDSETRAD:
431 /* XXX ignore for now */
432 return (0);
433
434 default:
435 return (-1);
436
437 /*
438 * the following are converted to wsdisplay ioctls
439 */
440 case KDSETMODE:
441 req = WSDISPLAYIO_SMODE;
442 #define d (*(int *)data)
443 switch (d) {
444 case KD_GRAPHICS:
445 intarg = WSDISPLAYIO_MODE_MAPPED;
446 break;
447 case KD_TEXT:
448 intarg = WSDISPLAYIO_MODE_EMUL;
449 break;
450 default:
451 return (EINVAL);
452 }
453 #undef d
454 arg = &intarg;
455 break;
456 case KDMKTONE:
457 req = WSKBDIO_COMPLEXBELL;
458 #define d (*(int *)data)
459 if (d) {
460 #define PCVT_SYSBEEPF 1193182
461 if (d >> 16) {
462 bd.which = WSKBD_BELL_DOPERIOD;
463 bd.period = d >> 16; /* ms */
464 }
465 else
466 bd.which = 0;
467 if (d & 0xffff) {
468 bd.which |= WSKBD_BELL_DOPITCH;
469 bd.pitch = PCVT_SYSBEEPF/(d & 0xffff); /* Hz */
470 }
471 } else
472 bd.which = 0; /* default */
473 #undef d
474 arg = &bd;
475 break;
476 case KDSETLED:
477 req = WSKBDIO_SETLEDS;
478 intarg = 0;
479 #define d (*(int *)data)
480 if (d & LED_CAP)
481 intarg |= WSKBD_LED_CAPS;
482 if (d & LED_NUM)
483 intarg |= WSKBD_LED_NUM;
484 if (d & LED_SCR)
485 intarg |= WSKBD_LED_SCROLL;
486 #undef d
487 arg = &intarg;
488 break;
489 case KDGETLED:
490 req = WSKBDIO_GETLEDS;
491 arg = &intarg;
492 break;
493 #ifdef WSDISPLAY_COMPAT_RAWKBD
494 case KDSKBMODE:
495 req = WSKBDIO_SETMODE;
496 switch (*(int *)data) {
497 case K_RAW:
498 intarg = WSKBD_RAW;
499 break;
500 case K_XLATE:
501 intarg = WSKBD_TRANSLATED;
502 break;
503 default:
504 return (EINVAL);
505 }
506 arg = &intarg;
507 break;
508 case KDGKBMODE:
509 req = WSKBDIO_GETMODE;
510 arg = &intarg;
511 break;
512 #endif
513 }
514
515 res = wsdisplay_internal_ioctl(sc, scr, req, arg, flag, p);
516 if (res)
517 return (res);
518
519 switch (cmd) {
520 case KDGETLED:
521 #define d (*(int *)data)
522 d = 0;
523 if (intarg & WSKBD_LED_CAPS)
524 d |= LED_CAP;
525 if (intarg & WSKBD_LED_NUM)
526 d |= LED_NUM;
527 if (intarg & WSKBD_LED_SCROLL)
528 d |= LED_SCR;
529 #undef d
530 break;
531 #ifdef WSDISPLAY_COMPAT_RAWKBD
532 case KDGKBMODE:
533 *(int *)data = (intarg == WSKBD_RAW ? K_RAW : K_XLATE);
534 break;
535 #endif
536 }
537
538 return (0);
539 }
540