1 /* $NetBSD: wsdisplay.c,v 1.132 2010/03/11 04:00:36 mrg 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.132 2010/03/11 04:00:36 mrg 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, const 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, const 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 aprint_naive("\n"); 782 783 #if NWSKBD > 0 && NWSMUX > 0 784 wsmux_set_display(mux, sc->sc_dev); 785 #endif 786 787 mutex_init(&sc->sc_flagsmtx, MUTEX_DEFAULT, IPL_NONE); 788 cv_init(&sc->sc_flagscv, "wssw"); 789 790 sc->sc_accessops = accessops; 791 sc->sc_accesscookie = accesscookie; 792 sc->sc_scrdata = scrdata; 793 794 #ifdef WSDISPLAY_SCROLLSUPPORT 795 sc->sc_scroll_values = wsdisplay_default_scroll_values; 796 #endif 797 798 /* 799 * Set up a number of virtual screens if wanted. The 800 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 801 * is for special cases like installation kernels. 802 */ 803 for (i = start; i < wsdisplay_defaultscreens; i++) { 804 if (wsdisplay_addscreen(sc, i, 0, 0)) 805 break; 806 } 807 808 if (i > start) 809 wsdisplay_addscreen_print(sc, start, i-start); 810 811 if (!pmf_device_register(sc->sc_dev, wsdisplay_suspend, NULL)) 812 aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); 813 } 814 815 void 816 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie, 817 int ccol, int crow, long defattr) 818 { 819 const struct wsemul_ops *wsemul; 820 821 KASSERT(wsdisplay_console_initted < 2); 822 KASSERT(type->nrows > 0); 823 KASSERT(type->ncols > 0); 824 KASSERT(crow < type->nrows); 825 KASSERT(ccol < type->ncols); 826 827 wsdisplay_console_conf.emulops = type->textops; 828 wsdisplay_console_conf.emulcookie = cookie; 829 wsdisplay_console_conf.scrdata = type; 830 831 wsemul = wsemul_pick(0); /* default */ 832 wsdisplay_console_conf.wsemul = wsemul; 833 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 834 ccol, crow, 835 defattr); 836 837 cn_tab = &wsdisplay_cons; 838 wsdisplay_console_initted = 2; 839 } 840 841 void 842 wsdisplay_preattach(const struct wsscreen_descr *type, void *cookie, 843 int ccol, int crow, long defattr) 844 { 845 const struct wsemul_ops *wsemul; 846 847 KASSERT(!wsdisplay_console_initted); 848 KASSERT(type->nrows > 0); 849 KASSERT(type->ncols > 0); 850 KASSERT(crow < type->nrows); 851 KASSERT(ccol < type->ncols); 852 853 wsdisplay_console_conf.emulops = type->textops; 854 wsdisplay_console_conf.emulcookie = cookie; 855 wsdisplay_console_conf.scrdata = type; 856 857 wsemul = wsemul_pick(0); /* default */ 858 wsdisplay_console_conf.wsemul = wsemul; 859 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 860 ccol, crow, 861 defattr); 862 863 cn_tab = &wsdisplay_cons; 864 wsdisplay_console_initted = 1; 865 } 866 867 /* 868 * Tty and cdevsw functions. 869 */ 870 int 871 wsdisplayopen(dev_t dev, int flag, int mode, struct lwp *l) 872 { 873 struct wsdisplay_softc *sc; 874 struct tty *tp; 875 int newopen, error; 876 struct wsscreen *scr; 877 878 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 879 if (sc == NULL) /* make sure it was attached */ 880 return (ENXIO); 881 882 if (ISWSDISPLAYSTAT(dev)) { 883 wsevent_init(&sc->evar, l->l_proc); 884 return (0); 885 } 886 887 if (ISWSDISPLAYCTL(dev)) 888 return (0); 889 890 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 891 return (ENXIO); 892 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 893 return (ENXIO); 894 895 if (WSSCREEN_HAS_TTY(scr)) { 896 tp = scr->scr_tty; 897 tp->t_oproc = wsdisplaystart; 898 tp->t_param = wsdisplayparam; 899 tp->t_dev = dev; 900 newopen = (tp->t_state & TS_ISOPEN) == 0; 901 902 if (kauth_authorize_device_tty(l->l_cred, 903 KAUTH_DEVICE_TTY_OPEN, tp)) 904 return (EBUSY); 905 906 if (newopen) { 907 ttychars(tp); 908 tp->t_iflag = TTYDEF_IFLAG; 909 tp->t_oflag = TTYDEF_OFLAG; 910 tp->t_cflag = TTYDEF_CFLAG; 911 tp->t_lflag = TTYDEF_LFLAG; 912 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 913 wsdisplayparam(tp, &tp->t_termios); 914 ttsetwater(tp); 915 } 916 tp->t_state |= TS_CARR_ON; 917 918 error = ((*tp->t_linesw->l_open)(dev, tp)); 919 if (error) 920 return (error); 921 922 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 923 /* set window sizes as appropriate, and reset 924 the emulation */ 925 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 926 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 927 928 /* wsdisplay_set_emulation() */ 929 } 930 } 931 932 scr->scr_flags |= SCR_OPEN; 933 return (0); 934 } 935 936 int 937 wsdisplayclose(dev_t dev, int flag, int mode, struct lwp *l) 938 { 939 device_t dv; 940 struct wsdisplay_softc *sc; 941 struct tty *tp; 942 struct wsscreen *scr; 943 944 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 945 sc = device_private(dv); 946 947 if (ISWSDISPLAYSTAT(dev)) { 948 wsevent_fini(&sc->evar); 949 return (0); 950 } 951 952 if (ISWSDISPLAYCTL(dev)) 953 return (0); 954 955 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 956 return (0); 957 958 if (WSSCREEN_HAS_TTY(scr)) { 959 if (scr->scr_hold_screen) { 960 int s; 961 962 /* XXX RESET KEYBOARD LEDS, etc. */ 963 s = spltty(); /* avoid conflict with keyboard */ 964 wsdisplay_kbdholdscreen(dv, 0); 965 splx(s); 966 } 967 tp = scr->scr_tty; 968 (*tp->t_linesw->l_close)(tp, flag); 969 ttyclose(tp); 970 } 971 972 if (scr->scr_syncops) 973 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 974 975 if (WSSCREEN_HAS_EMULATOR(scr)) { 976 scr->scr_flags &= ~SCR_GRAPHICS; 977 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 978 WSEMUL_RESET); 979 if (wsdisplay_clearonclose) 980 (*scr->scr_dconf->wsemul->reset) 981 (scr->scr_dconf->wsemulcookie, 982 WSEMUL_CLEARSCREEN); 983 } 984 985 #ifdef WSDISPLAY_COMPAT_RAWKBD 986 if (scr->scr_rawkbd) { 987 int kbmode = WSKBD_TRANSLATED; 988 (void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 989 (void *)&kbmode, 0, l); 990 } 991 #endif 992 993 scr->scr_flags &= ~SCR_OPEN; 994 995 return (0); 996 } 997 998 int 999 wsdisplayread(dev_t dev, struct uio *uio, int flag) 1000 { 1001 struct wsdisplay_softc *sc; 1002 struct tty *tp; 1003 struct wsscreen *scr; 1004 int error; 1005 1006 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1007 1008 if (ISWSDISPLAYSTAT(dev)) { 1009 error = wsevent_read(&sc->evar, uio, flag); 1010 return (error); 1011 } 1012 1013 if (ISWSDISPLAYCTL(dev)) 1014 return (0); 1015 1016 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1017 return (ENXIO); 1018 1019 if (!WSSCREEN_HAS_TTY(scr)) 1020 return (ENODEV); 1021 1022 tp = scr->scr_tty; 1023 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 1024 } 1025 1026 int 1027 wsdisplaywrite(dev_t dev, struct uio *uio, int flag) 1028 { 1029 struct wsdisplay_softc *sc; 1030 struct tty *tp; 1031 struct wsscreen *scr; 1032 1033 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1034 1035 if (ISWSDISPLAYSTAT(dev)) { 1036 return (0); 1037 } 1038 1039 if (ISWSDISPLAYCTL(dev)) 1040 return (0); 1041 1042 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1043 return (ENXIO); 1044 1045 if (!WSSCREEN_HAS_TTY(scr)) 1046 return (ENODEV); 1047 1048 tp = scr->scr_tty; 1049 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 1050 } 1051 1052 int 1053 wsdisplaypoll(dev_t dev, int events, struct lwp *l) 1054 { 1055 struct wsdisplay_softc *sc; 1056 struct tty *tp; 1057 struct wsscreen *scr; 1058 1059 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1060 1061 if (ISWSDISPLAYSTAT(dev)) 1062 return (wsevent_poll(&sc->evar, events, l)); 1063 1064 if (ISWSDISPLAYCTL(dev)) 1065 return (0); 1066 1067 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1068 return (POLLHUP); 1069 1070 if (!WSSCREEN_HAS_TTY(scr)) 1071 return (POLLERR); 1072 1073 tp = scr->scr_tty; 1074 return ((*tp->t_linesw->l_poll)(tp, events, l)); 1075 } 1076 1077 int 1078 wsdisplaykqfilter(dev_t dev, struct knote *kn) 1079 { 1080 struct wsdisplay_softc *sc; 1081 struct wsscreen *scr; 1082 1083 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1084 1085 if (ISWSDISPLAYCTL(dev)) 1086 return (1); 1087 1088 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1089 return (1); 1090 1091 1092 if (WSSCREEN_HAS_TTY(scr)) 1093 return (ttykqfilter(dev, kn)); 1094 else 1095 return (1); 1096 } 1097 1098 struct tty * 1099 wsdisplaytty(dev_t dev) 1100 { 1101 struct wsdisplay_softc *sc; 1102 struct wsscreen *scr; 1103 1104 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1105 1106 if (ISWSDISPLAYSTAT(dev)) 1107 panic("wsdisplaytty() on status device"); 1108 1109 if (ISWSDISPLAYCTL(dev)) 1110 panic("wsdisplaytty() on ctl device"); 1111 1112 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1113 return NULL; 1114 1115 return (scr->scr_tty); 1116 } 1117 1118 int 1119 wsdisplayioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1120 { 1121 device_t dv; 1122 struct wsdisplay_softc *sc; 1123 struct tty *tp; 1124 int error; 1125 struct wsscreen *scr; 1126 1127 dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1128 sc = device_private(dv); 1129 1130 #ifdef WSDISPLAY_COMPAT_USL 1131 error = wsdisplay_usl_ioctl1(dv, cmd, data, flag, l); 1132 if (error != EPASSTHROUGH) 1133 return (error); 1134 #endif 1135 1136 if (ISWSDISPLAYSTAT(dev)) 1137 return (wsdisplay_stat_ioctl(sc, cmd, data, flag, l)); 1138 1139 if (ISWSDISPLAYCTL(dev)) 1140 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, l)); 1141 1142 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1143 return (ENXIO); 1144 1145 if (WSSCREEN_HAS_TTY(scr)) { 1146 tp = scr->scr_tty; 1147 1148 /* printf("disc\n"); */ 1149 /* do the line discipline ioctls first */ 1150 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 1151 if (error != EPASSTHROUGH) 1152 return (error); 1153 1154 /* printf("tty\n"); */ 1155 /* then the tty ioctls */ 1156 error = ttioctl(tp, cmd, data, flag, l); 1157 if (error != EPASSTHROUGH) 1158 return (error); 1159 } 1160 1161 #ifdef WSDISPLAY_COMPAT_USL 1162 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, l); 1163 if (error != EPASSTHROUGH) 1164 return (error); 1165 #endif 1166 1167 return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, l)); 1168 } 1169 1170 int 1171 wsdisplay_param(device_t dv, u_long cmd, struct wsdisplay_param *dp) 1172 { 1173 struct wsdisplay_softc *sc = device_private(dv); 1174 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1175 sc->sc_focus->scr_dconf->emulcookie, 1176 cmd, (void *)dp, 0, NULL)); 1177 } 1178 1179 int 1180 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 1181 u_long cmd, void *data, int flag, struct lwp *l) 1182 { 1183 int error; 1184 char namebuf[16]; 1185 struct wsdisplay_font fd; 1186 #ifdef WSDISPLAY_SCROLLSUPPORT 1187 struct wsdisplay_scroll_data *ksdp, *usdp; 1188 #endif 1189 1190 #if NWSKBD > 0 1191 struct wsevsrc *inp; 1192 1193 #ifdef WSDISPLAY_COMPAT_RAWKBD 1194 switch (cmd) { 1195 case WSKBDIO_SETMODE: 1196 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 1197 return (wsdisplay_update_rawkbd(sc, scr)); 1198 case WSKBDIO_GETMODE: 1199 *(int *)data = (scr->scr_rawkbd ? 1200 WSKBD_RAW : WSKBD_TRANSLATED); 1201 return (0); 1202 } 1203 #endif 1204 inp = sc->sc_input; 1205 if (inp == NULL) 1206 return (ENXIO); 1207 error = wsevsrc_display_ioctl(inp, cmd, data, flag, l); 1208 if (error != EPASSTHROUGH) 1209 return (error); 1210 #endif /* NWSKBD > 0 */ 1211 1212 switch (cmd) { 1213 case WSDISPLAYIO_GMODE: 1214 if (scr->scr_flags & SCR_GRAPHICS) { 1215 if (scr->scr_flags & SCR_DUMBFB) 1216 *(u_int *)data = WSDISPLAYIO_MODE_DUMBFB; 1217 else 1218 *(u_int *)data = WSDISPLAYIO_MODE_MAPPED; 1219 } else 1220 *(u_int *)data = WSDISPLAYIO_MODE_EMUL; 1221 return (0); 1222 1223 case WSDISPLAYIO_SMODE: 1224 #define d (*(int *)data) 1225 if (d != WSDISPLAYIO_MODE_EMUL && 1226 d != WSDISPLAYIO_MODE_MAPPED && 1227 d != WSDISPLAYIO_MODE_DUMBFB) 1228 return (EINVAL); 1229 1230 if (WSSCREEN_HAS_EMULATOR(scr)) { 1231 scr->scr_flags &= ~SCR_GRAPHICS; 1232 if (d == WSDISPLAYIO_MODE_MAPPED || 1233 d == WSDISPLAYIO_MODE_DUMBFB) 1234 scr->scr_flags |= SCR_GRAPHICS | 1235 ((d == WSDISPLAYIO_MODE_DUMBFB) ? SCR_DUMBFB : 0); 1236 } else if (d == WSDISPLAYIO_MODE_EMUL) 1237 return (EINVAL); 1238 1239 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1240 scr->scr_dconf->emulcookie, cmd, data, flag, l); 1241 1242 return (0); 1243 #undef d 1244 1245 #ifdef WSDISPLAY_SCROLLSUPPORT 1246 #define SETSCROLLLINES(dstp, srcp, dfltp) \ 1247 do { \ 1248 (dstp)->fastlines = ((srcp)->which & \ 1249 WSDISPLAY_SCROLL_DOFASTLINES) ? \ 1250 (srcp)->fastlines : (dfltp)->fastlines; \ 1251 (dstp)->slowlines = ((srcp)->which & \ 1252 WSDISPLAY_SCROLL_DOSLOWLINES) ? \ 1253 (srcp)->slowlines : (dfltp)->slowlines; \ 1254 (dstp)->which = WSDISPLAY_SCROLL_DOALL; \ 1255 } while (0) 1256 1257 1258 case WSDISPLAYIO_DSSCROLL: 1259 usdp = (struct wsdisplay_scroll_data *)data; 1260 ksdp = &sc->sc_scroll_values; 1261 SETSCROLLLINES(ksdp, usdp, ksdp); 1262 return (0); 1263 1264 case WSDISPLAYIO_DGSCROLL: 1265 usdp = (struct wsdisplay_scroll_data *)data; 1266 ksdp = &sc->sc_scroll_values; 1267 SETSCROLLLINES(usdp, ksdp, ksdp); 1268 return (0); 1269 #else 1270 case WSDISPLAYIO_DSSCROLL: 1271 case WSDISPLAYIO_DGSCROLL: 1272 return ENODEV; 1273 #endif 1274 1275 case WSDISPLAYIO_SFONT: 1276 #define d ((struct wsdisplay_usefontdata *)data) 1277 if (!sc->sc_accessops->load_font) 1278 return (EINVAL); 1279 if (d->name) { 1280 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 1281 if (error) 1282 return (error); 1283 fd.name = namebuf; 1284 } else 1285 fd.name = 0; 1286 fd.data = 0; 1287 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 1288 scr->scr_dconf->emulcookie, &fd); 1289 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 1290 (*scr->scr_dconf->wsemul->reset) 1291 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 1292 return (error); 1293 #undef d 1294 1295 #ifdef WSDISPLAY_CUSTOM_OUTPUT 1296 case WSDISPLAYIO_GMSGATTRS: 1297 #define d ((struct wsdisplay_msgattrs *)data) 1298 (*scr->scr_dconf->wsemul->getmsgattrs) 1299 (scr->scr_dconf->wsemulcookie, d); 1300 return (0); 1301 #undef d 1302 1303 case WSDISPLAYIO_SMSGATTRS: { 1304 #define d ((struct wsdisplay_msgattrs *)data) 1305 int i; 1306 for (i = 0; i < WSDISPLAY_MAXSCREEN; i++) 1307 if (sc->sc_scr[i] != NULL) 1308 (*sc->sc_scr[i]->scr_dconf->wsemul->setmsgattrs) 1309 (sc->sc_scr[i]->scr_dconf->wsemulcookie, 1310 sc->sc_scr[i]->scr_dconf->scrdata, 1311 d); 1312 } 1313 return (0); 1314 #undef d 1315 #else 1316 case WSDISPLAYIO_GMSGATTRS: 1317 case WSDISPLAYIO_SMSGATTRS: 1318 return (ENODEV); 1319 #endif 1320 case WSDISPLAYIO_SETVERSION: 1321 return wsevent_setversion(&sc->evar, *(int *)data); 1322 } 1323 1324 /* check ioctls for display */ 1325 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1326 scr->scr_dconf->emulcookie, cmd, data, flag, l)); 1327 } 1328 1329 int 1330 wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data, 1331 int flag, struct lwp *l) 1332 { 1333 switch (cmd) { 1334 case WSDISPLAYIO_GETACTIVESCREEN: 1335 *(int*)data = wsdisplay_getactivescreen(sc); 1336 return (0); 1337 } 1338 1339 return (EPASSTHROUGH); 1340 } 1341 1342 int 1343 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data, 1344 int flag, struct lwp *l) 1345 { 1346 int error; 1347 char *type, typebuf[16], *emul, emulbuf[16]; 1348 void *tbuf; 1349 u_int fontsz; 1350 #if defined(COMPAT_14) && NWSKBD > 0 1351 struct wsmux_device wsmuxdata; 1352 #endif 1353 #if NWSKBD > 0 1354 struct wsevsrc *inp; 1355 #endif 1356 1357 switch (cmd) { 1358 case WSDISPLAYIO_ADDSCREEN: 1359 #define d ((struct wsdisplay_addscreendata *)data) 1360 if (d->screentype) { 1361 error = copyinstr(d->screentype, typebuf, 1362 sizeof(typebuf), 0); 1363 if (error) 1364 return (error); 1365 type = typebuf; 1366 } else 1367 type = 0; 1368 if (d->emul) { 1369 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1370 if (error) 1371 return (error); 1372 emul = emulbuf; 1373 } else 1374 emul = 0; 1375 1376 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1377 wsdisplay_addscreen_print(sc, d->idx, 0); 1378 return (error); 1379 #undef d 1380 case WSDISPLAYIO_DELSCREEN: 1381 #define d ((struct wsdisplay_delscreendata *)data) 1382 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1383 #undef d 1384 case WSDISPLAYIO_LDFONT: 1385 #define d ((struct wsdisplay_font *)data) 1386 if (!sc->sc_accessops->load_font) 1387 return (EINVAL); 1388 if (d->name) { 1389 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1390 if (error) 1391 return (error); 1392 d->name = typebuf; 1393 } else 1394 d->name = "loaded"; /* ??? */ 1395 fontsz = d->fontheight * d->stride * d->numchars; 1396 if (fontsz > WSDISPLAY_MAXFONTSZ) 1397 return (EINVAL); 1398 1399 tbuf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1400 error = copyin(d->data, tbuf, fontsz); 1401 if (error) { 1402 free(tbuf, M_DEVBUF); 1403 return (error); 1404 } 1405 d->data = tbuf; 1406 error = 1407 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1408 free(tbuf, M_DEVBUF); 1409 #undef d 1410 return (error); 1411 1412 #if NWSKBD > 0 1413 #ifdef COMPAT_14 1414 case _O_WSDISPLAYIO_SETKEYBOARD: 1415 #define d ((struct wsdisplay_kbddata *)data) 1416 inp = sc->sc_input; 1417 if (inp == NULL) 1418 return (ENXIO); 1419 switch (d->op) { 1420 case _O_WSDISPLAY_KBD_ADD: 1421 if (d->idx == -1) { 1422 d->idx = wskbd_pickfree(); 1423 if (d->idx == -1) 1424 return (ENXIO); 1425 } 1426 wsmuxdata.type = WSMUX_KBD; 1427 wsmuxdata.idx = d->idx; 1428 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE, 1429 &wsmuxdata, flag, l)); 1430 case _O_WSDISPLAY_KBD_DEL: 1431 wsmuxdata.type = WSMUX_KBD; 1432 wsmuxdata.idx = d->idx; 1433 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE, 1434 &wsmuxdata, flag, l)); 1435 default: 1436 return (EINVAL); 1437 } 1438 #undef d 1439 #endif 1440 1441 case WSMUXIO_ADD_DEVICE: 1442 #define d ((struct wsmux_device *)data) 1443 if (d->idx == -1 && d->type == WSMUX_KBD) 1444 d->idx = wskbd_pickfree(); 1445 #undef d 1446 /* fall into */ 1447 case WSMUXIO_INJECTEVENT: 1448 case WSMUXIO_REMOVE_DEVICE: 1449 case WSMUXIO_LIST_DEVICES: 1450 inp = sc->sc_input; 1451 if (inp == NULL) 1452 return (ENXIO); 1453 return (wsevsrc_ioctl(inp, cmd, data, flag, l)); 1454 #endif /* NWSKBD > 0 */ 1455 1456 } 1457 return (EPASSTHROUGH); 1458 } 1459 1460 int 1461 wsdisplay_stat_inject(device_t dv, u_int type, int value) 1462 { 1463 struct wsdisplay_softc *sc = device_private(dv); 1464 struct wseventvar *evar; 1465 struct wscons_event event; 1466 1467 evar = &sc->evar; 1468 1469 if (evar == NULL) 1470 return (0); 1471 1472 if (evar->q == NULL) 1473 return (1); 1474 1475 event.type = type; 1476 event.value = value; 1477 if (wsevent_inject(evar, &event, 1) != 0) { 1478 log(LOG_WARNING, "wsdisplay: event queue overflow\n"); 1479 return (1); 1480 } 1481 1482 return (0); 1483 } 1484 1485 paddr_t 1486 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1487 { 1488 struct wsdisplay_softc *sc; 1489 struct wsscreen *scr; 1490 1491 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1492 1493 if (ISWSDISPLAYSTAT(dev)) 1494 return (-1); 1495 1496 if (ISWSDISPLAYCTL(dev)) 1497 return (-1); 1498 1499 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1500 return (-1); 1501 1502 if (!(scr->scr_flags & SCR_GRAPHICS)) 1503 return (-1); 1504 1505 /* pass mmap to display */ 1506 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, 1507 scr->scr_dconf->emulcookie, offset, prot)); 1508 } 1509 1510 void 1511 wsdisplaystart(struct tty *tp) 1512 { 1513 struct wsdisplay_softc *sc; 1514 struct wsscreen *scr; 1515 int s, n; 1516 u_char *tbuf; 1517 1518 s = spltty(); 1519 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1520 splx(s); 1521 return; 1522 } 1523 sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1524 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) { 1525 splx(s); 1526 return; 1527 } 1528 1529 if (scr->scr_hold_screen) { 1530 tp->t_state |= TS_TIMEOUT; 1531 splx(s); 1532 return; 1533 } 1534 tp->t_state |= TS_BUSY; 1535 splx(s); 1536 1537 #ifdef DIAGNOSTIC 1538 scr->scr_in_ttyoutput = 1; 1539 #endif 1540 1541 /* 1542 * Drain output from ring buffer. 1543 * The output will normally be in one contiguous chunk, but when the 1544 * ring wraps, it will be in two pieces.. one at the end of the ring, 1545 * the other at the start. For performance, rather than loop here, 1546 * we output one chunk, see if there's another one, and if so, output 1547 * it too. 1548 */ 1549 1550 n = ndqb(&tp->t_outq, 0); 1551 tbuf = tp->t_outq.c_cf; 1552 1553 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1554 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1555 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1556 tbuf, n, 0); 1557 } 1558 ndflush(&tp->t_outq, n); 1559 1560 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1561 tbuf = tp->t_outq.c_cf; 1562 1563 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1564 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1565 (*scr->scr_dconf->wsemul->output) 1566 (scr->scr_dconf->wsemulcookie, tbuf, n, 0); 1567 } 1568 ndflush(&tp->t_outq, n); 1569 } 1570 1571 #ifdef DIAGNOSTIC 1572 scr->scr_in_ttyoutput = 0; 1573 #endif 1574 1575 s = spltty(); 1576 tp->t_state &= ~TS_BUSY; 1577 /* Come back if there's more to do */ 1578 if (ttypull(tp)) { 1579 tp->t_state |= TS_TIMEOUT; 1580 callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1); 1581 } 1582 splx(s); 1583 } 1584 1585 void 1586 wsdisplaystop(struct tty *tp, int flag) 1587 { 1588 int s; 1589 1590 s = spltty(); 1591 if (ISSET(tp->t_state, TS_BUSY)) 1592 if (!ISSET(tp->t_state, TS_TTSTOP)) 1593 SET(tp->t_state, TS_FLUSH); 1594 splx(s); 1595 } 1596 1597 /* Set line parameters. */ 1598 int 1599 wsdisplayparam(struct tty *tp, struct termios *t) 1600 { 1601 1602 tp->t_ispeed = t->c_ispeed; 1603 tp->t_ospeed = t->c_ospeed; 1604 tp->t_cflag = t->c_cflag; 1605 return 0; 1606 } 1607 1608 /* 1609 * Callbacks for the emulation code. 1610 */ 1611 void 1612 wsdisplay_emulbell(void *v) 1613 { 1614 struct wsscreen *scr = v; 1615 1616 if (scr == NULL) /* console, before real attach */ 1617 return; 1618 1619 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1620 return; 1621 1622 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1623 FWRITE, NULL); 1624 } 1625 1626 void 1627 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1628 { 1629 struct wsscreen *scr = v; 1630 struct tty *tp; 1631 int (*ifcn)(int, struct tty *); 1632 1633 if (v == NULL) /* console, before real attach */ 1634 return; 1635 1636 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1637 return; 1638 if (!WSSCREEN_HAS_TTY(scr)) 1639 return; 1640 1641 tp = scr->scr_tty; 1642 1643 /* 1644 * XXX bad hack to work around locking problems in tty.c: 1645 * ttyinput() will try to lock again, causing deadlock. 1646 * We assume that wsdisplay_emulinput() can only be called 1647 * from within wsdisplaystart(), and thus the tty lock 1648 * is already held. Use an entry point which doesn't lock. 1649 */ 1650 KASSERT(scr->scr_in_ttyoutput); 1651 ifcn = tp->t_linesw->l_rint; 1652 if (ifcn == ttyinput) 1653 ifcn = ttyinput_wlock; 1654 1655 while (count-- > 0) 1656 (*ifcn)(*data++, tp); 1657 } 1658 1659 /* 1660 * Calls from the keyboard interface. 1661 */ 1662 void 1663 wsdisplay_kbdinput(device_t dv, keysym_t ks) 1664 { 1665 struct wsdisplay_softc *sc = device_private(dv); 1666 struct wsscreen *scr; 1667 const char *dp; 1668 int count; 1669 struct tty *tp; 1670 1671 KASSERT(sc != NULL); 1672 1673 scr = sc->sc_focus; 1674 1675 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1676 return; 1677 1678 tp = scr->scr_tty; 1679 1680 if (KS_GROUP(ks) == KS_GROUP_Plain && KS_VALUE(ks) <= 0x7f) 1681 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1682 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1683 count = (*scr->scr_dconf->wsemul->translate) 1684 (scr->scr_dconf->wsemulcookie, ks, &dp); 1685 while (count-- > 0) 1686 (*tp->t_linesw->l_rint)((unsigned char)(*dp++), tp); 1687 } 1688 } 1689 1690 #if defined(WSDISPLAY_COMPAT_RAWKBD) 1691 int 1692 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1693 { 1694 #if NWSKBD > 0 1695 int s, raw, data, error; 1696 struct wsevsrc *inp; 1697 1698 s = spltty(); 1699 1700 raw = (scr ? scr->scr_rawkbd : 0); 1701 1702 if (scr != sc->sc_focus || 1703 sc->sc_rawkbd == raw) { 1704 splx(s); 1705 return (0); 1706 } 1707 1708 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1709 inp = sc->sc_input; 1710 if (inp == NULL) { 1711 splx(s); 1712 return (ENXIO); 1713 } 1714 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0); 1715 if (!error) 1716 sc->sc_rawkbd = raw; 1717 splx(s); 1718 return (error); 1719 #else 1720 return (0); 1721 #endif 1722 } 1723 #endif 1724 1725 static void 1726 wsdisplay_switch3_cb(void *arg, int error, int waitok) 1727 { 1728 device_t dv = arg; 1729 1730 wsdisplay_switch3(dv, error, waitok); 1731 } 1732 1733 static int 1734 wsdisplay_switch3(device_t dv, int error, int waitok) 1735 { 1736 struct wsdisplay_softc *sc = device_private(dv); 1737 int no; 1738 struct wsscreen *scr; 1739 1740 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1741 aprint_error_dev(dv, "wsdisplay_switch3: not switching\n"); 1742 return (EINVAL); 1743 } 1744 1745 no = sc->sc_screenwanted; 1746 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1747 panic("wsdisplay_switch3: invalid screen %d", no); 1748 scr = sc->sc_scr[no]; 1749 if (!scr) { 1750 aprint_error_dev(dv, 1751 "wsdisplay_switch3: screen %d disappeared\n", no); 1752 error = ENXIO; 1753 } 1754 1755 if (error) { 1756 /* try to recover, avoid recursion */ 1757 1758 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1759 aprint_error_dev(dv, "wsdisplay_switch3: giving up\n"); 1760 sc->sc_focus = 0; 1761 #ifdef WSDISPLAY_COMPAT_RAWKBD 1762 wsdisplay_update_rawkbd(sc, 0); 1763 #endif 1764 sc->sc_flags &= ~SC_SWITCHPENDING; 1765 return (error); 1766 } 1767 1768 sc->sc_screenwanted = sc->sc_oldscreen; 1769 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1770 return (wsdisplay_switch1(dv, 0, waitok)); 1771 } 1772 1773 if (scr->scr_syncops && !error) 1774 sc->sc_flags |= SC_XATTACHED; 1775 1776 sc->sc_flags &= ~SC_SWITCHPENDING; 1777 1778 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1779 wakeup(scr); 1780 return (error); 1781 } 1782 1783 static void 1784 wsdisplay_switch2_cb(void *arg, int error, int waitok) 1785 { 1786 device_t dv = arg; 1787 1788 wsdisplay_switch2(dv, error, waitok); 1789 } 1790 1791 static int 1792 wsdisplay_switch2(device_t dv, int error, int waitok) 1793 { 1794 struct wsdisplay_softc *sc = device_private(dv); 1795 int no; 1796 struct wsscreen *scr; 1797 1798 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1799 aprint_error_dev(dv, "wsdisplay_switch2: not switching\n"); 1800 return (EINVAL); 1801 } 1802 1803 no = sc->sc_screenwanted; 1804 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1805 panic("wsdisplay_switch2: invalid screen %d", no); 1806 scr = sc->sc_scr[no]; 1807 if (!scr) { 1808 aprint_error_dev(dv, 1809 "wsdisplay_switch2: screen %d disappeared\n", no); 1810 error = ENXIO; 1811 } 1812 1813 if (error) { 1814 /* try to recover, avoid recursion */ 1815 1816 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1817 aprint_error_dev(dv, "wsdisplay_switch2: giving up\n"); 1818 sc->sc_focus = 0; 1819 sc->sc_flags &= ~SC_SWITCHPENDING; 1820 return (error); 1821 } 1822 1823 sc->sc_screenwanted = sc->sc_oldscreen; 1824 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1825 return (wsdisplay_switch1(dv, 0, waitok)); 1826 } 1827 1828 sc->sc_focusidx = no; 1829 sc->sc_focus = scr; 1830 1831 #ifdef WSDISPLAY_COMPAT_RAWKBD 1832 (void) wsdisplay_update_rawkbd(sc, scr); 1833 #endif 1834 /* keyboard map??? */ 1835 1836 if (scr->scr_syncops && 1837 !(sc->sc_isconsole && wsdisplay_cons_pollmode)) { 1838 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1839 wsdisplay_switch3_cb, dv); 1840 if (error == EAGAIN) { 1841 /* switch will be done asynchronously */ 1842 return (0); 1843 } 1844 } 1845 1846 return (wsdisplay_switch3(dv, error, waitok)); 1847 } 1848 1849 static void 1850 wsdisplay_switch1_cb(void *arg, int error, int waitok) 1851 { 1852 device_t dv = arg; 1853 1854 wsdisplay_switch1(dv, error, waitok); 1855 } 1856 1857 static int 1858 wsdisplay_switch1(device_t dv, int error, int waitok) 1859 { 1860 struct wsdisplay_softc *sc = device_private(dv); 1861 int no; 1862 struct wsscreen *scr; 1863 1864 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1865 aprint_error_dev(dv, "wsdisplay_switch1: not switching\n"); 1866 return (EINVAL); 1867 } 1868 1869 no = sc->sc_screenwanted; 1870 if (no == WSDISPLAY_NULLSCREEN) { 1871 sc->sc_flags &= ~SC_SWITCHPENDING; 1872 if (!error) { 1873 sc->sc_flags &= ~SC_XATTACHED; 1874 sc->sc_focus = 0; 1875 } 1876 wakeup(sc); 1877 return (error); 1878 } 1879 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1880 panic("wsdisplay_switch1: invalid screen %d", no); 1881 scr = sc->sc_scr[no]; 1882 if (!scr) { 1883 aprint_error_dev(dv, "wsdisplay_switch1: screen %d disappeared\n", no); 1884 error = ENXIO; 1885 } 1886 1887 if (error) { 1888 sc->sc_flags &= ~SC_SWITCHPENDING; 1889 return (error); 1890 } 1891 1892 sc->sc_flags &= ~SC_XATTACHED; 1893 1894 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1895 scr->scr_dconf->emulcookie, 1896 waitok, 1897 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsdisplay_switch2_cb, dv); 1898 if (error == EAGAIN) { 1899 /* switch will be done asynchronously */ 1900 return (0); 1901 } 1902 1903 return (wsdisplay_switch2(dv, error, waitok)); 1904 } 1905 1906 int 1907 wsdisplay_switch(device_t dv, int no, int waitok) 1908 { 1909 struct wsdisplay_softc *sc = device_private(dv); 1910 int s, res = 0; 1911 struct wsscreen *scr; 1912 1913 if (no != WSDISPLAY_NULLSCREEN) { 1914 if ((no < 0 || no >= WSDISPLAY_MAXSCREEN)) 1915 return (EINVAL); 1916 if (sc->sc_scr[no] == NULL) 1917 return (ENXIO); 1918 } 1919 1920 wsdisplay_stat_inject(dv, WSCONS_EVENT_SCREEN_SWITCH, no); 1921 1922 s = spltty(); 1923 1924 if ((sc->sc_focus && no == sc->sc_focusidx) || 1925 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1926 splx(s); 1927 return (0); 1928 } 1929 1930 if (sc->sc_flags & SC_SWITCHPENDING) { 1931 splx(s); 1932 return (EBUSY); 1933 } 1934 1935 sc->sc_flags |= SC_SWITCHPENDING; 1936 sc->sc_screenwanted = no; 1937 1938 splx(s); 1939 1940 scr = sc->sc_focus; 1941 if (!scr) { 1942 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1943 return (wsdisplay_switch1(dv, 0, waitok)); 1944 } else 1945 sc->sc_oldscreen = sc->sc_focusidx; 1946 1947 if (scr->scr_syncops) { 1948 if (!(sc->sc_flags & SC_XATTACHED) || 1949 (sc->sc_isconsole && wsdisplay_cons_pollmode)) { 1950 /* nothing to do here */ 1951 return (wsdisplay_switch1(dv, 0, waitok)); 1952 } 1953 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1954 wsdisplay_switch1_cb, dv); 1955 if (res == EAGAIN) { 1956 /* switch will be done asynchronously */ 1957 return (0); 1958 } 1959 } else if (scr->scr_flags & SCR_GRAPHICS) { 1960 /* no way to save state */ 1961 res = EBUSY; 1962 } 1963 1964 return (wsdisplay_switch1(dv, res, waitok)); 1965 } 1966 1967 void 1968 wsdisplay_reset(device_t dv, enum wsdisplay_resetops op) 1969 { 1970 struct wsdisplay_softc *sc = device_private(dv); 1971 struct wsscreen *scr; 1972 1973 KASSERT(sc != NULL); 1974 scr = sc->sc_focus; 1975 1976 if (!scr) 1977 return; 1978 1979 switch (op) { 1980 case WSDISPLAY_RESETEMUL: 1981 if (!WSSCREEN_HAS_EMULATOR(scr)) 1982 break; 1983 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1984 WSEMUL_RESET); 1985 break; 1986 case WSDISPLAY_RESETCLOSE: 1987 wsdisplay_closescreen(sc, scr); 1988 break; 1989 } 1990 } 1991 1992 /* 1993 * Interface for (external) VT switch / process synchronization code 1994 */ 1995 int 1996 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1997 void *cookie) 1998 { 1999 if (scr->scr_syncops) { 2000 /* 2001 * The screen is already claimed. 2002 * Check if the owner is still alive. 2003 */ 2004 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 2005 return (EBUSY); 2006 } 2007 scr->scr_syncops = ops; 2008 scr->scr_synccookie = cookie; 2009 if (scr == scr->sc->sc_focus) 2010 scr->sc->sc_flags |= SC_XATTACHED; 2011 return (0); 2012 } 2013 2014 int 2015 wsscreen_detach_sync(struct wsscreen *scr) 2016 { 2017 if (!scr->scr_syncops) 2018 return (EINVAL); 2019 scr->scr_syncops = 0; 2020 if (scr == scr->sc->sc_focus) 2021 scr->sc->sc_flags &= ~SC_XATTACHED; 2022 return (0); 2023 } 2024 2025 int 2026 wsscreen_lookup_sync(struct wsscreen *scr, 2027 const struct wscons_syncops *ops, /* used as ID */ 2028 void **cookiep) 2029 { 2030 if (!scr->scr_syncops || ops != scr->scr_syncops) 2031 return (EINVAL); 2032 *cookiep = scr->scr_synccookie; 2033 return (0); 2034 } 2035 2036 /* 2037 * Interface to virtual screen stuff 2038 */ 2039 int 2040 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 2041 { 2042 return (WSDISPLAY_MAXSCREEN - 1); 2043 } 2044 2045 int 2046 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 2047 { 2048 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 2049 return (EINVAL); 2050 if (!sc->sc_scr[idx]) 2051 return (ENXIO); 2052 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 2053 } 2054 2055 int 2056 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 2057 { 2058 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 2059 } 2060 2061 int 2062 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 2063 { 2064 struct wsscreen *scr; 2065 int s, res = 0; 2066 2067 if (no == WSDISPLAY_NULLSCREEN) { 2068 s = spltty(); 2069 while (sc->sc_focus && res == 0) { 2070 res = tsleep(sc, PCATCH, "wswait", 0); 2071 } 2072 splx(s); 2073 return (res); 2074 } 2075 2076 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 2077 return (ENXIO); 2078 scr = sc->sc_scr[no]; 2079 if (!scr) 2080 return (ENXIO); 2081 2082 s = spltty(); 2083 if (scr != sc->sc_focus) { 2084 scr->scr_flags |= SCR_WAITACTIVE; 2085 res = tsleep(scr, PCATCH, "wswait", 0); 2086 if (scr != sc->sc_scr[no]) 2087 res = ENXIO; /* disappeared in the meantime */ 2088 else 2089 scr->scr_flags &= ~SCR_WAITACTIVE; 2090 } 2091 splx(s); 2092 return (res); 2093 } 2094 2095 void 2096 wsdisplay_kbdholdscreen(device_t dv, int hold) 2097 { 2098 struct wsdisplay_softc *sc = device_private(dv); 2099 struct wsscreen *scr; 2100 2101 scr = sc->sc_focus; 2102 2103 if (!scr) 2104 return; 2105 2106 if (hold) 2107 scr->scr_hold_screen = 1; 2108 else { 2109 scr->scr_hold_screen = 0; 2110 callout_schedule(&scr->scr_tty->t_rstrt_ch, 0); 2111 } 2112 } 2113 2114 #if NWSKBD > 0 2115 void 2116 wsdisplay_set_console_kbd(struct wsevsrc *src) 2117 { 2118 if (wsdisplay_console_device == NULL) { 2119 src->me_dispdv = NULL; 2120 return; 2121 } 2122 #if NWSMUX > 0 2123 if (wsmux_attach_sc((struct wsmux_softc *) 2124 wsdisplay_console_device->sc_input, src)) { 2125 src->me_dispdv = NULL; 2126 return; 2127 } 2128 #else 2129 wsdisplay_console_device->sc_input = src; 2130 #endif 2131 src->me_dispdv = wsdisplay_console_device->sc_dev; 2132 } 2133 #endif /* NWSKBD > 0 */ 2134 2135 /* 2136 * Console interface. 2137 */ 2138 void 2139 wsdisplay_cnputc(dev_t dev, int i) 2140 { 2141 struct wsscreen_internal *dc; 2142 u_char c = i; 2143 2144 if (!wsdisplay_console_initted) 2145 return; 2146 2147 if ((wsdisplay_console_device != NULL) && 2148 (wsdisplay_console_device->sc_scr[0] != NULL) && 2149 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 2150 return; 2151 2152 dc = &wsdisplay_console_conf; 2153 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 2154 } 2155 2156 static int 2157 wsdisplay_getc_dummy(dev_t dev) 2158 { 2159 /* panic? */ 2160 return (0); 2161 } 2162 2163 static void 2164 wsdisplay_pollc(dev_t dev, int on) 2165 { 2166 2167 wsdisplay_cons_pollmode = on; 2168 2169 /* notify to fb drivers */ 2170 if (wsdisplay_console_device != NULL && 2171 wsdisplay_console_device->sc_accessops->pollc != NULL) 2172 (*wsdisplay_console_device->sc_accessops->pollc) 2173 (wsdisplay_console_device->sc_accesscookie, on); 2174 2175 /* notify to kbd drivers */ 2176 if (wsdisplay_cons_kbd_pollc) 2177 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 2178 } 2179 2180 void 2181 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 2182 void (*bell)(dev_t, u_int, u_int, u_int)) 2183 { 2184 wsdisplay_cons.cn_getc = get; 2185 wsdisplay_cons.cn_bell = bell; 2186 wsdisplay_cons_kbd_pollc = poll; 2187 } 2188 2189 void 2190 wsdisplay_unset_cons_kbd(void) 2191 { 2192 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 2193 wsdisplay_cons.cn_bell = NULL; 2194 wsdisplay_cons_kbd_pollc = 0; 2195 } 2196