1 /* $NetBSD: wsdisplay.c,v 1.21 1999/03/13 14:46:20 drochner Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 static const char _copyright[] __attribute__ ((unused)) = 34 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved."; 35 static const char _rcsid[] __attribute__ ((unused)) = 36 "$NetBSD: wsdisplay.c,v 1.21 1999/03/13 14:46:20 drochner Exp $"; 37 38 #include <sys/param.h> 39 #include <sys/conf.h> 40 #include <sys/device.h> 41 #include <sys/ioctl.h> 42 #include <sys/kernel.h> 43 #include <sys/proc.h> 44 #include <sys/malloc.h> 45 #include <sys/syslog.h> 46 #include <sys/systm.h> 47 #include <sys/tty.h> 48 #include <sys/signalvar.h> 49 #include <sys/errno.h> 50 #include <sys/fcntl.h> 51 #include <sys/vnode.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 #include <dev/wscons/wsksymvar.h> 56 #include <dev/wscons/wsksymdef.h> 57 #include <dev/wscons/wsemulvar.h> 58 #include <dev/wscons/wscons_callbacks.h> 59 #include <dev/cons.h> 60 61 #include "opt_wsdisplay_compat.h" 62 63 #include "wsdisplay.h" 64 65 struct wsscreen_internal { 66 const struct wsdisplay_emulops *emulops; 67 void *emulcookie; 68 69 const struct wsscreen_descr *scrdata; 70 71 const struct wsemul_ops *wsemul; 72 void *wsemulcookie; 73 }; 74 75 struct wsscreen { 76 struct wsscreen_internal *scr_dconf; 77 78 struct tty *scr_tty; 79 int scr_hold_screen; /* hold tty output */ 80 81 int scr_flags; 82 #define SCR_OPEN 1 /* is it open? */ 83 #define SCR_WAITACTIVE 2 /* someone waiting on activation */ 84 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */ 85 const struct wscons_syncops *scr_syncops; 86 void *scr_synccookie; 87 88 #ifdef WSDISPLAY_COMPAT_RAWKBD 89 int scr_rawkbd; 90 #endif 91 92 struct wsdisplay_softc *sc; 93 }; 94 95 struct wsscreen *wsscreen_attach __P((struct wsdisplay_softc *, int, 96 const char *, 97 const struct wsscreen_descr *, void *, 98 int, int, long)); 99 void wsscreen_detach __P((struct wsscreen *)); 100 static const struct wsscreen_descr * 101 wsdisplay_screentype_pick __P((const struct wsscreen_list *, char *)); 102 int wsdisplay_addscreen __P((struct wsdisplay_softc *, int, char *, char *)); 103 static void wsdisplay_closescreen __P((struct wsdisplay_softc *, 104 struct wsscreen *)); 105 int wsdisplay_delscreen __P((struct wsdisplay_softc *, int, int)); 106 107 #define WSDISPLAY_MAXSCREEN 8 108 109 struct wsdisplay_softc { 110 struct device sc_dv; 111 112 const struct wsdisplay_accessops *sc_accessops; 113 void *sc_accesscookie; 114 115 const struct wsscreen_list *sc_scrdata; 116 117 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN]; 118 int sc_focusidx; 119 struct wsscreen *sc_focus; 120 121 int sc_isconsole; 122 struct device *sc_kbddv; 123 124 int sc_flags; 125 #define SC_SWITCHPENDING 1 126 int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */ 127 128 #ifdef WSDISPLAY_COMPAT_RAWKBD 129 int sc_rawkbd; 130 #endif 131 }; 132 133 #if NWSDISPLAY > 0 134 extern struct cfdriver wsdisplay_cd; 135 #endif /* NWSDISPLAY > 0 */ 136 137 /* Autoconfiguration definitions. */ 138 static int wsdisplay_emul_match __P((struct device *, struct cfdata *, 139 void *)); 140 static void wsdisplay_emul_attach __P((struct device *, struct device *, 141 void *)); 142 static int wsdisplay_noemul_match __P((struct device *, struct cfdata *, 143 void *)); 144 static void wsdisplay_noemul_attach __P((struct device *, struct device *, 145 void *)); 146 147 struct cfattach wsdisplay_emul_ca = { 148 sizeof (struct wsdisplay_softc), 149 wsdisplay_emul_match, 150 wsdisplay_emul_attach, 151 }; 152 153 struct cfattach wsdisplay_noemul_ca = { 154 sizeof (struct wsdisplay_softc), 155 wsdisplay_noemul_match, 156 wsdisplay_noemul_attach, 157 }; 158 159 /* Exported tty- and cdevsw-related functions. */ 160 cdev_decl(wsdisplay); 161 162 #if NWSDISPLAY > 0 163 static void wsdisplaystart __P((struct tty *)); 164 static int wsdisplayparam __P((struct tty *, struct termios *)); 165 #endif /* NWSDISPLAY > 0 */ 166 167 168 /* Internal macros, functions, and variables. */ 169 #define SET(t, f) (t) |= (f) 170 #define CLR(t, f) (t) &= ~(f) 171 #define ISSET(t, f) ((t) & (f)) 172 173 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8) 174 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff) 175 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255) 176 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen)) 177 178 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL) 179 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL) 180 181 static void wsdisplay_common_attach __P((struct wsdisplay_softc *sc, 182 int console, const struct wsscreen_list *, 183 const struct wsdisplay_accessops *accessops, 184 void *accesscookie)); 185 186 #ifdef WSDISPLAY_COMPAT_RAWKBD 187 int wsdisplay_update_rawkbd __P((struct wsdisplay_softc *, 188 struct wsscreen *)); 189 #endif 190 191 static int wsdisplay_console_initted; 192 static struct wsdisplay_softc *wsdisplay_console_device; 193 static struct wsscreen_internal wsdisplay_console_conf; 194 195 static int wsdisplay_getc_dummy __P((dev_t)); 196 static void wsdisplay_pollc_dummy __P((dev_t, int)); 197 198 static struct consdev wsdisplay_cons = { 199 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc, 200 wsdisplay_pollc_dummy, NODEV, CN_NORMAL 201 }; 202 203 int wsdisplay_switch1 __P((void *, int, int)); 204 int wsdisplay_switch3 __P((void *, int, int)); 205 206 int wsdisplay_clearonclose; 207 208 struct wsscreen * 209 wsscreen_attach(sc, console, emul, type, cookie, ccol, crow, defattr) 210 struct wsdisplay_softc *sc; 211 int console; 212 const char *emul; 213 const struct wsscreen_descr *type; 214 void *cookie; 215 int ccol, crow; 216 long defattr; 217 { 218 struct wsscreen_internal *dconf; 219 struct wsscreen *scr; 220 221 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK); 222 if (!scr) 223 return (NULL); 224 225 if (console) { 226 dconf = &wsdisplay_console_conf; 227 /* 228 * If there's an emulation, tell it about the callback argument. 229 * The other stuff is already there. 230 */ 231 if (dconf->wsemul != NULL) 232 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0); 233 } else { /* not console */ 234 dconf = malloc(sizeof(struct wsscreen_internal), 235 M_DEVBUF, M_NOWAIT); 236 dconf->emulops = type->textops; 237 dconf->emulcookie = cookie; 238 if (dconf->emulops) { 239 dconf->wsemul = wsemul_pick(emul); 240 if (dconf->wsemul == NULL) { 241 free(dconf, M_DEVBUF); 242 free(scr, M_DEVBUF); 243 return (NULL); 244 } 245 dconf->wsemulcookie = 246 (*dconf->wsemul->attach)(0, type, cookie, 247 ccol, crow, scr, defattr); 248 } else 249 dconf->wsemul = NULL; 250 dconf->scrdata = type; 251 } 252 253 scr->scr_dconf = dconf; 254 255 scr->scr_tty = ttymalloc(); 256 tty_attach(scr->scr_tty); 257 scr->scr_hold_screen = 0; 258 if (WSSCREEN_HAS_EMULATOR(scr)) 259 scr->scr_flags = 0; 260 else 261 scr->scr_flags = SCR_GRAPHICS; 262 263 scr->scr_syncops = 0; 264 scr->sc = sc; 265 #ifdef WSDISPLAY_COMPAT_RAWKBD 266 scr->scr_rawkbd = 0; 267 #endif 268 return (scr); 269 } 270 271 void 272 wsscreen_detach(scr) 273 struct wsscreen *scr; 274 { 275 int ccol, crow; /* XXX */ 276 277 if (WSSCREEN_HAS_TTY(scr)) { 278 tty_detach(scr->scr_tty); 279 ttyfree(scr->scr_tty); 280 } 281 if (WSSCREEN_HAS_EMULATOR(scr)) 282 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie, 283 &ccol, &crow); 284 free(scr->scr_dconf, M_DEVBUF); 285 free(scr, M_DEVBUF); 286 } 287 288 static const struct wsscreen_descr * 289 wsdisplay_screentype_pick(scrdata, name) 290 const struct wsscreen_list *scrdata; 291 char *name; 292 { 293 int i; 294 const struct wsscreen_descr *scr; 295 296 KASSERT(scrdata->nscreens > 0); 297 298 if (name == NULL) 299 return (scrdata->screens[0]); 300 301 for (i = 0; i < scrdata->nscreens; i++) { 302 scr = scrdata->screens[i]; 303 if (!strcmp(name, scr->name)) 304 return (scr); 305 } 306 307 return (0); 308 } 309 310 int 311 wsdisplay_addscreen(sc, idx, screentype, emul) 312 struct wsdisplay_softc *sc; 313 int idx; 314 char *screentype, *emul; 315 { 316 const struct wsscreen_descr *scrdesc; 317 int error; 318 void *cookie; 319 int ccol, crow; 320 long defattr; 321 struct wsscreen *scr; 322 323 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 324 return (EINVAL); 325 if (sc->sc_scr[idx] != NULL) 326 return (EBUSY); 327 328 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype); 329 if (!scrdesc) 330 return (ENXIO); 331 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie, 332 scrdesc, &cookie, &ccol, &crow, &defattr); 333 if (error) 334 return (error); 335 336 scr = wsscreen_attach(sc, 0, emul, scrdesc, 337 cookie, ccol, crow, defattr); 338 if (scr == NULL) { 339 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 340 cookie); 341 return (ENXIO); 342 } 343 344 sc->sc_scr[idx] = scr; 345 346 printf("%s: screen %d added (%s", sc->sc_dv.dv_xname, idx, 347 scrdesc->name); 348 if (WSSCREEN_HAS_EMULATOR(scr)) 349 printf(", %s emulation", scr->scr_dconf->wsemul->name); 350 printf(")\n"); 351 return (0); 352 } 353 354 static void 355 wsdisplay_closescreen(sc, scr) 356 struct wsdisplay_softc *sc; 357 struct wsscreen *scr; 358 { 359 int maj, mn, idx; 360 361 /* hangup */ 362 if (WSSCREEN_HAS_TTY(scr)) { 363 struct tty *tp = scr->scr_tty; 364 (*linesw[tp->t_line].l_modem)(tp, 0); 365 } 366 367 /* locate the major number */ 368 for (maj = 0; maj < nchrdev; maj++) 369 if (cdevsw[maj].d_open == wsdisplayopen) 370 break; 371 /* locate the screen index */ 372 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++) 373 if (scr == sc->sc_scr[idx]) 374 break; 375 #ifdef DIAGNOSTIC 376 if (idx == WSDISPLAY_MAXSCREEN) 377 panic("wsdisplay_forceclose: bad screen"); 378 #endif 379 380 /* nuke the vnodes */ 381 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx); 382 vdevgone(maj, mn, mn, VCHR); 383 } 384 385 int 386 wsdisplay_delscreen(sc, idx, flags) 387 struct wsdisplay_softc *sc; 388 int idx, flags; 389 { 390 struct wsscreen *scr; 391 int s; 392 void *cookie; 393 394 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 395 return (EINVAL); 396 scr = sc->sc_scr[idx]; 397 if (!scr) 398 return (ENXIO); 399 400 if (scr->scr_dconf == &wsdisplay_console_conf || 401 scr->scr_syncops || 402 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE))) 403 return(EBUSY); 404 405 wsdisplay_closescreen(sc, scr); 406 407 /* 408 * delete pointers, so neither device entries 409 * nor keyboard input can reference it anymore 410 */ 411 s = spltty(); 412 if (sc->sc_focus == scr) { 413 sc->sc_focus = 0; 414 #ifdef WSDISPLAY_COMPAT_RAWKBD 415 wsdisplay_update_rawkbd(sc, 0); 416 #endif 417 } 418 sc->sc_scr[idx] = 0; 419 splx(s); 420 421 /* 422 * Wake up processes waiting for the screen to 423 * be activated. Sleepers must check whether 424 * the screen still exists. 425 */ 426 if (scr->scr_flags & SCR_WAITACTIVE) 427 wakeup(scr); 428 429 /* save a reference to the graphics screen */ 430 cookie = scr->scr_dconf->emulcookie; 431 432 wsscreen_detach(scr); 433 434 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 435 cookie); 436 437 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx); 438 return (0); 439 } 440 441 /* 442 * Autoconfiguration functions. 443 */ 444 int 445 wsdisplay_emul_match(parent, match, aux) 446 struct device *parent; 447 struct cfdata *match; 448 void *aux; 449 { 450 struct wsemuldisplaydev_attach_args *ap = aux; 451 452 if (match->wsemuldisplaydevcf_console != 453 WSEMULDISPLAYDEVCF_CONSOLE_UNK) { 454 /* 455 * If console-ness of device specified, either match 456 * exactly (at high priority), or fail. 457 */ 458 if (match->wsemuldisplaydevcf_console != 0 && 459 ap->console != 0) 460 return (10); 461 else 462 return (0); 463 } 464 465 /* If console-ness unspecified, it wins. */ 466 return (1); 467 } 468 469 void 470 wsdisplay_emul_attach(parent, self, aux) 471 struct device *parent, *self; 472 void *aux; 473 { 474 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 475 struct wsemuldisplaydev_attach_args *ap = aux; 476 477 wsdisplay_common_attach(sc, ap->console, ap->scrdata, 478 ap->accessops, ap->accesscookie); 479 480 if (ap->console) { 481 int maj; 482 483 /* locate the major number */ 484 for (maj = 0; maj < nchrdev; maj++) 485 if (cdevsw[maj].d_open == wsdisplayopen) 486 break; 487 488 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0)); 489 } 490 } 491 492 /* Print function (for parent devices). */ 493 int 494 wsemuldisplaydevprint(aux, pnp) 495 void *aux; 496 const char *pnp; 497 { 498 #if 0 /* -Wunused */ 499 struct wsemuldisplaydev_attach_args *ap = aux; 500 #endif 501 502 if (pnp) 503 printf("wsdisplay at %s", pnp); 504 #if 0 /* don't bother; it's ugly */ 505 printf(" console %d", ap->console); 506 #endif 507 508 return (UNCONF); 509 } 510 511 int 512 wsdisplay_noemul_match(parent, match, aux) 513 struct device *parent; 514 struct cfdata *match; 515 void *aux; 516 { 517 #if 0 /* -Wunused */ 518 struct wsdisplaydev_attach_args *ap = aux; 519 #endif 520 521 /* Always match. */ 522 return (1); 523 } 524 525 void 526 wsdisplay_noemul_attach(parent, self, aux) 527 struct device *parent, *self; 528 void *aux; 529 { 530 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 531 struct wsdisplaydev_attach_args *ap = aux; 532 533 wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie); 534 } 535 536 /* Print function (for parent devices). */ 537 int 538 wsdisplaydevprint(aux, pnp) 539 void *aux; 540 const char *pnp; 541 { 542 #if 0 /* -Wunused */ 543 struct wsdisplaydev_attach_args *ap = aux; 544 #endif 545 546 if (pnp) 547 printf("wsdisplay at %s", pnp); 548 549 return (UNCONF); 550 } 551 552 static void 553 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie) 554 struct wsdisplay_softc *sc; 555 int console; 556 const struct wsscreen_list *scrdata; 557 const struct wsdisplay_accessops *accessops; 558 void *accesscookie; 559 { 560 int i = 0; 561 562 if (console) { 563 KASSERT(wsdisplay_console_initted); 564 KASSERT(wsdisplay_console_device == NULL); 565 566 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0); 567 wsdisplay_console_device = sc; 568 569 printf(": console (%s, %s emulation)", 570 wsdisplay_console_conf.scrdata->name, 571 wsdisplay_console_conf.wsemul->name); 572 573 sc->sc_focusidx = 0; 574 sc->sc_focus = sc->sc_scr[0]; 575 i++; 576 } 577 578 printf("\n"); 579 580 sc->sc_accessops = accessops; 581 sc->sc_accesscookie = accesscookie; 582 sc->sc_scrdata = scrdata; 583 584 sc->sc_isconsole = console; 585 sc->sc_kbddv = NULL; 586 587 wscons_glue_set_callback(); 588 589 /* 590 * Set up a number of virtual screens if possible. The 591 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 592 * should go away as soon as we have a userspace utility. 593 */ 594 #ifdef WSDISPLAY_DEFAULTSCREENS 595 for (; i < WSDISPLAY_DEFAULTSCREENS; i++) 596 if (wsdisplay_addscreen(sc, i, 0, 0)) 597 break; 598 #endif 599 } 600 601 void 602 wsdisplay_cnattach(type, cookie, ccol, crow, defattr) 603 const struct wsscreen_descr *type; 604 void *cookie; 605 int ccol, crow; 606 long defattr; 607 { 608 const struct wsemul_ops *wsemul; 609 610 KASSERT(!wsdisplay_console_initted); 611 KASSERT(type->nrows > 0); 612 KASSERT(type->ncols > 0); 613 KASSERT(crow < type->nrows); 614 KASSERT(ccol < type->ncols); 615 616 wsdisplay_console_conf.emulops = type->textops; 617 wsdisplay_console_conf.emulcookie = cookie; 618 wsdisplay_console_conf.scrdata = type; 619 620 wsemul = wsemul_pick(0); /* default */ 621 wsdisplay_console_conf.wsemul = wsemul; 622 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 623 ccol, crow, 624 defattr); 625 626 cn_tab = &wsdisplay_cons; 627 628 wsdisplay_console_initted = 1; 629 } 630 631 /* 632 * Tty and cdevsw functions. 633 */ 634 int 635 wsdisplayopen(dev, flag, mode, p) 636 dev_t dev; 637 int flag, mode; 638 struct proc *p; 639 { 640 #if NWSDISPLAY > 0 641 struct wsdisplay_softc *sc; 642 struct tty *tp; 643 int unit, newopen, error; 644 struct wsscreen *scr; 645 646 unit = WSDISPLAYUNIT(dev); 647 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */ 648 (sc = wsdisplay_cd.cd_devs[unit]) == NULL) 649 return (ENXIO); 650 651 if (ISWSDISPLAYCTL(dev)) 652 return (0); 653 654 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 655 return (ENXIO); 656 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 657 if (!scr) 658 return (ENXIO); 659 660 if (WSSCREEN_HAS_TTY(scr)) { 661 tp = scr->scr_tty; 662 tp->t_oproc = wsdisplaystart; 663 tp->t_param = wsdisplayparam; 664 tp->t_dev = dev; 665 newopen = (tp->t_state & TS_ISOPEN) == 0; 666 if (newopen) { 667 ttychars(tp); 668 tp->t_iflag = TTYDEF_IFLAG; 669 tp->t_oflag = TTYDEF_OFLAG; 670 tp->t_cflag = TTYDEF_CFLAG; 671 tp->t_lflag = TTYDEF_LFLAG; 672 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 673 wsdisplayparam(tp, &tp->t_termios); 674 ttsetwater(tp); 675 } else if ((tp->t_state & TS_XCLUDE) != 0 && 676 p->p_ucred->cr_uid != 0) 677 return EBUSY; 678 tp->t_state |= TS_CARR_ON; 679 680 error = ((*linesw[tp->t_line].l_open)(dev, tp)); 681 if (error) 682 return (error); 683 684 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 685 /* set window sizes as appropriate, and reset 686 the emulation */ 687 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 688 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 689 690 /* wsdisplay_set_emulation() */ 691 } 692 } 693 694 scr->scr_flags |= SCR_OPEN; 695 return (0); 696 #else 697 return (ENXIO); 698 #endif /* NWSDISPLAY > 0 */ 699 } 700 701 int 702 wsdisplayclose(dev, flag, mode, p) 703 dev_t dev; 704 int flag, mode; 705 struct proc *p; 706 { 707 #if NWSDISPLAY > 0 708 struct wsdisplay_softc *sc; 709 struct tty *tp; 710 int unit; 711 struct wsscreen *scr; 712 713 unit = WSDISPLAYUNIT(dev); 714 sc = wsdisplay_cd.cd_devs[unit]; 715 716 if (ISWSDISPLAYCTL(dev)) 717 return (0); 718 719 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 720 721 if (WSSCREEN_HAS_TTY(scr)) { 722 if (scr->scr_hold_screen) { 723 int s; 724 725 /* XXX RESET KEYBOARD LEDS, etc. */ 726 s = spltty(); /* avoid conflict with keyboard */ 727 wsdisplay_kbdholdscreen((struct device *)sc, 0); 728 splx(s); 729 } 730 tp = scr->scr_tty; 731 (*linesw[tp->t_line].l_close)(tp, flag); 732 ttyclose(tp); 733 } 734 735 if (scr->scr_syncops) 736 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 737 738 if (WSSCREEN_HAS_EMULATOR(scr)) { 739 scr->scr_flags &= ~SCR_GRAPHICS; 740 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 741 WSEMUL_RESET); 742 if (wsdisplay_clearonclose) 743 (*scr->scr_dconf->wsemul->reset) 744 (scr->scr_dconf->wsemulcookie, 745 WSEMUL_CLEARSCREEN); 746 } 747 748 #ifdef WSDISPLAY_COMPAT_RAWKBD 749 if (scr->scr_rawkbd) { 750 int kbmode = WSKBD_TRANSLATED; 751 (void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 752 (caddr_t)&kbmode, 0, p); 753 } 754 #endif 755 756 scr->scr_flags &= ~SCR_OPEN; 757 758 return (0); 759 #else 760 return (ENXIO); 761 #endif /* NWSDISPLAY > 0 */ 762 } 763 764 int 765 wsdisplayread(dev, uio, flag) 766 dev_t dev; 767 struct uio *uio; 768 int flag; 769 { 770 #if NWSDISPLAY > 0 771 struct wsdisplay_softc *sc; 772 struct tty *tp; 773 int unit; 774 struct wsscreen *scr; 775 776 unit = WSDISPLAYUNIT(dev); 777 sc = wsdisplay_cd.cd_devs[unit]; 778 779 if (ISWSDISPLAYCTL(dev)) 780 return (0); 781 782 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 783 784 if (!WSSCREEN_HAS_TTY(scr)) 785 return (ENODEV); 786 787 tp = scr->scr_tty; 788 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 789 #else 790 return (ENXIO); 791 #endif /* NWSDISPLAY > 0 */ 792 } 793 794 int 795 wsdisplaywrite(dev, uio, flag) 796 dev_t dev; 797 struct uio *uio; 798 int flag; 799 { 800 #if NWSDISPLAY > 0 801 struct wsdisplay_softc *sc; 802 struct tty *tp; 803 int unit; 804 struct wsscreen *scr; 805 806 unit = WSDISPLAYUNIT(dev); 807 sc = wsdisplay_cd.cd_devs[unit]; 808 809 if (ISWSDISPLAYCTL(dev)) 810 return (0); 811 812 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 813 814 if (!WSSCREEN_HAS_TTY(scr)) 815 return (ENODEV); 816 817 tp = scr->scr_tty; 818 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 819 #else 820 return (ENXIO); 821 #endif /* NWSDISPLAY > 0 */ 822 } 823 824 struct tty * 825 wsdisplaytty(dev) 826 dev_t dev; 827 { 828 #if NWSDISPLAY > 0 829 struct wsdisplay_softc *sc; 830 int unit; 831 struct wsscreen *scr; 832 833 unit = WSDISPLAYUNIT(dev); 834 sc = wsdisplay_cd.cd_devs[unit]; 835 836 if (ISWSDISPLAYCTL(dev)) 837 panic("wsdisplaytty() on ctl device"); 838 839 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 840 841 return (scr->scr_tty); 842 #else 843 return (NULL); 844 #endif /* NWSDISPLAY > 0 */ 845 } 846 847 int 848 wsdisplayioctl(dev, cmd, data, flag, p) 849 dev_t dev; 850 u_long cmd; 851 caddr_t data; 852 int flag; 853 struct proc *p; 854 { 855 #if NWSDISPLAY > 0 856 struct wsdisplay_softc *sc; 857 struct tty *tp; 858 int unit, error; 859 struct wsscreen *scr; 860 861 unit = WSDISPLAYUNIT(dev); 862 sc = wsdisplay_cd.cd_devs[unit]; 863 864 if (ISWSDISPLAYCTL(dev)) 865 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 866 867 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 868 869 if (WSSCREEN_HAS_TTY(scr)) { 870 tp = scr->scr_tty; 871 872 /* printf("disc\n"); */ 873 /* do the line discipline ioctls first */ 874 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 875 if (error >= 0) 876 return error; 877 878 /* printf("tty\n"); */ 879 /* then the tty ioctls */ 880 error = ttioctl(tp, cmd, data, flag, p); 881 if (error >= 0) 882 return error; 883 } 884 885 #ifdef WSDISPLAY_COMPAT_USL 886 error = wsdisplay_usl_ioctl(sc, scr, cmd, data, flag, p); 887 if (error >= 0) 888 return (error); 889 #endif 890 891 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p); 892 return (error != -1 ? error : ENOTTY); 893 #else 894 return (ENXIO); 895 #endif /* NWSDISPLAY > 0 */ 896 } 897 898 int 899 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p) 900 struct wsdisplay_softc *sc; 901 struct wsscreen *scr; 902 u_long cmd; 903 caddr_t data; 904 int flag; 905 struct proc *p; 906 { 907 int error; 908 char namebuf[16]; 909 struct wsdisplay_font fd; 910 911 if (sc->sc_kbddv != NULL) { 912 /* check ioctls for keyboard */ 913 #ifdef WSDISPLAY_COMPAT_RAWKBD 914 switch (cmd) { 915 case WSKBDIO_SETMODE: 916 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 917 return (wsdisplay_update_rawkbd(sc, scr)); 918 case WSKBDIO_GETMODE: 919 *(int *)data = (scr->scr_rawkbd ? 920 WSKBD_RAW : WSKBD_TRANSLATED); 921 return (0); 922 } 923 #endif 924 /* printf("kbdcallback\n"); */ 925 error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p); 926 if (error >= 0) 927 return error; 928 } 929 930 /* printf("display\n"); */ 931 switch (cmd) { 932 case WSDISPLAYIO_GMODE: 933 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 934 WSDISPLAYIO_MODE_MAPPED : 935 WSDISPLAYIO_MODE_EMUL); 936 return (0); 937 938 case WSDISPLAYIO_SMODE: 939 #define d (*(int *)data) 940 if (d != WSDISPLAYIO_MODE_EMUL && 941 d != WSDISPLAYIO_MODE_MAPPED) 942 return (EINVAL); 943 944 if (WSSCREEN_HAS_EMULATOR(scr)) { 945 scr->scr_flags &= ~SCR_GRAPHICS; 946 if (d == WSDISPLAYIO_MODE_MAPPED) 947 scr->scr_flags |= SCR_GRAPHICS; 948 } else if (d == WSDISPLAYIO_MODE_EMUL) 949 return (EINVAL); 950 return (0); 951 #undef d 952 953 case WSDISPLAYIO_USEFONT: 954 #define d ((struct wsdisplay_usefontdata *)data) 955 if (!sc->sc_accessops->load_font) 956 return (EINVAL); 957 if (d->name) { 958 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 959 if (error) 960 return (error); 961 fd.name = namebuf; 962 } else 963 fd.name = 0; 964 fd.data = 0; 965 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 966 scr->scr_dconf->emulcookie, &fd); 967 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 968 (*scr->scr_dconf->wsemul->reset) 969 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 970 return (error); 971 #undef d 972 } 973 974 /* check ioctls for display */ 975 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 976 flag, p)); 977 } 978 979 int 980 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p) 981 struct wsdisplay_softc *sc; 982 u_long cmd; 983 caddr_t data; 984 int flag; 985 struct proc *p; 986 { 987 int error; 988 char *type, typebuf[16], *emul, emulbuf[16]; 989 void *buf; 990 991 switch (cmd) { 992 case WSDISPLAYIO_ADDSCREEN: 993 #define d ((struct wsdisplay_addscreendata *)data) 994 if (d->screentype) { 995 error = copyinstr(d->screentype, typebuf, 996 sizeof(typebuf), 0); 997 if (error) 998 return (error); 999 type = typebuf; 1000 } else 1001 type = 0; 1002 if (d->emul) { 1003 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf), 0); 1004 if (error) 1005 return (error); 1006 emul = emulbuf; 1007 } else 1008 emul = 0; 1009 1010 return (wsdisplay_addscreen(sc, d->idx, type, emul)); 1011 #undef d 1012 case WSDISPLAYIO_DELSCREEN: 1013 #define d ((struct wsdisplay_delscreendata *)data) 1014 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1015 #undef d 1016 case WSDISPLAYIO_LDFONT: 1017 #define d ((struct wsdisplay_font *)data) 1018 if (!sc->sc_accessops->load_font) 1019 return (EINVAL); 1020 if (d->name) { 1021 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1022 if (error) 1023 return (error); 1024 d->name = typebuf; 1025 } else 1026 d->name = "loaded"; /* ??? */ 1027 buf = malloc(d->fontheight * d->stride * d->numchars, 1028 M_DEVBUF, M_WAITOK); 1029 error = copyin(d->data, buf, 1030 d->fontheight * d->stride * d->numchars); 1031 if (error) { 1032 free(buf, M_DEVBUF); 1033 return (error); 1034 } 1035 d->data = buf; 1036 error = 1037 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1038 free(buf, M_DEVBUF); 1039 #undef d 1040 return (error); 1041 } 1042 return (EINVAL); 1043 } 1044 1045 int 1046 wsdisplaymmap(dev, offset, prot) 1047 dev_t dev; 1048 int offset; /* XXX */ 1049 int prot; 1050 { 1051 #if NWSDISPLAY > 0 1052 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1053 struct wsscreen *scr; 1054 1055 if (ISWSDISPLAYCTL(dev)) 1056 return (-1); 1057 1058 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1059 1060 if (!(scr->scr_flags & SCR_GRAPHICS)) 1061 return (-1); 1062 1063 /* pass mmap to display */ 1064 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1065 #else 1066 return (-1); 1067 #endif /* NWSDISPLAY > 0 */ 1068 } 1069 1070 int 1071 wsdisplaypoll(dev, events, p) 1072 dev_t dev; 1073 int events; 1074 struct proc *p; 1075 { 1076 #if NWSDISPLAY > 0 1077 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1078 struct wsscreen *scr; 1079 1080 if (ISWSDISPLAYCTL(dev)) 1081 return (0); 1082 1083 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1084 1085 if (WSSCREEN_HAS_TTY(scr)) 1086 return (ttpoll(dev, events, p)); 1087 else 1088 return (0); 1089 #else 1090 return (0); 1091 #endif /* NWSDISPLAY > 0 */ 1092 } 1093 1094 #if NWSDISPLAY > 0 1095 void 1096 wsdisplaystart(tp) 1097 register struct tty *tp; 1098 { 1099 struct wsdisplay_softc *sc; 1100 struct wsscreen *scr; 1101 register int s, n; 1102 u_char *buf; 1103 1104 s = spltty(); 1105 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1106 splx(s); 1107 return; 1108 } 1109 sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)]; 1110 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1111 if (scr->scr_hold_screen) { 1112 tp->t_state |= TS_TIMEOUT; 1113 splx(s); 1114 return; 1115 } 1116 tp->t_state |= TS_BUSY; 1117 splx(s); 1118 1119 /* 1120 * Drain output from ring buffer. 1121 * The output will normally be in one contiguous chunk, but when the 1122 * ring wraps, it will be in two pieces.. one at the end of the ring, 1123 * the other at the start. For performance, rather than loop here, 1124 * we output one chunk, see if there's another one, and if so, output 1125 * it too. 1126 */ 1127 1128 n = ndqb(&tp->t_outq, 0); 1129 buf = tp->t_outq.c_cf; 1130 1131 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1132 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1133 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1134 buf, n, 0); 1135 } 1136 ndflush(&tp->t_outq, n); 1137 1138 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1139 buf = tp->t_outq.c_cf; 1140 1141 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1142 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1143 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1144 buf, n, 0); 1145 } 1146 ndflush(&tp->t_outq, n); 1147 } 1148 1149 s = spltty(); 1150 tp->t_state &= ~TS_BUSY; 1151 /* Come back if there's more to do */ 1152 if (tp->t_outq.c_cc) { 1153 tp->t_state |= TS_TIMEOUT; 1154 timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1); 1155 } 1156 if (tp->t_outq.c_cc <= tp->t_lowat) { 1157 if (tp->t_state&TS_ASLEEP) { 1158 tp->t_state &= ~TS_ASLEEP; 1159 wakeup((caddr_t)&tp->t_outq); 1160 } 1161 selwakeup(&tp->t_wsel); 1162 } 1163 splx(s); 1164 } 1165 #endif /* NWSDISPLAY > 0 */ 1166 1167 void 1168 wsdisplaystop(tp, flag) 1169 struct tty *tp; 1170 int flag; 1171 { 1172 int s; 1173 1174 s = spltty(); 1175 if (ISSET(tp->t_state, TS_BUSY)) 1176 if (!ISSET(tp->t_state, TS_TTSTOP)) 1177 SET(tp->t_state, TS_FLUSH); 1178 splx(s); 1179 } 1180 1181 #if NWSDISPLAY > 0 1182 /* Set line parameters. */ 1183 int 1184 wsdisplayparam(tp, t) 1185 struct tty *tp; 1186 struct termios *t; 1187 { 1188 1189 tp->t_ispeed = t->c_ispeed; 1190 tp->t_ospeed = t->c_ospeed; 1191 tp->t_cflag = t->c_cflag; 1192 return 0; 1193 } 1194 #endif /* NWSDISPLAY > 0 */ 1195 1196 /* 1197 * Callbacks for the emulation code. 1198 */ 1199 void 1200 wsdisplay_emulbell(v) 1201 void *v; 1202 { 1203 struct wsscreen *scr = v; 1204 1205 if (scr == NULL) /* console, before real attach */ 1206 return; 1207 1208 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1209 return; 1210 1211 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1212 FWRITE, NULL); 1213 } 1214 1215 void 1216 wsdisplay_emulinput(v, data, count) 1217 void *v; 1218 const u_char *data; 1219 u_int count; 1220 { 1221 struct wsscreen *scr = v; 1222 struct tty *tp; 1223 1224 if (v == NULL) /* console, before real attach */ 1225 return; 1226 1227 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1228 return; 1229 if (!WSSCREEN_HAS_TTY(scr)) 1230 return; 1231 1232 tp = scr->scr_tty; 1233 while (count-- > 0) 1234 (*linesw[tp->t_line].l_rint)(*data++, tp); 1235 }; 1236 1237 /* 1238 * Calls from the keyboard interface. 1239 */ 1240 void 1241 wsdisplay_kbdinput(dev, ks) 1242 struct device *dev; 1243 keysym_t ks; 1244 { 1245 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1246 struct wsscreen *scr; 1247 char *dp; 1248 int count; 1249 struct tty *tp; 1250 1251 KASSERT(sc != NULL); 1252 1253 scr = sc->sc_focus; 1254 1255 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1256 return; 1257 1258 tp = scr->scr_tty; 1259 1260 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1261 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp); 1262 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1263 count = (*scr->scr_dconf->wsemul->translate) 1264 (scr->scr_dconf->wsemulcookie, ks, &dp); 1265 while (count-- > 0) 1266 (*linesw[tp->t_line].l_rint)(*dp++, tp); 1267 } 1268 } 1269 1270 #ifdef WSDISPLAY_COMPAT_RAWKBD 1271 int 1272 wsdisplay_update_rawkbd(sc, scr) 1273 struct wsdisplay_softc *sc; 1274 struct wsscreen *scr; 1275 { 1276 int s, raw, data, error; 1277 s = spltty(); 1278 1279 raw = (scr ? scr->scr_rawkbd : 0); 1280 1281 if (!sc->sc_kbddv || 1282 scr != sc->sc_focus || 1283 sc->sc_rawkbd == raw) { 1284 splx(s); 1285 return (0); 1286 } 1287 1288 data = (raw ? WSKBD_RAW : WSKBD_TRANSLATED); 1289 error = wskbd_displayioctl(sc->sc_kbddv, WSKBDIO_SETMODE, 1290 (caddr_t)&data, 0, 0); 1291 if (!error) 1292 sc->sc_rawkbd = raw; 1293 splx(s); 1294 return (error); 1295 } 1296 #endif 1297 1298 int 1299 wsdisplay_switch3(arg, error, waitok) 1300 void *arg; 1301 int error, waitok; 1302 { 1303 struct wsdisplay_softc *sc = arg; 1304 int no; 1305 struct wsscreen *scr; 1306 1307 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1308 printf("wsdisplay_switch3: not switching\n"); 1309 return (EINVAL); 1310 } 1311 1312 no = sc->sc_screenwanted; 1313 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1314 panic("wsdisplay_switch3: invalid screen %d", no); 1315 scr = sc->sc_scr[no]; 1316 if (!scr) { 1317 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1318 error = ENXIO; 1319 } 1320 1321 if (error) { 1322 /* try to recover, avoid recursion */ 1323 1324 if (sc->sc_oldscreen == -1) { 1325 printf("wsdisplay_switch3: giving up\n"); 1326 sc->sc_focus = 0; 1327 #ifdef WSDISPLAY_COMPAT_RAWKBD 1328 wsdisplay_update_rawkbd(sc, 0); 1329 #endif 1330 sc->sc_flags &= ~SC_SWITCHPENDING; 1331 return (error); 1332 } 1333 1334 sc->sc_screenwanted = sc->sc_oldscreen; 1335 sc->sc_oldscreen = -1; 1336 return (wsdisplay_switch1(arg, 0, waitok)); 1337 } 1338 1339 sc->sc_flags &= ~SC_SWITCHPENDING; 1340 1341 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1342 wakeup(scr); 1343 return (error); 1344 } 1345 1346 int 1347 wsdisplay_switch1(arg, error, waitok) 1348 void *arg; 1349 int error, waitok; 1350 { 1351 struct wsdisplay_softc *sc = arg; 1352 int no; 1353 struct wsscreen *scr; 1354 1355 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1356 printf("wsdisplay_switch1: not switching\n"); 1357 return (EINVAL); 1358 } 1359 1360 no = sc->sc_screenwanted; 1361 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1362 panic("wsdisplay_switch1: invalid screen %d", no); 1363 scr = sc->sc_scr[no]; 1364 if (!scr) { 1365 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1366 error = ENXIO; 1367 } 1368 1369 if (error) { 1370 sc->sc_flags &= ~SC_SWITCHPENDING; 1371 return (error); 1372 } 1373 1374 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1375 scr->scr_dconf->emulcookie); 1376 sc->sc_focusidx = no; 1377 sc->sc_focus = scr; 1378 1379 #ifdef WSDISPLAY_COMPAT_RAWKBD 1380 (void) wsdisplay_update_rawkbd(sc, scr); 1381 #endif 1382 /* keyboard map??? */ 1383 1384 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3) 1385 if (scr->scr_syncops) { 1386 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1387 wsswitch_cb3, sc); 1388 if (error == EAGAIN) { 1389 /* switch will be done asynchronously */ 1390 return (0); 1391 } 1392 } 1393 1394 return (wsdisplay_switch3(sc, error, waitok)); 1395 } 1396 1397 int 1398 wsdisplay_switch(dev, no, waitok) 1399 struct device *dev; 1400 int no, waitok; 1401 { 1402 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1403 int s, res = 0; 1404 struct wsscreen *scr; 1405 1406 if (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no]) 1407 return (ENXIO); 1408 1409 s = spltty(); 1410 1411 if (sc->sc_focus && no == sc->sc_focusidx) { 1412 splx(s); 1413 return (0); 1414 } 1415 1416 if (sc->sc_flags & SC_SWITCHPENDING) { 1417 splx(s); 1418 return (EBUSY); 1419 } 1420 1421 sc->sc_flags |= SC_SWITCHPENDING; 1422 sc->sc_screenwanted = no; 1423 1424 splx(s); 1425 1426 scr = sc->sc_focus; 1427 if (!scr) { 1428 sc->sc_oldscreen = -1; 1429 return (wsdisplay_switch1(sc, 0, waitok)); 1430 } else 1431 sc->sc_oldscreen = sc->sc_focusidx; 1432 1433 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1) 1434 if (scr->scr_syncops) { 1435 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1436 wsswitch_cb1, sc); 1437 if (res == EAGAIN) { 1438 /* switch will be done asynchronously */ 1439 return (0); 1440 } 1441 } else if (scr->scr_flags & SCR_GRAPHICS) { 1442 /* no way to save state */ 1443 res = EBUSY; 1444 } 1445 1446 return (wsdisplay_switch1(sc, res, waitok)); 1447 } 1448 1449 void 1450 wsdisplay_reset(dev, op) 1451 struct device *dev; 1452 enum wsdisplay_resetops op; 1453 { 1454 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1455 struct wsscreen *scr; 1456 1457 KASSERT(sc != NULL); 1458 scr = sc->sc_focus; 1459 1460 if (!scr) 1461 return; 1462 1463 switch (op) { 1464 case WSDISPLAY_RESETEMUL: 1465 if (!WSSCREEN_HAS_EMULATOR(scr)) 1466 break; 1467 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1468 WSEMUL_RESET); 1469 break; 1470 case WSDISPLAY_RESETCLOSE: 1471 wsdisplay_closescreen(sc, scr); 1472 break; 1473 } 1474 } 1475 1476 /* 1477 * Interface for (external) VT switch / process synchronization code 1478 */ 1479 int 1480 wsscreen_attach_sync(scr, ops, cookie) 1481 struct wsscreen *scr; 1482 const struct wscons_syncops *ops; 1483 void *cookie; 1484 { 1485 if (scr->scr_syncops) { 1486 /* 1487 * The screen is already claimed. 1488 * Check if the owner is still alive. 1489 */ 1490 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1491 return (EBUSY); 1492 } 1493 scr->scr_syncops = ops; 1494 scr->scr_synccookie = cookie; 1495 return (0); 1496 } 1497 1498 int 1499 wsscreen_detach_sync(scr) 1500 struct wsscreen *scr; 1501 { 1502 if (!scr->scr_syncops) 1503 return (EINVAL); 1504 scr->scr_syncops = 0; 1505 return (0); 1506 } 1507 1508 int 1509 wsscreen_lookup_sync(scr, ops, cookiep) 1510 struct wsscreen *scr; 1511 const struct wscons_syncops *ops; /* used as ID */ 1512 void **cookiep; 1513 { 1514 if (!scr->scr_syncops || ops != scr->scr_syncops) 1515 return (EINVAL); 1516 *cookiep = scr->scr_synccookie; 1517 return (0); 1518 } 1519 1520 /* 1521 * Interface to virtual screen stuff 1522 */ 1523 int 1524 wsdisplay_maxscreenidx(sc) 1525 struct wsdisplay_softc *sc; 1526 { 1527 return (WSDISPLAY_MAXSCREEN - 1); 1528 } 1529 1530 int 1531 wsdisplay_screenstate(sc, idx) 1532 struct wsdisplay_softc *sc; 1533 int idx; 1534 { 1535 if (idx >= WSDISPLAY_MAXSCREEN) 1536 return (EINVAL); 1537 if (!sc->sc_scr[idx]) 1538 return (ENXIO); 1539 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1540 } 1541 1542 int 1543 wsdisplay_getactivescreen(sc) 1544 struct wsdisplay_softc *sc; 1545 { 1546 return (sc->sc_focusidx); 1547 } 1548 1549 int 1550 wsscreen_switchwait(sc, no) 1551 struct wsdisplay_softc *sc; 1552 int no; 1553 { 1554 struct wsscreen *scr; 1555 int s, res = 0; 1556 1557 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1558 return (ENXIO); 1559 scr = sc->sc_scr[no]; 1560 if (!scr) 1561 return (ENXIO); 1562 1563 s = spltty(); 1564 if (scr != sc->sc_focus) { 1565 scr->scr_flags |= SCR_WAITACTIVE; 1566 res = tsleep(scr, PCATCH, "wswait", 0); 1567 if (scr != sc->sc_scr[no]) 1568 res = ENXIO; /* disappeared in the meantime */ 1569 else 1570 scr->scr_flags &= ~SCR_WAITACTIVE; 1571 } 1572 splx(s); 1573 return (res); 1574 } 1575 1576 void 1577 wsdisplay_kbdholdscreen(dev, hold) 1578 struct device *dev; 1579 int hold; 1580 { 1581 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1582 struct wsscreen *scr; 1583 1584 scr = sc->sc_focus; 1585 1586 if (hold) 1587 scr->scr_hold_screen = 1; 1588 else { 1589 scr->scr_hold_screen = 0; 1590 timeout(ttrstrt, scr->scr_tty, 0); /* "immediate" */ 1591 } 1592 } 1593 1594 /* 1595 * Calls from the glue code. 1596 */ 1597 int 1598 wsdisplay_is_console(dv) 1599 struct device *dv; 1600 { 1601 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv; 1602 1603 KASSERT(sc != NULL); 1604 return (sc->sc_isconsole); 1605 } 1606 1607 struct device * 1608 wsdisplay_kbd(dv) 1609 struct device *dv; 1610 { 1611 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv; 1612 1613 KASSERT(sc != NULL); 1614 return (sc->sc_kbddv); 1615 } 1616 1617 void 1618 wsdisplay_set_kbd(dv, kbddv) 1619 struct device *dv, *kbddv; 1620 { 1621 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv; 1622 1623 KASSERT(sc != NULL); 1624 if (sc->sc_kbddv) { 1625 /* disable old keyboard */ 1626 wskbd_enable(sc->sc_kbddv, 0); 1627 } 1628 if (kbddv) { 1629 /* enable new keyboard */ 1630 wskbd_enable(kbddv, 1); 1631 } 1632 sc->sc_kbddv = kbddv; 1633 } 1634 1635 /* 1636 * Console interface. 1637 */ 1638 void 1639 wsdisplay_cnputc(dev, i) 1640 dev_t dev; 1641 int i; 1642 { 1643 struct wsscreen_internal *dc; 1644 char c = i; 1645 1646 if (!wsdisplay_console_initted) 1647 return; 1648 1649 if (wsdisplay_console_device != NULL && 1650 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1651 return; 1652 1653 dc = &wsdisplay_console_conf; 1654 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1655 } 1656 1657 static int 1658 wsdisplay_getc_dummy(dev) 1659 dev_t dev; 1660 { 1661 /* panic? */ 1662 return (0); 1663 } 1664 1665 static void 1666 wsdisplay_pollc_dummy(dev, on) 1667 dev_t dev; 1668 int on; 1669 { 1670 } 1671 1672 void 1673 wsdisplay_set_cons_kbd(get, poll) 1674 int (*get) __P((dev_t)); 1675 void (*poll) __P((dev_t, int)); 1676 { 1677 wsdisplay_cons.cn_getc = get; 1678 wsdisplay_cons.cn_pollc = poll; 1679 } 1680