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