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