wsdisplay_compat_usl.c revision 1.9 1 /* $NetBSD: wsdisplay_compat_usl.c,v 1.9 1999/05/30 21:13:04 christos 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_ioctl(sc, scr, cmd, data, flag, p)
292 struct wsdisplay_softc *sc;
293 struct wsscreen *scr;
294 u_long cmd;
295 caddr_t data;
296 int flag;
297 struct proc *p;
298 {
299 int res, idx, maxidx;
300 struct usl_syncdata *sd;
301 int req, intarg;
302 struct wskbd_bell_data bd;
303 void *arg;
304
305 switch (cmd) {
306 case VT_SETMODE:
307 #define newmode ((struct vt_mode *)data)
308 if (newmode->mode == VT_PROCESS) {
309 res = usl_sync_init(scr, &sd, p, newmode->acqsig,
310 newmode->relsig, newmode->frsig);
311 if (res)
312 return (res);
313 } else {
314 sd = usl_sync_get(scr);
315 if (sd)
316 usl_sync_done(sd);
317 }
318 #undef newmode
319 return (0);
320 case VT_GETMODE:
321 #define cmode ((struct vt_mode *)data)
322 sd = usl_sync_get(scr);
323 if (sd) {
324 cmode->mode = VT_PROCESS;
325 cmode->relsig = sd->s_relsig;
326 cmode->acqsig = sd->s_acqsig;
327 cmode->frsig = sd->s_frsig;
328 } else
329 cmode->mode = VT_AUTO;
330 #undef cmode
331 return (0);
332 case VT_RELDISP:
333 #define d (*(int *)data)
334 sd = usl_sync_get(scr);
335 if (!sd)
336 return (EINVAL);
337 switch (d) {
338 case VT_FALSE:
339 case VT_TRUE:
340 return (usl_detachack(sd, (d == VT_TRUE)));
341 case VT_ACKACQ:
342 return (usl_attachack(sd, 1));
343 default:
344 return (EINVAL);
345 }
346 #undef d
347 return (0);
348 case VT_OPENQRY:
349 maxidx = wsdisplay_maxscreenidx(sc);
350 for (idx = 0; idx <= maxidx; idx++) {
351 if (wsdisplay_screenstate(sc, idx) == 0) {
352 *(int *)data = idx + 1;
353 return (0);
354 }
355 }
356 return (ENXIO);
357 case VT_GETACTIVE:
358 idx = wsdisplay_getactivescreen(sc);
359 *(int *)data = idx + 1;
360 return (0);
361 case VT_ACTIVATE:
362 idx = *(int *)data - 1;
363 return (wsdisplay_switch((struct device *)sc, idx, 1));
364 case VT_WAITACTIVE:
365 idx = *(int *)data - 1;
366 return (wsscreen_switchwait(sc, idx));
367 case VT_GETSTATE:
368 #define ss ((struct vt_stat *)data)
369 idx = wsdisplay_getactivescreen(sc);
370 ss->v_active = idx + 1;
371 ss->v_state = 0;
372 maxidx = wsdisplay_maxscreenidx(sc);
373 for (idx = 0; idx <= maxidx; idx++)
374 if (wsdisplay_screenstate(sc, idx) == EBUSY)
375 ss->v_state |= (1 << (idx + 1));
376 #undef s
377 return (0);
378 case KDENABIO:
379 if (suser(p->p_ucred, &p->p_acflag) || securelevel > 1)
380 return (EPERM);
381 /* FALLTHRU */
382 case KDDISABIO:
383 #if defined(__i386__)
384 #if defined(COMPAT_10) || defined(COMPAT_11) || defined(COMPAT_FREEBSD)
385 {
386 struct trapframe *fp = (struct trapframe *)p->p_md.md_regs;
387 if (cmd == KDENABIO)
388 fp->tf_eflags |= PSL_IOPL;
389 else
390 fp->tf_eflags &= ~PSL_IOPL;
391 }
392 #endif
393 #endif
394 return (0);
395 case KDSETRAD:
396 /* XXX ignore for now */
397 return (0);
398
399 #ifdef WSDISPLAY_COMPAT_PCVT
400 case VGAPCVTID:
401 #define id ((struct pcvtid *)data)
402 strcpy(id->name, "pcvt");
403 id->rmajor = 3;
404 id->rminor = 32;
405 #undef id
406 return (0);
407 #endif
408 #ifdef WSDISPLAY_COMPAT_SYSCONS
409 case CONS_GETVERS:
410 *(int *)data = 0x200; /* version 2.0 */
411 return (0);
412 #endif
413
414 default:
415 return (-1);
416
417 /*
418 * the following are converted to wsdisplay ioctls
419 */
420 case KDSETMODE:
421 req = WSDISPLAYIO_SMODE;
422 #define d (*(int *)data)
423 switch (d) {
424 case KD_GRAPHICS:
425 intarg = WSDISPLAYIO_MODE_MAPPED;
426 break;
427 case KD_TEXT:
428 intarg = WSDISPLAYIO_MODE_EMUL;
429 break;
430 default:
431 return (EINVAL);
432 }
433 #undef d
434 arg = &intarg;
435 break;
436 case KDMKTONE:
437 req = WSKBDIO_COMPLEXBELL;
438 #define d (*(int *)data)
439 if (d) {
440 #define PCVT_SYSBEEPF 1193182
441 if (d >> 16) {
442 bd.which = WSKBD_BELL_DOPERIOD;
443 bd.period = d >> 16; /* ms */
444 }
445 else
446 bd.which = 0;
447 if (d & 0xffff) {
448 bd.which |= WSKBD_BELL_DOPITCH;
449 bd.pitch = PCVT_SYSBEEPF/(d & 0xffff); /* Hz */
450 }
451 } else
452 bd.which = 0; /* default */
453 #undef d
454 arg = &bd;
455 break;
456 case KDSETLED:
457 req = WSKBDIO_SETLEDS;
458 intarg = 0;
459 #define d (*(int *)data)
460 if (d & LED_CAP)
461 intarg |= WSKBD_LED_CAPS;
462 if (d & LED_NUM)
463 intarg |= WSKBD_LED_NUM;
464 if (d & LED_SCR)
465 intarg |= WSKBD_LED_SCROLL;
466 #undef d
467 arg = &intarg;
468 break;
469 case KDGETLED:
470 req = WSKBDIO_GETLEDS;
471 arg = &intarg;
472 break;
473 #ifdef WSDISPLAY_COMPAT_RAWKBD
474 case KDSKBMODE:
475 req = WSKBDIO_SETMODE;
476 switch (*(int *)data) {
477 case K_RAW:
478 intarg = WSKBD_RAW;
479 break;
480 case K_XLATE:
481 intarg = WSKBD_TRANSLATED;
482 break;
483 default:
484 return (EINVAL);
485 }
486 arg = &intarg;
487 break;
488 case KDGKBMODE:
489 req = WSKBDIO_GETMODE;
490 arg = &intarg;
491 break;
492 #endif
493 }
494
495 res = wsdisplay_internal_ioctl(sc, scr, req, arg, flag, p);
496 if (res)
497 return (res);
498
499 switch (cmd) {
500 case KDGETLED:
501 #define d (*(int *)data)
502 d = 0;
503 if (intarg & WSKBD_LED_CAPS)
504 d |= LED_CAP;
505 if (intarg & WSKBD_LED_NUM)
506 d |= LED_NUM;
507 if (intarg & WSKBD_LED_SCROLL)
508 d |= LED_SCR;
509 #undef d
510 break;
511 #ifdef WSDISPLAY_COMPAT_RAWKBD
512 case KDGKBMODE:
513 *(int *)data = (intarg == WSKBD_RAW ? K_RAW : K_XLATE);
514 break;
515 #endif
516 }
517
518 return (0);
519 }
520