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