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