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