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