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