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