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