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