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