1 /* $NetBSD: wsdisplay.c,v 1.38 2000/06/26 04:56:32 simonb 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.38 2000/06/26 04:56:32 simonb 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 paddr_t 1124 wsdisplaymmap(dev, offset, prot) 1125 dev_t dev; 1126 off_t offset; 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 struct tty *tp; 1167 { 1168 struct wsdisplay_softc *sc; 1169 struct wsscreen *scr; 1170 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 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1224 ttrstrt, tp); 1225 } 1226 if (tp->t_outq.c_cc <= tp->t_lowat) { 1227 if (tp->t_state&TS_ASLEEP) { 1228 tp->t_state &= ~TS_ASLEEP; 1229 wakeup((caddr_t)&tp->t_outq); 1230 } 1231 selwakeup(&tp->t_wsel); 1232 } 1233 splx(s); 1234 } 1235 1236 void 1237 wsdisplaystop(tp, flag) 1238 struct tty *tp; 1239 int flag; 1240 { 1241 int s; 1242 1243 s = spltty(); 1244 if (ISSET(tp->t_state, TS_BUSY)) 1245 if (!ISSET(tp->t_state, TS_TTSTOP)) 1246 SET(tp->t_state, TS_FLUSH); 1247 splx(s); 1248 } 1249 1250 /* Set line parameters. */ 1251 int 1252 wsdisplayparam(tp, t) 1253 struct tty *tp; 1254 struct termios *t; 1255 { 1256 1257 tp->t_ispeed = t->c_ispeed; 1258 tp->t_ospeed = t->c_ospeed; 1259 tp->t_cflag = t->c_cflag; 1260 return 0; 1261 } 1262 1263 /* 1264 * Callbacks for the emulation code. 1265 */ 1266 void 1267 wsdisplay_emulbell(v) 1268 void *v; 1269 { 1270 struct wsscreen *scr = v; 1271 1272 if (scr == NULL) /* console, before real attach */ 1273 return; 1274 1275 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1276 return; 1277 1278 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1279 FWRITE, NULL); 1280 } 1281 1282 void 1283 wsdisplay_emulinput(v, data, count) 1284 void *v; 1285 const u_char *data; 1286 u_int count; 1287 { 1288 struct wsscreen *scr = v; 1289 struct tty *tp; 1290 1291 if (v == NULL) /* console, before real attach */ 1292 return; 1293 1294 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1295 return; 1296 if (!WSSCREEN_HAS_TTY(scr)) 1297 return; 1298 1299 tp = scr->scr_tty; 1300 while (count-- > 0) 1301 (*linesw[tp->t_line].l_rint)(*data++, tp); 1302 }; 1303 1304 /* 1305 * Calls from the keyboard interface. 1306 */ 1307 void 1308 wsdisplay_kbdinput(dev, ks) 1309 struct device *dev; 1310 keysym_t ks; 1311 { 1312 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1313 struct wsscreen *scr; 1314 char *dp; 1315 int count; 1316 struct tty *tp; 1317 1318 KASSERT(sc != NULL); 1319 1320 scr = sc->sc_focus; 1321 1322 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1323 return; 1324 1325 tp = scr->scr_tty; 1326 1327 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1328 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp); 1329 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1330 count = (*scr->scr_dconf->wsemul->translate) 1331 (scr->scr_dconf->wsemulcookie, ks, &dp); 1332 while (count-- > 0) 1333 (*linesw[tp->t_line].l_rint)(*dp++, tp); 1334 } 1335 } 1336 1337 #ifdef WSDISPLAY_COMPAT_RAWKBD 1338 int 1339 wsdisplay_update_rawkbd(sc, scr) 1340 struct wsdisplay_softc *sc; 1341 struct wsscreen *scr; 1342 { 1343 int s, raw, data, error; 1344 s = spltty(); 1345 1346 raw = (scr ? scr->scr_rawkbd : 0); 1347 1348 if (scr != sc->sc_focus || 1349 sc->sc_rawkbd == raw) { 1350 splx(s); 1351 return (0); 1352 } 1353 1354 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1355 error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, WSKBDIO_SETMODE, 1356 (caddr_t)&data, 0, 0); 1357 if (!error) 1358 sc->sc_rawkbd = raw; 1359 splx(s); 1360 return (error); 1361 } 1362 #endif 1363 1364 int 1365 wsdisplay_switch3(arg, error, waitok) 1366 void *arg; 1367 int error, waitok; 1368 { 1369 struct wsdisplay_softc *sc = arg; 1370 int no; 1371 struct wsscreen *scr; 1372 1373 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1374 printf("wsdisplay_switch3: not switching\n"); 1375 return (EINVAL); 1376 } 1377 1378 no = sc->sc_screenwanted; 1379 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1380 panic("wsdisplay_switch3: invalid screen %d", no); 1381 scr = sc->sc_scr[no]; 1382 if (!scr) { 1383 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1384 error = ENXIO; 1385 } 1386 1387 if (error) { 1388 /* try to recover, avoid recursion */ 1389 1390 if (sc->sc_oldscreen == -1) { 1391 printf("wsdisplay_switch3: giving up\n"); 1392 sc->sc_focus = 0; 1393 #ifdef WSDISPLAY_COMPAT_RAWKBD 1394 wsdisplay_update_rawkbd(sc, 0); 1395 #endif 1396 sc->sc_flags &= ~SC_SWITCHPENDING; 1397 return (error); 1398 } 1399 1400 sc->sc_screenwanted = sc->sc_oldscreen; 1401 sc->sc_oldscreen = -1; 1402 return (wsdisplay_switch1(arg, 0, waitok)); 1403 } 1404 1405 sc->sc_flags &= ~SC_SWITCHPENDING; 1406 1407 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1408 wakeup(scr); 1409 return (error); 1410 } 1411 1412 int 1413 wsdisplay_switch2(arg, error, waitok) 1414 void *arg; 1415 int error, waitok; 1416 { 1417 struct wsdisplay_softc *sc = arg; 1418 int no; 1419 struct wsscreen *scr; 1420 1421 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1422 printf("wsdisplay_switch2: not switching\n"); 1423 return (EINVAL); 1424 } 1425 1426 no = sc->sc_screenwanted; 1427 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1428 panic("wsdisplay_switch2: invalid screen %d", no); 1429 scr = sc->sc_scr[no]; 1430 if (!scr) { 1431 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1432 error = ENXIO; 1433 } 1434 1435 if (error) { 1436 /* try to recover, avoid recursion */ 1437 1438 if (sc->sc_oldscreen == -1) { 1439 printf("wsdisplay_switch2: giving up\n"); 1440 sc->sc_focus = 0; 1441 sc->sc_flags &= ~SC_SWITCHPENDING; 1442 return (error); 1443 } 1444 1445 sc->sc_screenwanted = sc->sc_oldscreen; 1446 sc->sc_oldscreen = -1; 1447 return (wsdisplay_switch1(arg, 0, waitok)); 1448 } 1449 1450 sc->sc_focusidx = no; 1451 sc->sc_focus = scr; 1452 1453 #ifdef WSDISPLAY_COMPAT_RAWKBD 1454 (void) wsdisplay_update_rawkbd(sc, scr); 1455 #endif 1456 /* keyboard map??? */ 1457 1458 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3) 1459 if (scr->scr_syncops) { 1460 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1461 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1462 if (error == EAGAIN) { 1463 /* switch will be done asynchronously */ 1464 return (0); 1465 } 1466 } 1467 1468 return (wsdisplay_switch3(sc, error, waitok)); 1469 } 1470 1471 int 1472 wsdisplay_switch1(arg, error, waitok) 1473 void *arg; 1474 int error, waitok; 1475 { 1476 struct wsdisplay_softc *sc = arg; 1477 int no; 1478 struct wsscreen *scr; 1479 1480 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1481 printf("wsdisplay_switch1: not switching\n"); 1482 return (EINVAL); 1483 } 1484 1485 no = sc->sc_screenwanted; 1486 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1487 panic("wsdisplay_switch1: invalid screen %d", no); 1488 scr = sc->sc_scr[no]; 1489 if (!scr) { 1490 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1491 error = ENXIO; 1492 } 1493 1494 if (error) { 1495 sc->sc_flags &= ~SC_SWITCHPENDING; 1496 return (error); 1497 } 1498 1499 #define wsswitch_cb2 ((void (*) __P((void *, int, int)))wsdisplay_switch2) 1500 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1501 scr->scr_dconf->emulcookie, 1502 waitok, 1503 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1504 if (error == EAGAIN) { 1505 /* switch will be done asynchronously */ 1506 return (0); 1507 } 1508 1509 return (wsdisplay_switch2(sc, error, waitok)); 1510 } 1511 1512 int 1513 wsdisplay_switch(dev, no, waitok) 1514 struct device *dev; 1515 int no, waitok; 1516 { 1517 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1518 int s, res = 0; 1519 struct wsscreen *scr; 1520 1521 if (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no]) 1522 return (ENXIO); 1523 1524 s = spltty(); 1525 1526 if (sc->sc_focus && no == sc->sc_focusidx) { 1527 splx(s); 1528 return (0); 1529 } 1530 1531 if (sc->sc_flags & SC_SWITCHPENDING) { 1532 splx(s); 1533 return (EBUSY); 1534 } 1535 1536 sc->sc_flags |= SC_SWITCHPENDING; 1537 sc->sc_screenwanted = no; 1538 1539 splx(s); 1540 1541 scr = sc->sc_focus; 1542 if (!scr) { 1543 sc->sc_oldscreen = -1; 1544 return (wsdisplay_switch1(sc, 0, waitok)); 1545 } else 1546 sc->sc_oldscreen = sc->sc_focusidx; 1547 1548 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1) 1549 if (scr->scr_syncops) { 1550 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1551 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1552 if (res == EAGAIN) { 1553 /* switch will be done asynchronously */ 1554 return (0); 1555 } 1556 } else if (scr->scr_flags & SCR_GRAPHICS) { 1557 /* no way to save state */ 1558 res = EBUSY; 1559 } 1560 1561 return (wsdisplay_switch1(sc, res, waitok)); 1562 } 1563 1564 void 1565 wsdisplay_reset(dev, op) 1566 struct device *dev; 1567 enum wsdisplay_resetops op; 1568 { 1569 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1570 struct wsscreen *scr; 1571 1572 KASSERT(sc != NULL); 1573 scr = sc->sc_focus; 1574 1575 if (!scr) 1576 return; 1577 1578 switch (op) { 1579 case WSDISPLAY_RESETEMUL: 1580 if (!WSSCREEN_HAS_EMULATOR(scr)) 1581 break; 1582 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1583 WSEMUL_RESET); 1584 break; 1585 case WSDISPLAY_RESETCLOSE: 1586 wsdisplay_closescreen(sc, scr); 1587 break; 1588 } 1589 } 1590 1591 /* 1592 * Interface for (external) VT switch / process synchronization code 1593 */ 1594 int 1595 wsscreen_attach_sync(scr, ops, cookie) 1596 struct wsscreen *scr; 1597 const struct wscons_syncops *ops; 1598 void *cookie; 1599 { 1600 if (scr->scr_syncops) { 1601 /* 1602 * The screen is already claimed. 1603 * Check if the owner is still alive. 1604 */ 1605 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1606 return (EBUSY); 1607 } 1608 scr->scr_syncops = ops; 1609 scr->scr_synccookie = cookie; 1610 return (0); 1611 } 1612 1613 int 1614 wsscreen_detach_sync(scr) 1615 struct wsscreen *scr; 1616 { 1617 if (!scr->scr_syncops) 1618 return (EINVAL); 1619 scr->scr_syncops = 0; 1620 return (0); 1621 } 1622 1623 int 1624 wsscreen_lookup_sync(scr, ops, cookiep) 1625 struct wsscreen *scr; 1626 const struct wscons_syncops *ops; /* used as ID */ 1627 void **cookiep; 1628 { 1629 if (!scr->scr_syncops || ops != scr->scr_syncops) 1630 return (EINVAL); 1631 *cookiep = scr->scr_synccookie; 1632 return (0); 1633 } 1634 1635 /* 1636 * Interface to virtual screen stuff 1637 */ 1638 int 1639 wsdisplay_maxscreenidx(sc) 1640 struct wsdisplay_softc *sc; 1641 { 1642 return (WSDISPLAY_MAXSCREEN - 1); 1643 } 1644 1645 int 1646 wsdisplay_screenstate(sc, idx) 1647 struct wsdisplay_softc *sc; 1648 int idx; 1649 { 1650 if (idx >= WSDISPLAY_MAXSCREEN) 1651 return (EINVAL); 1652 if (!sc->sc_scr[idx]) 1653 return (ENXIO); 1654 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1655 } 1656 1657 int 1658 wsdisplay_getactivescreen(sc) 1659 struct wsdisplay_softc *sc; 1660 { 1661 return (sc->sc_focusidx); 1662 } 1663 1664 int 1665 wsscreen_switchwait(sc, no) 1666 struct wsdisplay_softc *sc; 1667 int no; 1668 { 1669 struct wsscreen *scr; 1670 int s, res = 0; 1671 1672 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1673 return (ENXIO); 1674 scr = sc->sc_scr[no]; 1675 if (!scr) 1676 return (ENXIO); 1677 1678 s = spltty(); 1679 if (scr != sc->sc_focus) { 1680 scr->scr_flags |= SCR_WAITACTIVE; 1681 res = tsleep(scr, PCATCH, "wswait", 0); 1682 if (scr != sc->sc_scr[no]) 1683 res = ENXIO; /* disappeared in the meantime */ 1684 else 1685 scr->scr_flags &= ~SCR_WAITACTIVE; 1686 } 1687 splx(s); 1688 return (res); 1689 } 1690 1691 void 1692 wsdisplay_kbdholdscreen(dev, hold) 1693 struct device *dev; 1694 int hold; 1695 { 1696 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1697 struct wsscreen *scr; 1698 1699 scr = sc->sc_focus; 1700 1701 if (hold) 1702 scr->scr_hold_screen = 1; 1703 else { 1704 scr->scr_hold_screen = 0; 1705 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1706 ttrstrt, scr->scr_tty); /* "immediate" */ 1707 } 1708 } 1709 1710 #if NWSKBD > 0 1711 struct device * 1712 wsdisplay_set_console_kbd(kbddv) 1713 struct device *kbddv; 1714 { 1715 if (!wsdisplay_console_device) 1716 return (0); 1717 if (wskbd_add_mux(kbddv->dv_unit, wsdisplay_console_device->sc_muxdv)) 1718 return (0); 1719 return (&wsdisplay_console_device->sc_dv); 1720 } 1721 #endif /* NWSKBD > 0 */ 1722 1723 /* 1724 * Console interface. 1725 */ 1726 void 1727 wsdisplay_cnputc(dev, i) 1728 dev_t dev; 1729 int i; 1730 { 1731 struct wsscreen_internal *dc; 1732 char c = i; 1733 1734 if (!wsdisplay_console_initted) 1735 return; 1736 1737 if (wsdisplay_console_device != NULL && 1738 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1739 return; 1740 1741 dc = &wsdisplay_console_conf; 1742 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1743 } 1744 1745 static int 1746 wsdisplay_getc_dummy(dev) 1747 dev_t dev; 1748 { 1749 /* panic? */ 1750 return (0); 1751 } 1752 1753 static void 1754 wsdisplay_pollc(dev, on) 1755 dev_t dev; 1756 int on; 1757 { 1758 1759 wsdisplay_cons_pollmode = on; 1760 1761 if (wsdisplay_cons_kbd_pollc) 1762 (*wsdisplay_cons_kbd_pollc)(dev, on); 1763 } 1764 1765 void 1766 wsdisplay_set_cons_kbd(get, poll, bell) 1767 int (*get) __P((dev_t)); 1768 void (*poll) __P((dev_t, int)); 1769 void (*bell) __P((dev_t, u_int, u_int, u_int)); 1770 { 1771 wsdisplay_cons.cn_getc = get; 1772 wsdisplay_cons.cn_bell = bell; 1773 wsdisplay_cons_kbd_pollc = poll; 1774 } 1775 1776 void 1777 wsdisplay_unset_cons_kbd() 1778 { 1779 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1780 wsdisplay_cons.cn_bell = NULL; 1781 wsdisplay_cons_kbd_pollc = 0; 1782 } 1783 1784 /* 1785 * Switch the console display to it's first screen. 1786 */ 1787 void 1788 wsdisplay_switchtoconsole() 1789 { 1790 if (wsdisplay_console_device != NULL) 1791 wsdisplay_switch((struct device *)wsdisplay_console_device, 1792 0, 0); 1793 } 1794 1795 /* 1796 * Switch the console at shutdown. 1797 */ 1798 static void 1799 wsdisplay_shutdownhook(arg) 1800 void *arg; 1801 { 1802 wsdisplay_switchtoconsole(); 1803 } 1804