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