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