1 /* $OpenBSD: wsdisplay_compat_usl.c,v 1.20 2008/09/10 14:01:23 blambert 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_sec(&sd->s_detach_ch, wscompat_usl_synctimeout); 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_sec(&sd->s_attach_ch, wscompat_usl_synctimeout); 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 } 569