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