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