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