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