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