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