Annotation of sys/dev/wscons/wsdisplay_compat_usl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: wsdisplay_compat_usl.c,v 1.19 2007/02/14 01:12:16 jsg 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/ioctl.h>
! 34: #include <sys/kernel.h>
! 35: #include <sys/proc.h>
! 36: #include <sys/signalvar.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/errno.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 proc *s_proc;
! 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 proc *, 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: usl_sync_init(scr, sdp, p, acqsig, relsig, frsig)
! 96: struct wsscreen *scr;
! 97: struct usl_syncdata **sdp;
! 98: struct proc *p;
! 99: int acqsig, relsig, frsig;
! 100: {
! 101: struct usl_syncdata *sd;
! 102: int res;
! 103:
! 104: if (acqsig <= 0 || acqsig >= NSIG || relsig <= 0 || relsig >= NSIG ||
! 105: frsig <= 0 || frsig >= NSIG)
! 106: return (EINVAL);
! 107: sd = malloc(sizeof(struct usl_syncdata), M_DEVBUF, M_NOWAIT);
! 108: if (!sd)
! 109: return (ENOMEM);
! 110: sd->s_scr = scr;
! 111: sd->s_proc = p;
! 112: sd->s_pid = p->p_pid;
! 113: sd->s_flags = 0;
! 114: sd->s_acqsig = acqsig;
! 115: sd->s_relsig = relsig;
! 116: sd->s_frsig = frsig;
! 117: timeout_set(&sd->s_attach_ch, usl_attachtimeout, sd);
! 118: timeout_set(&sd->s_detach_ch, usl_detachtimeout, sd);
! 119: res = wsscreen_attach_sync(scr, &usl_syncops, sd);
! 120: if (res) {
! 121: free(sd, M_DEVBUF);
! 122: return (res);
! 123: }
! 124: *sdp = sd;
! 125: return (0);
! 126: }
! 127:
! 128: void
! 129: usl_sync_done(sd)
! 130: struct usl_syncdata *sd;
! 131: {
! 132: if (sd->s_flags & SF_DETACHPENDING) {
! 133: timeout_del(&sd->s_detach_ch);
! 134: (*sd->s_callback)(sd->s_cbarg, 0, 0);
! 135: }
! 136: if (sd->s_flags & SF_ATTACHPENDING) {
! 137: timeout_del(&sd->s_attach_ch);
! 138: (*sd->s_callback)(sd->s_cbarg, ENXIO, 0);
! 139: }
! 140: wsscreen_detach_sync(sd->s_scr);
! 141: free(sd, M_DEVBUF);
! 142: }
! 143:
! 144: int
! 145: usl_sync_check(sd)
! 146: struct usl_syncdata *sd;
! 147: {
! 148: if (sd->s_proc == pfind(sd->s_pid))
! 149: return (1);
! 150: DPRINTF(("usl_sync_check: process %d died\n", sd->s_pid));
! 151: usl_sync_done(sd);
! 152: return (0);
! 153: }
! 154:
! 155: struct usl_syncdata *
! 156: usl_sync_get(scr)
! 157: struct wsscreen *scr;
! 158: {
! 159: struct usl_syncdata *sd;
! 160:
! 161: if (wsscreen_lookup_sync(scr, &usl_syncops, (void **)&sd))
! 162: return (0);
! 163: return (sd);
! 164: }
! 165:
! 166: int
! 167: usl_detachproc(cookie, waitok, callback, cbarg)
! 168: void *cookie;
! 169: int waitok;
! 170: void (*callback)(void *, int, int);
! 171: void *cbarg;
! 172: {
! 173: struct usl_syncdata *sd = cookie;
! 174:
! 175: if (!usl_sync_check(sd))
! 176: return (0);
! 177:
! 178: /* we really need a callback */
! 179: if (!callback)
! 180: return (EINVAL);
! 181:
! 182: /*
! 183: * Normally, this is called from the controlling process.
! 184: * It is supposed to reply with a VT_RELDISP ioctl(), so
! 185: * it is not useful to tsleep() here.
! 186: */
! 187: sd->s_callback = callback;
! 188: sd->s_cbarg = cbarg;
! 189: sd->s_flags |= SF_DETACHPENDING;
! 190: psignal(sd->s_proc, sd->s_relsig);
! 191: timeout_add(&sd->s_detach_ch, wscompat_usl_synctimeout * hz);
! 192:
! 193: return (EAGAIN);
! 194: }
! 195:
! 196: int
! 197: usl_detachack(sd, ack)
! 198: struct usl_syncdata *sd;
! 199: int ack;
! 200: {
! 201: if (!(sd->s_flags & SF_DETACHPENDING)) {
! 202: DPRINTF(("usl_detachack: not detaching\n"));
! 203: return (EINVAL);
! 204: }
! 205:
! 206: timeout_del(&sd->s_detach_ch);
! 207: sd->s_flags &= ~SF_DETACHPENDING;
! 208:
! 209: if (sd->s_callback)
! 210: (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
! 211:
! 212: return (0);
! 213: }
! 214:
! 215: void
! 216: usl_detachtimeout(arg)
! 217: void *arg;
! 218: {
! 219: struct usl_syncdata *sd = arg;
! 220:
! 221: DPRINTF(("usl_detachtimeout\n"));
! 222:
! 223: if (!(sd->s_flags & SF_DETACHPENDING)) {
! 224: DPRINTF(("usl_detachtimeout: not detaching\n"));
! 225: return;
! 226: }
! 227:
! 228: sd->s_flags &= ~SF_DETACHPENDING;
! 229:
! 230: if (sd->s_callback)
! 231: (*sd->s_callback)(sd->s_cbarg, EIO, 0);
! 232:
! 233: (void) usl_sync_check(sd);
! 234: }
! 235:
! 236: int
! 237: usl_attachproc(cookie, waitok, callback, cbarg)
! 238: void *cookie;
! 239: int waitok;
! 240: void (*callback)(void *, int, int);
! 241: void *cbarg;
! 242: {
! 243: struct usl_syncdata *sd = cookie;
! 244:
! 245: if (!usl_sync_check(sd))
! 246: return (0);
! 247:
! 248: /* we really need a callback */
! 249: if (!callback)
! 250: return (EINVAL);
! 251:
! 252: sd->s_callback = callback;
! 253: sd->s_cbarg = cbarg;
! 254: sd->s_flags |= SF_ATTACHPENDING;
! 255: psignal(sd->s_proc, sd->s_acqsig);
! 256: timeout_add(&sd->s_attach_ch, wscompat_usl_synctimeout * hz);
! 257:
! 258: return (EAGAIN);
! 259: }
! 260:
! 261: int
! 262: usl_attachack(sd, ack)
! 263: struct usl_syncdata *sd;
! 264: int ack;
! 265: {
! 266: if (!(sd->s_flags & SF_ATTACHPENDING)) {
! 267: DPRINTF(("usl_attachack: not attaching\n"));
! 268: return (EINVAL);
! 269: }
! 270:
! 271: timeout_del(&sd->s_attach_ch);
! 272: sd->s_flags &= ~SF_ATTACHPENDING;
! 273:
! 274: if (sd->s_callback)
! 275: (*sd->s_callback)(sd->s_cbarg, (ack ? 0 : EIO), 1);
! 276:
! 277: return (0);
! 278: }
! 279:
! 280: void
! 281: usl_attachtimeout(arg)
! 282: void *arg;
! 283: {
! 284: struct usl_syncdata *sd = arg;
! 285:
! 286: DPRINTF(("usl_attachtimeout\n"));
! 287:
! 288: if (!(sd->s_flags & SF_ATTACHPENDING)) {
! 289: DPRINTF(("usl_attachtimeout: not attaching\n"));
! 290: return;
! 291: }
! 292:
! 293: sd->s_flags &= ~SF_ATTACHPENDING;
! 294:
! 295: if (sd->s_callback)
! 296: (*sd->s_callback)(sd->s_cbarg, EIO, 0);
! 297:
! 298: (void) usl_sync_check(sd);
! 299: }
! 300:
! 301: int
! 302: wsdisplay_usl_ioctl1(sc, cmd, data, flag, p)
! 303: struct wsdisplay_softc *sc;
! 304: u_long cmd;
! 305: caddr_t data;
! 306: int flag;
! 307: struct proc *p;
! 308: {
! 309: int idx, maxidx;
! 310:
! 311: switch (cmd) {
! 312: case VT_OPENQRY:
! 313: maxidx = wsdisplay_maxscreenidx(sc);
! 314: for (idx = 0; idx <= maxidx; idx++) {
! 315: if (wsdisplay_screenstate(sc, idx) == 0) {
! 316: *(int *)data = idx + 1;
! 317: return (0);
! 318: }
! 319: }
! 320: return (ENXIO);
! 321: case VT_GETACTIVE:
! 322: idx = wsdisplay_getactivescreen(sc);
! 323: *(int *)data = idx + 1;
! 324: return (0);
! 325: case VT_ACTIVATE:
! 326: idx = *(int *)data - 1;
! 327: if (idx < 0)
! 328: return (EINVAL);
! 329: return (wsdisplay_switch((struct device *)sc, idx, 1));
! 330: case VT_WAITACTIVE:
! 331: idx = *(int *)data - 1;
! 332: if (idx < 0)
! 333: return (EINVAL);
! 334: return (wsscreen_switchwait(sc, idx));
! 335: case VT_GETSTATE:
! 336: #define ss ((struct vt_stat *)data)
! 337: idx = wsdisplay_getactivescreen(sc);
! 338: ss->v_active = idx + 1;
! 339: ss->v_state = 0;
! 340: maxidx = wsdisplay_maxscreenidx(sc);
! 341: for (idx = 0; idx <= maxidx; idx++)
! 342: if (wsdisplay_screenstate(sc, idx) == EBUSY)
! 343: ss->v_state |= (1 << (idx + 1));
! 344: #undef ss
! 345: return (0);
! 346:
! 347: #ifdef WSDISPLAY_COMPAT_PCVT
! 348: case VGAPCVTID:
! 349: #define id ((struct pcvtid *)data)
! 350: strlcpy(id->name, "pcvt", sizeof id->name);
! 351: id->rmajor = 3;
! 352: id->rminor = 32;
! 353: #undef id
! 354: return (0);
! 355: #endif
! 356: #ifdef WSDISPLAY_COMPAT_SYSCONS
! 357: case CONS_GETVERS:
! 358: *(int *)data = 0x200; /* version 2.0 */
! 359: return (0);
! 360: #endif
! 361:
! 362: default:
! 363: return (-1);
! 364: }
! 365:
! 366: return (0);
! 367: }
! 368:
! 369: int
! 370: wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p)
! 371: struct wsdisplay_softc *sc;
! 372: struct wsscreen *scr;
! 373: u_long cmd;
! 374: caddr_t data;
! 375: int flag;
! 376: struct proc *p;
! 377: {
! 378: int intarg, res;
! 379: u_long req;
! 380: void *arg;
! 381: struct usl_syncdata *sd;
! 382: struct wskbd_bell_data bd;
! 383:
! 384: switch (cmd) {
! 385: case VT_SETMODE:
! 386: #define newmode ((struct vt_mode *)data)
! 387: if (newmode->mode == VT_PROCESS) {
! 388: res = usl_sync_init(scr, &sd, p, newmode->acqsig,
! 389: newmode->relsig, newmode->frsig);
! 390: if (res)
! 391: return (res);
! 392: } else {
! 393: sd = usl_sync_get(scr);
! 394: if (sd)
! 395: usl_sync_done(sd);
! 396: }
! 397: #undef newmode
! 398: return (0);
! 399: case VT_GETMODE:
! 400: #define cmode ((struct vt_mode *)data)
! 401: sd = usl_sync_get(scr);
! 402: if (sd) {
! 403: cmode->mode = VT_PROCESS;
! 404: cmode->relsig = sd->s_relsig;
! 405: cmode->acqsig = sd->s_acqsig;
! 406: cmode->frsig = sd->s_frsig;
! 407: } else
! 408: cmode->mode = VT_AUTO;
! 409: #undef cmode
! 410: return (0);
! 411: case VT_RELDISP:
! 412: #define d (*(int *)data)
! 413: sd = usl_sync_get(scr);
! 414: if (!sd)
! 415: return (EINVAL);
! 416: switch (d) {
! 417: case VT_FALSE:
! 418: case VT_TRUE:
! 419: return (usl_detachack(sd, (d == VT_TRUE)));
! 420: case VT_ACKACQ:
! 421: return (usl_attachack(sd, 1));
! 422: default:
! 423: return (EINVAL);
! 424: }
! 425: #undef d
! 426: return (0);
! 427:
! 428: #if defined(__i386__)
! 429: case KDENABIO:
! 430: if (suser(p, 0) || securelevel > 0)
! 431: return (EPERM);
! 432: /* FALLTHROUGH */
! 433: case KDDISABIO:
! 434: #if defined(COMPAT_FREEBSD)
! 435: {
! 436: struct trapframe *fp = (struct trapframe *)p->p_md.md_regs;
! 437: extern struct emul emul_freebsd_aout;
! 438: extern struct emul emul_freebsd_elf;
! 439:
! 440: if (p->p_emul == &emul_freebsd_aout ||
! 441: p->p_emul == &emul_freebsd_elf) {
! 442: if (cmd == KDENABIO)
! 443: fp->tf_eflags |= PSL_IOPL;
! 444: else
! 445: fp->tf_eflags &= ~PSL_IOPL;
! 446: }
! 447: }
! 448: #endif
! 449: return (0);
! 450: #else
! 451: case KDENABIO:
! 452: case KDDISABIO:
! 453: /*
! 454: * This is a lie, but non-x86 platforms are not supposed to
! 455: * issue these ioctls anyway.
! 456: */
! 457: return (0);
! 458: #endif
! 459: case KDSETRAD:
! 460: /* XXX ignore for now */
! 461: return (0);
! 462:
! 463: default:
! 464: return (-1);
! 465:
! 466: /*
! 467: * the following are converted to wsdisplay ioctls
! 468: */
! 469: case KDSETMODE:
! 470: req = WSDISPLAYIO_SMODE;
! 471: #define d (*(int *)data)
! 472: switch (d) {
! 473: case KD_GRAPHICS:
! 474: intarg = WSDISPLAYIO_MODE_MAPPED;
! 475: break;
! 476: case KD_TEXT:
! 477: intarg = WSDISPLAYIO_MODE_EMUL;
! 478: break;
! 479: default:
! 480: return (EINVAL);
! 481: }
! 482: #undef d
! 483: arg = &intarg;
! 484: break;
! 485: case KDMKTONE:
! 486: req = WSKBDIO_COMPLEXBELL;
! 487: #define d (*(int *)data)
! 488: if (d) {
! 489: #define PCVT_SYSBEEPF 1193182
! 490: if (d >> 16) {
! 491: bd.which = WSKBD_BELL_DOPERIOD;
! 492: bd.period = d >> 16; /* ms */
! 493: }
! 494: else
! 495: bd.which = 0;
! 496: if (d & 0xffff) {
! 497: bd.which |= WSKBD_BELL_DOPITCH;
! 498: bd.pitch = PCVT_SYSBEEPF/(d & 0xffff); /* Hz */
! 499: }
! 500: } else
! 501: bd.which = 0; /* default */
! 502: #undef d
! 503: arg = &bd;
! 504: break;
! 505: case KDSETLED:
! 506: req = WSKBDIO_SETLEDS;
! 507: intarg = 0;
! 508: #define d (*(int *)data)
! 509: if (d & LED_CAP)
! 510: intarg |= WSKBD_LED_CAPS;
! 511: if (d & LED_NUM)
! 512: intarg |= WSKBD_LED_NUM;
! 513: if (d & LED_SCR)
! 514: intarg |= WSKBD_LED_SCROLL;
! 515: #undef d
! 516: arg = &intarg;
! 517: break;
! 518: case KDGETLED:
! 519: req = WSKBDIO_GETLEDS;
! 520: arg = &intarg;
! 521: break;
! 522: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 523: case KDSKBMODE:
! 524: req = WSKBDIO_SETMODE;
! 525: switch (*(int *)data) {
! 526: case K_RAW:
! 527: intarg = WSKBD_RAW;
! 528: break;
! 529: case K_XLATE:
! 530: intarg = WSKBD_TRANSLATED;
! 531: break;
! 532: default:
! 533: return (EINVAL);
! 534: }
! 535: arg = &intarg;
! 536: break;
! 537: case KDGKBMODE:
! 538: req = WSKBDIO_GETMODE;
! 539: arg = &intarg;
! 540: break;
! 541: #endif
! 542: }
! 543:
! 544: res = wsdisplay_internal_ioctl(sc, scr, req, arg, flag, p);
! 545: if (res)
! 546: return (res);
! 547:
! 548: switch (cmd) {
! 549: case KDGETLED:
! 550: #define d (*(int *)data)
! 551: d = 0;
! 552: if (intarg & WSKBD_LED_CAPS)
! 553: d |= LED_CAP;
! 554: if (intarg & WSKBD_LED_NUM)
! 555: d |= LED_NUM;
! 556: if (intarg & WSKBD_LED_SCROLL)
! 557: d |= LED_SCR;
! 558: #undef d
! 559: break;
! 560: #ifdef WSDISPLAY_COMPAT_RAWKBD
! 561: case KDGKBMODE:
! 562: *(int *)data = (intarg == WSKBD_RAW ? K_RAW : K_XLATE);
! 563: break;
! 564: #endif
! 565: }
! 566:
! 567: return (0);
! 568: }
CVSweb