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