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