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