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