1 /* $NetBSD: wsdisplay.c,v 1.60 2001/11/13 06:17:46 lukem 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.60 2001/11/13 06:17:46 lukem Exp $"); 35 36 #include "opt_wsdisplay_compat.h" 37 #include "opt_compat_netbsd.h" 38 #include "wskbd.h" 39 #include "wsmux.h" 40 #include "wsdisplay.h" 41 42 #include <sys/param.h> 43 #include <sys/conf.h> 44 #include <sys/device.h> 45 #include <sys/ioctl.h> 46 #include <sys/kernel.h> 47 #include <sys/proc.h> 48 #include <sys/malloc.h> 49 #include <sys/syslog.h> 50 #include <sys/systm.h> 51 #include <sys/tty.h> 52 #include <sys/signalvar.h> 53 #include <sys/errno.h> 54 #include <sys/fcntl.h> 55 #include <sys/vnode.h> 56 57 #include <dev/wscons/wseventvar.h> 58 #include <dev/wscons/wsmuxvar.h> 59 #include <dev/wscons/wsconsio.h> 60 #include <dev/wscons/wsdisplayvar.h> 61 #include <dev/wscons/wsksymvar.h> 62 #include <dev/wscons/wsksymdef.h> 63 #include <dev/wscons/wsemulvar.h> 64 #include <dev/wscons/wscons_callbacks.h> 65 #include <dev/cons.h> 66 67 struct wsscreen_internal { 68 const struct wsdisplay_emulops *emulops; 69 void *emulcookie; 70 71 const struct wsscreen_descr *scrdata; 72 73 const struct wsemul_ops *wsemul; 74 void *wsemulcookie; 75 }; 76 77 struct wsscreen { 78 struct wsscreen_internal *scr_dconf; 79 80 struct tty *scr_tty; 81 int scr_hold_screen; /* hold tty output */ 82 83 int scr_flags; 84 #define SCR_OPEN 1 /* is it open? */ 85 #define SCR_WAITACTIVE 2 /* someone waiting on activation */ 86 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */ 87 const struct wscons_syncops *scr_syncops; 88 void *scr_synccookie; 89 90 #ifdef WSDISPLAY_COMPAT_RAWKBD 91 int scr_rawkbd; 92 #endif 93 94 struct wsdisplay_softc *sc; 95 }; 96 97 struct wsscreen *wsscreen_attach(struct wsdisplay_softc *, int, 98 const char *, 99 const struct wsscreen_descr *, void *, 100 int, int, long); 101 void wsscreen_detach(struct wsscreen *); 102 int wsdisplay_addscreen(struct wsdisplay_softc *, int, const char *, const char *); 103 static void wsdisplay_shutdownhook(void *); 104 static void wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int); 105 static void wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *); 106 int wsdisplay_delscreen(struct wsdisplay_softc *, int, int); 107 108 #define WSDISPLAY_MAXSCREEN 8 109 110 struct wsdisplay_softc { 111 struct device sc_dv; 112 113 const struct wsdisplay_accessops *sc_accessops; 114 void *sc_accesscookie; 115 116 const struct wsscreen_list *sc_scrdata; 117 118 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN]; 119 int sc_focusidx; /* available only if sc_focus isn't null */ 120 struct wsscreen *sc_focus; 121 122 int sc_isconsole; 123 124 int sc_flags; 125 #define SC_SWITCHPENDING 1 126 int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */ 127 128 #if NWSKBD > 0 129 struct wsevsrc *sc_input; 130 #ifdef WSDISPLAY_COMPAT_RAWKBD 131 int sc_rawkbd; 132 #endif 133 #endif /* NWSKBD > 0 */ 134 }; 135 136 extern struct cfdriver wsdisplay_cd; 137 138 /* Autoconfiguration definitions. */ 139 static int wsdisplay_emul_match(struct device *, struct cfdata *, void *); 140 static void wsdisplay_emul_attach(struct device *, struct device *, void *); 141 static int wsdisplay_noemul_match(struct device *, struct cfdata *, void *); 142 static void wsdisplay_noemul_attach(struct device *, struct device *, void *); 143 144 struct cfattach wsdisplay_emul_ca = { 145 sizeof (struct wsdisplay_softc), 146 wsdisplay_emul_match, 147 wsdisplay_emul_attach, 148 }; 149 150 struct cfattach wsdisplay_noemul_ca = { 151 sizeof (struct wsdisplay_softc), 152 wsdisplay_noemul_match, 153 wsdisplay_noemul_attach, 154 }; 155 156 /* Exported tty- and cdevsw-related functions. */ 157 cdev_decl(wsdisplay); 158 159 static void wsdisplaystart(struct tty *); 160 static int wsdisplayparam(struct tty *, struct termios *); 161 162 163 /* Internal macros, functions, and variables. */ 164 #define SET(t, f) (t) |= (f) 165 #define CLR(t, f) (t) &= ~(f) 166 #define ISSET(t, f) ((t) & (f)) 167 168 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8) 169 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff) 170 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255) 171 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen)) 172 173 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL) 174 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL) 175 176 static void wsdisplay_common_attach(struct wsdisplay_softc *sc, 177 int console, int kbdmux, const struct wsscreen_list *, 178 const struct wsdisplay_accessops *accessops, 179 void *accesscookie); 180 181 #ifdef WSDISPLAY_COMPAT_RAWKBD 182 int wsdisplay_update_rawkbd(struct wsdisplay_softc *, 183 struct wsscreen *); 184 #endif 185 186 static int wsdisplay_console_initted; 187 static struct wsdisplay_softc *wsdisplay_console_device; 188 static struct wsscreen_internal wsdisplay_console_conf; 189 190 static int wsdisplay_getc_dummy(dev_t); 191 static void wsdisplay_pollc(dev_t, int); 192 193 static int wsdisplay_cons_pollmode; 194 static void (*wsdisplay_cons_kbd_pollc)(dev_t, int); 195 196 static struct consdev wsdisplay_cons = { 197 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc, 198 wsdisplay_pollc, NULL, NODEV, CN_NORMAL 199 }; 200 201 #ifndef WSDISPLAY_DEFAULTSCREENS 202 # define WSDISPLAY_DEFAULTSCREENS 0 203 #endif 204 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS; 205 206 int wsdisplay_switch1(void *, int, int); 207 int wsdisplay_switch2(void *, int, int); 208 int wsdisplay_switch3(void *, int, int); 209 210 int wsdisplay_clearonclose; 211 212 struct wsscreen * 213 wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul, 214 const struct wsscreen_descr *type, void *cookie, int ccol, 215 int crow, long defattr) 216 { 217 struct wsscreen_internal *dconf; 218 struct wsscreen *scr; 219 220 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK); 221 if (!scr) 222 return (NULL); 223 224 if (console) { 225 dconf = &wsdisplay_console_conf; 226 /* 227 * If there's an emulation, tell it about the callback argument. 228 * The other stuff is already there. 229 */ 230 if (dconf->wsemul != NULL) 231 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0); 232 } else { /* not console */ 233 dconf = malloc(sizeof(struct wsscreen_internal), 234 M_DEVBUF, M_NOWAIT); 235 dconf->emulops = type->textops; 236 dconf->emulcookie = cookie; 237 if (dconf->emulops) { 238 dconf->wsemul = wsemul_pick(emul); 239 if (dconf->wsemul == NULL) { 240 free(dconf, M_DEVBUF); 241 free(scr, M_DEVBUF); 242 return (NULL); 243 } 244 dconf->wsemulcookie = 245 (*dconf->wsemul->attach)(0, type, cookie, 246 ccol, crow, scr, defattr); 247 } else 248 dconf->wsemul = NULL; 249 dconf->scrdata = type; 250 } 251 252 scr->scr_dconf = dconf; 253 254 scr->scr_tty = ttymalloc(); 255 tty_attach(scr->scr_tty); 256 scr->scr_hold_screen = 0; 257 if (WSSCREEN_HAS_EMULATOR(scr)) 258 scr->scr_flags = 0; 259 else 260 scr->scr_flags = SCR_GRAPHICS; 261 262 scr->scr_syncops = 0; 263 scr->sc = sc; 264 #ifdef WSDISPLAY_COMPAT_RAWKBD 265 scr->scr_rawkbd = 0; 266 #endif 267 return (scr); 268 } 269 270 void 271 wsscreen_detach(struct wsscreen *scr) 272 { 273 int ccol, crow; /* XXX */ 274 275 if (WSSCREEN_HAS_TTY(scr)) { 276 tty_detach(scr->scr_tty); 277 ttyfree(scr->scr_tty); 278 } 279 if (WSSCREEN_HAS_EMULATOR(scr)) 280 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie, 281 &ccol, &crow); 282 free(scr->scr_dconf, M_DEVBUF); 283 free(scr, M_DEVBUF); 284 } 285 286 const struct wsscreen_descr * 287 wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name) 288 { 289 int i; 290 const struct wsscreen_descr *scr; 291 292 KASSERT(scrdata->nscreens > 0); 293 294 if (name == NULL) 295 return (scrdata->screens[0]); 296 297 for (i = 0; i < scrdata->nscreens; i++) { 298 scr = scrdata->screens[i]; 299 if (!strcmp(name, scr->name)) 300 return (scr); 301 } 302 303 return (0); 304 } 305 306 /* 307 * print info about attached screen 308 */ 309 static void 310 wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count) 311 { 312 printf("%s: screen %d", sc->sc_dv.dv_xname, idx); 313 if (count > 1) 314 printf("-%d", idx + (count-1)); 315 printf(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name); 316 if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) { 317 printf(", %s emulation", 318 sc->sc_scr[idx]->scr_dconf->wsemul->name); 319 } 320 printf(")\n"); 321 } 322 323 int 324 wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx, 325 const char *screentype, const char *emul) 326 { 327 const struct wsscreen_descr *scrdesc; 328 int error; 329 void *cookie; 330 int ccol, crow; 331 long defattr; 332 struct wsscreen *scr; 333 int s; 334 335 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 336 return (EINVAL); 337 if (sc->sc_scr[idx] != NULL) 338 return (EBUSY); 339 340 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype); 341 if (!scrdesc) 342 return (ENXIO); 343 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie, 344 scrdesc, &cookie, &ccol, &crow, &defattr); 345 if (error) 346 return (error); 347 348 scr = wsscreen_attach(sc, 0, emul, scrdesc, 349 cookie, ccol, crow, defattr); 350 if (scr == NULL) { 351 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 352 cookie); 353 return (ENXIO); 354 } 355 356 sc->sc_scr[idx] = scr; 357 358 /* if no screen has focus yet, activate the first we get */ 359 s = spltty(); 360 if (!sc->sc_focus) { 361 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 362 scr->scr_dconf->emulcookie, 363 0, 0, 0); 364 sc->sc_focusidx = idx; 365 sc->sc_focus = scr; 366 } 367 splx(s); 368 return (0); 369 } 370 371 static void 372 wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr) 373 { 374 int maj, mn, idx; 375 376 /* hangup */ 377 if (WSSCREEN_HAS_TTY(scr)) { 378 struct tty *tp = scr->scr_tty; 379 (*tp->t_linesw->l_modem)(tp, 0); 380 } 381 382 /* locate the major number */ 383 for (maj = 0; maj < nchrdev; maj++) 384 if (cdevsw[maj].d_open == wsdisplayopen) 385 break; 386 /* locate the screen index */ 387 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++) 388 if (scr == sc->sc_scr[idx]) 389 break; 390 #ifdef DIAGNOSTIC 391 if (idx == WSDISPLAY_MAXSCREEN) 392 panic("wsdisplay_forceclose: bad screen"); 393 #endif 394 395 /* nuke the vnodes */ 396 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx); 397 vdevgone(maj, mn, mn, VCHR); 398 } 399 400 int 401 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags) 402 { 403 struct wsscreen *scr; 404 int s; 405 void *cookie; 406 407 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 408 return (EINVAL); 409 scr = sc->sc_scr[idx]; 410 if (!scr) 411 return (ENXIO); 412 413 if (scr->scr_dconf == &wsdisplay_console_conf || 414 scr->scr_syncops || 415 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE))) 416 return(EBUSY); 417 418 wsdisplay_closescreen(sc, scr); 419 420 /* 421 * delete pointers, so neither device entries 422 * nor keyboard input can reference it anymore 423 */ 424 s = spltty(); 425 if (sc->sc_focus == scr) { 426 sc->sc_focus = 0; 427 #ifdef WSDISPLAY_COMPAT_RAWKBD 428 wsdisplay_update_rawkbd(sc, 0); 429 #endif 430 } 431 sc->sc_scr[idx] = 0; 432 splx(s); 433 434 /* 435 * Wake up processes waiting for the screen to 436 * be activated. Sleepers must check whether 437 * the screen still exists. 438 */ 439 if (scr->scr_flags & SCR_WAITACTIVE) 440 wakeup(scr); 441 442 /* save a reference to the graphics screen */ 443 cookie = scr->scr_dconf->emulcookie; 444 445 wsscreen_detach(scr); 446 447 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 448 cookie); 449 450 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx); 451 return (0); 452 } 453 454 /* 455 * Autoconfiguration functions. 456 */ 457 int 458 wsdisplay_emul_match(struct device *parent, struct cfdata *match, void *aux) 459 { 460 struct wsemuldisplaydev_attach_args *ap = aux; 461 462 if (match->wsemuldisplaydevcf_console != 463 WSEMULDISPLAYDEVCF_CONSOLE_UNK) { 464 /* 465 * If console-ness of device specified, either match 466 * exactly (at high priority), or fail. 467 */ 468 if (match->wsemuldisplaydevcf_console != 0 && 469 ap->console != 0) 470 return (10); 471 else 472 return (0); 473 } 474 475 /* If console-ness unspecified, it wins. */ 476 return (1); 477 } 478 479 void 480 wsdisplay_emul_attach(struct device *parent, struct device *self, void *aux) 481 { 482 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 483 struct wsemuldisplaydev_attach_args *ap = aux; 484 485 wsdisplay_common_attach(sc, ap->console, 486 sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, ap->scrdata, 487 ap->accessops, ap->accesscookie); 488 489 if (ap->console) { 490 int maj; 491 492 /* locate the major number */ 493 for (maj = 0; maj < nchrdev; maj++) 494 if (cdevsw[maj].d_open == wsdisplayopen) 495 break; 496 497 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0)); 498 } 499 } 500 501 /* Print function (for parent devices). */ 502 int 503 wsemuldisplaydevprint(void *aux, const char *pnp) 504 { 505 #if 0 /* -Wunused */ 506 struct wsemuldisplaydev_attach_args *ap = aux; 507 #endif 508 509 if (pnp) 510 printf("wsdisplay at %s", pnp); 511 #if 0 /* don't bother; it's ugly */ 512 printf(" console %d", ap->console); 513 #endif 514 515 return (UNCONF); 516 } 517 518 int 519 wsdisplay_noemul_match(struct device *parent, struct cfdata *match, void *aux) 520 { 521 #if 0 /* -Wunused */ 522 struct wsdisplaydev_attach_args *ap = aux; 523 #endif 524 525 /* Always match. */ 526 return (1); 527 } 528 529 void 530 wsdisplay_noemul_attach(struct device *parent, struct device *self, void *aux) 531 { 532 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 533 struct wsdisplaydev_attach_args *ap = aux; 534 535 wsdisplay_common_attach(sc, 0, 536 sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, NULL, 537 ap->accessops, ap->accesscookie); 538 } 539 540 /* Print function (for parent devices). */ 541 int 542 wsdisplaydevprint(void *aux, const char *pnp) 543 { 544 #if 0 /* -Wunused */ 545 struct wsdisplaydev_attach_args *ap = aux; 546 #endif 547 548 if (pnp) 549 printf("wsdisplay at %s", pnp); 550 551 return (UNCONF); 552 } 553 554 static void 555 wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux, 556 const struct wsscreen_list *scrdata, 557 const struct wsdisplay_accessops *accessops, 558 void *accesscookie) 559 { 560 static int hookset; 561 int i, start=0; 562 #if NWSKBD > 0 563 struct wsevsrc *kme; 564 #if NWSMUX > 0 565 struct wsevsrc *inp; 566 567 if (kbdmux >= 0) 568 inp = &wsmux_getmux(kbdmux)->sc_base; 569 else 570 inp = &wsmux_create("dmux", sc->sc_dv.dv_unit)->sc_base; 571 /* XXX panic()ing isn't nice, but attach cannot fail */ 572 if (inp == NULL) 573 panic("wsdisplay_common_attach: no memory\n"); 574 sc->sc_input = inp; 575 inp->me_dispdv = &sc->sc_dv; 576 printf(" kbdmux %d", kbdmux); 577 #else 578 if (kbdmux >= 0) 579 printf(" (kbdmux ignored)"); 580 #endif 581 #endif 582 583 sc->sc_isconsole = console; 584 585 if (console) { 586 KASSERT(wsdisplay_console_initted); 587 KASSERT(wsdisplay_console_device == NULL); 588 589 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0); 590 wsdisplay_console_device = sc; 591 592 printf(": console (%s, %s emulation)", 593 wsdisplay_console_conf.scrdata->name, 594 wsdisplay_console_conf.wsemul->name); 595 596 #if NWSKBD > 0 597 kme = wskbd_set_console_display(&sc->sc_dv, sc->sc_input); 598 if (kme != NULL) 599 printf(", using %s", kme->me_dv.dv_xname); 600 #if NWSMUX == 0 601 sc->sc_input = kme; 602 #endif 603 #endif 604 605 sc->sc_focusidx = 0; 606 sc->sc_focus = sc->sc_scr[0]; 607 start = 1; 608 } 609 printf("\n"); 610 611 sc->sc_accessops = accessops; 612 sc->sc_accesscookie = accesscookie; 613 sc->sc_scrdata = scrdata; 614 615 /* 616 * Set up a number of virtual screens if wanted. The 617 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 618 * is for special cases like installation kernels. 619 */ 620 for (i = start; i < wsdisplay_defaultscreens; i++) { 621 if (wsdisplay_addscreen(sc, i, 0, 0)) 622 break; 623 } 624 625 if (i > start) 626 wsdisplay_addscreen_print(sc, start, i-start); 627 628 if (hookset == 0) 629 shutdownhook_establish(wsdisplay_shutdownhook, NULL); 630 hookset = 1; 631 } 632 633 void 634 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie, 635 int ccol, int crow, long defattr) 636 { 637 const struct wsemul_ops *wsemul; 638 639 KASSERT(!wsdisplay_console_initted); 640 KASSERT(type->nrows > 0); 641 KASSERT(type->ncols > 0); 642 KASSERT(crow < type->nrows); 643 KASSERT(ccol < type->ncols); 644 645 wsdisplay_console_conf.emulops = type->textops; 646 wsdisplay_console_conf.emulcookie = cookie; 647 wsdisplay_console_conf.scrdata = type; 648 649 wsemul = wsemul_pick(0); /* default */ 650 wsdisplay_console_conf.wsemul = wsemul; 651 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 652 ccol, crow, 653 defattr); 654 655 cn_tab = &wsdisplay_cons; 656 wsdisplay_console_initted = 1; 657 } 658 659 /* 660 * Tty and cdevsw functions. 661 */ 662 int 663 wsdisplayopen(dev_t dev, int flag, int mode, struct proc *p) 664 { 665 struct wsdisplay_softc *sc; 666 struct tty *tp; 667 int newopen, error; 668 struct wsscreen *scr; 669 670 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 671 if (sc == NULL) /* make sure it was attached */ 672 return (ENXIO); 673 674 if (ISWSDISPLAYCTL(dev)) 675 return (0); 676 677 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 678 return (ENXIO); 679 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 680 if (!scr) 681 return (ENXIO); 682 683 if (WSSCREEN_HAS_TTY(scr)) { 684 tp = scr->scr_tty; 685 tp->t_oproc = wsdisplaystart; 686 tp->t_param = wsdisplayparam; 687 tp->t_dev = dev; 688 newopen = (tp->t_state & TS_ISOPEN) == 0; 689 if (newopen) { 690 ttychars(tp); 691 tp->t_iflag = TTYDEF_IFLAG; 692 tp->t_oflag = TTYDEF_OFLAG; 693 tp->t_cflag = TTYDEF_CFLAG; 694 tp->t_lflag = TTYDEF_LFLAG; 695 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 696 wsdisplayparam(tp, &tp->t_termios); 697 ttsetwater(tp); 698 } else if ((tp->t_state & TS_XCLUDE) != 0 && 699 p->p_ucred->cr_uid != 0) 700 return EBUSY; 701 tp->t_state |= TS_CARR_ON; 702 703 error = ((*tp->t_linesw->l_open)(dev, tp)); 704 if (error) 705 return (error); 706 707 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 708 /* set window sizes as appropriate, and reset 709 the emulation */ 710 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 711 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 712 713 /* wsdisplay_set_emulation() */ 714 } 715 } 716 717 scr->scr_flags |= SCR_OPEN; 718 return (0); 719 } 720 721 int 722 wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p) 723 { 724 struct wsdisplay_softc *sc; 725 struct tty *tp; 726 struct wsscreen *scr; 727 728 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 729 730 if (ISWSDISPLAYCTL(dev)) 731 return (0); 732 733 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 734 735 if (WSSCREEN_HAS_TTY(scr)) { 736 if (scr->scr_hold_screen) { 737 int s; 738 739 /* XXX RESET KEYBOARD LEDS, etc. */ 740 s = spltty(); /* avoid conflict with keyboard */ 741 wsdisplay_kbdholdscreen((struct device *)sc, 0); 742 splx(s); 743 } 744 tp = scr->scr_tty; 745 (*tp->t_linesw->l_close)(tp, flag); 746 ttyclose(tp); 747 } 748 749 if (scr->scr_syncops) 750 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 751 752 if (WSSCREEN_HAS_EMULATOR(scr)) { 753 scr->scr_flags &= ~SCR_GRAPHICS; 754 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 755 WSEMUL_RESET); 756 if (wsdisplay_clearonclose) 757 (*scr->scr_dconf->wsemul->reset) 758 (scr->scr_dconf->wsemulcookie, 759 WSEMUL_CLEARSCREEN); 760 } 761 762 #ifdef WSDISPLAY_COMPAT_RAWKBD 763 if (scr->scr_rawkbd) { 764 int kbmode = WSKBD_TRANSLATED; 765 (void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 766 (caddr_t)&kbmode, 0, p); 767 } 768 #endif 769 770 scr->scr_flags &= ~SCR_OPEN; 771 772 return (0); 773 } 774 775 int 776 wsdisplayread(dev_t dev, struct uio *uio, int flag) 777 { 778 struct wsdisplay_softc *sc; 779 struct tty *tp; 780 struct wsscreen *scr; 781 782 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 783 784 if (ISWSDISPLAYCTL(dev)) 785 return (0); 786 787 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 788 789 if (!WSSCREEN_HAS_TTY(scr)) 790 return (ENODEV); 791 792 tp = scr->scr_tty; 793 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 794 } 795 796 int 797 wsdisplaywrite(dev_t dev, struct uio *uio, int flag) 798 { 799 struct wsdisplay_softc *sc; 800 struct tty *tp; 801 struct wsscreen *scr; 802 803 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 804 805 if (ISWSDISPLAYCTL(dev)) 806 return (0); 807 808 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 809 810 if (!WSSCREEN_HAS_TTY(scr)) 811 return (ENODEV); 812 813 tp = scr->scr_tty; 814 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 815 } 816 817 int 818 wsdisplaypoll(dev_t dev, int events, struct proc *p) 819 { 820 struct wsdisplay_softc *sc; 821 struct tty *tp; 822 struct wsscreen *scr; 823 824 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 825 826 if (ISWSDISPLAYCTL(dev)) 827 return (0); 828 829 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 830 831 if (!WSSCREEN_HAS_TTY(scr)) 832 return (ENODEV); 833 834 tp = scr->scr_tty; 835 return ((*tp->t_linesw->l_poll)(tp, events, p)); 836 } 837 838 struct tty * 839 wsdisplaytty(dev_t dev) 840 { 841 struct wsdisplay_softc *sc; 842 struct wsscreen *scr; 843 844 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 845 846 if (ISWSDISPLAYCTL(dev)) 847 panic("wsdisplaytty() on ctl device"); 848 849 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 850 851 return (scr->scr_tty); 852 } 853 854 int 855 wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 856 { 857 struct wsdisplay_softc *sc; 858 struct tty *tp; 859 int error; 860 struct wsscreen *scr; 861 862 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 863 864 #ifdef WSDISPLAY_COMPAT_USL 865 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 866 if (error >= 0) 867 return (error); 868 #endif 869 870 if (ISWSDISPLAYCTL(dev)) 871 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 872 873 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 874 875 if (WSSCREEN_HAS_TTY(scr)) { 876 tp = scr->scr_tty; 877 878 /* printf("disc\n"); */ 879 /* do the line discipline ioctls first */ 880 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 881 if (error >= 0) 882 return (error); 883 884 /* printf("tty\n"); */ 885 /* then the tty ioctls */ 886 error = ttioctl(tp, cmd, data, flag, p); 887 if (error >= 0) 888 return (error); 889 } 890 891 #ifdef WSDISPLAY_COMPAT_USL 892 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 893 if (error >= 0) 894 return (error); 895 #endif 896 897 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p); 898 return (error != -1 ? error : ENOTTY); 899 } 900 901 int 902 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp) 903 { 904 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 905 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 906 (caddr_t)dp, 0, NULL)); 907 } 908 909 int 910 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 911 u_long cmd, caddr_t data, int flag, struct proc *p) 912 { 913 int error; 914 char namebuf[16]; 915 struct wsdisplay_font fd; 916 917 #if NWSKBD > 0 918 struct wsevsrc *inp; 919 920 #ifdef WSDISPLAY_COMPAT_RAWKBD 921 switch (cmd) { 922 case WSKBDIO_SETMODE: 923 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 924 return (wsdisplay_update_rawkbd(sc, scr)); 925 case WSKBDIO_GETMODE: 926 *(int *)data = (scr->scr_rawkbd ? 927 WSKBD_RAW : WSKBD_TRANSLATED); 928 return (0); 929 } 930 #endif 931 inp = sc->sc_input; 932 if (inp == NULL) 933 return (ENXIO); 934 error = wsevsrc_display_ioctl(inp, cmd, data, flag, p); 935 if (error >= 0) 936 return (error); 937 #endif /* NWSKBD > 0 */ 938 939 switch (cmd) { 940 case WSDISPLAYIO_GMODE: 941 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 942 WSDISPLAYIO_MODE_MAPPED : 943 WSDISPLAYIO_MODE_EMUL); 944 return (0); 945 946 case WSDISPLAYIO_SMODE: 947 #define d (*(int *)data) 948 if (d != WSDISPLAYIO_MODE_EMUL && 949 d != WSDISPLAYIO_MODE_MAPPED) 950 return (EINVAL); 951 952 if (WSSCREEN_HAS_EMULATOR(scr)) { 953 scr->scr_flags &= ~SCR_GRAPHICS; 954 if (d == WSDISPLAYIO_MODE_MAPPED) 955 scr->scr_flags |= SCR_GRAPHICS; 956 } else if (d == WSDISPLAYIO_MODE_EMUL) 957 return (EINVAL); 958 959 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 960 flag, p); 961 962 return (0); 963 #undef d 964 965 case WSDISPLAYIO_USEFONT: 966 #define d ((struct wsdisplay_usefontdata *)data) 967 if (!sc->sc_accessops->load_font) 968 return (EINVAL); 969 if (d->name) { 970 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 971 if (error) 972 return (error); 973 fd.name = namebuf; 974 } else 975 fd.name = 0; 976 fd.data = 0; 977 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 978 scr->scr_dconf->emulcookie, &fd); 979 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 980 (*scr->scr_dconf->wsemul->reset) 981 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 982 return (error); 983 #undef d 984 } 985 986 /* check ioctls for display */ 987 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 988 flag, p)); 989 } 990 991 int 992 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 993 int flag, struct proc *p) 994 { 995 int error; 996 char *type, typebuf[16], *emul, emulbuf[16]; 997 void *buf; 998 u_int fontsz; 999 #if defined(COMPAT_14) && NWSKBD > 0 1000 struct wsmux_device wsmuxdata; 1001 #endif 1002 #if NWSKBD > 0 1003 struct wsevsrc *inp; 1004 #endif 1005 1006 switch (cmd) { 1007 case WSDISPLAYIO_ADDSCREEN: 1008 #define d ((struct wsdisplay_addscreendata *)data) 1009 if (d->screentype) { 1010 error = copyinstr(d->screentype, typebuf, 1011 sizeof(typebuf), 0); 1012 if (error) 1013 return (error); 1014 type = typebuf; 1015 } else 1016 type = 0; 1017 if (d->emul) { 1018 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1019 if (error) 1020 return (error); 1021 emul = emulbuf; 1022 } else 1023 emul = 0; 1024 1025 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1026 wsdisplay_addscreen_print(sc, d->idx, 0); 1027 return (error); 1028 #undef d 1029 case WSDISPLAYIO_DELSCREEN: 1030 #define d ((struct wsdisplay_delscreendata *)data) 1031 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1032 #undef d 1033 case WSDISPLAYIO_LDFONT: 1034 #define d ((struct wsdisplay_font *)data) 1035 if (!sc->sc_accessops->load_font) 1036 return (EINVAL); 1037 if (d->name) { 1038 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1039 if (error) 1040 return (error); 1041 d->name = typebuf; 1042 } else 1043 d->name = "loaded"; /* ??? */ 1044 fontsz = d->fontheight * d->stride * d->numchars; 1045 if (fontsz > WSDISPLAY_MAXFONTSZ) 1046 return (EINVAL); 1047 1048 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1049 error = copyin(d->data, buf, fontsz); 1050 if (error) { 1051 free(buf, M_DEVBUF); 1052 return (error); 1053 } 1054 d->data = buf; 1055 error = 1056 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1057 free(buf, M_DEVBUF); 1058 #undef d 1059 return (error); 1060 1061 #if NWSKBD > 0 1062 #ifdef COMPAT_14 1063 case _O_WSDISPLAYIO_SETKEYBOARD: 1064 #define d ((struct wsdisplay_kbddata *)data) 1065 inp = sc->sc_input; 1066 if (inp == NULL) 1067 return (ENXIO); 1068 switch (d->op) { 1069 case _O_WSDISPLAY_KBD_ADD: 1070 if (d->idx == -1) { 1071 d->idx = wskbd_pickfree(); 1072 if (d->idx == -1) 1073 return (ENXIO); 1074 } 1075 wsmuxdata.type = WSMUX_KBD; 1076 wsmuxdata.idx = d->idx; 1077 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE, 1078 &wsmuxdata, flag, p)); 1079 case _O_WSDISPLAY_KBD_DEL: 1080 wsmuxdata.type = WSMUX_KBD; 1081 wsmuxdata.idx = d->idx; 1082 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE, 1083 &wsmuxdata, flag, p)); 1084 default: 1085 return (EINVAL); 1086 } 1087 #undef d 1088 #endif 1089 1090 case WSMUXIO_ADD_DEVICE: 1091 #define d ((struct wsmux_device *)data) 1092 if (d->idx == -1 && d->type == WSMUX_KBD) 1093 d->idx = wskbd_pickfree(); 1094 #undef d 1095 /* fall into */ 1096 case WSMUXIO_INJECTEVENT: 1097 case WSMUXIO_REMOVE_DEVICE: 1098 case WSMUXIO_LIST_DEVICES: 1099 inp = sc->sc_input; 1100 if (inp == NULL) 1101 return (ENXIO); 1102 return (wsevsrc_ioctl(inp, cmd, data, flag, p)); 1103 #endif /* NWSKBD > 0 */ 1104 1105 } 1106 return (EINVAL); 1107 } 1108 1109 paddr_t 1110 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1111 { 1112 struct wsdisplay_softc *sc = 1113 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1114 struct wsscreen *scr; 1115 1116 if (ISWSDISPLAYCTL(dev)) 1117 return (-1); 1118 1119 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1120 1121 if (!(scr->scr_flags & SCR_GRAPHICS)) 1122 return (-1); 1123 1124 /* pass mmap to display */ 1125 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1126 } 1127 1128 void 1129 wsdisplaystart(struct tty *tp) 1130 { 1131 struct wsdisplay_softc *sc; 1132 struct wsscreen *scr; 1133 int s, n; 1134 u_char *buf; 1135 1136 s = spltty(); 1137 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1138 splx(s); 1139 return; 1140 } 1141 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1142 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1143 if (scr->scr_hold_screen) { 1144 tp->t_state |= TS_TIMEOUT; 1145 splx(s); 1146 return; 1147 } 1148 tp->t_state |= TS_BUSY; 1149 splx(s); 1150 1151 /* 1152 * Drain output from ring buffer. 1153 * The output will normally be in one contiguous chunk, but when the 1154 * ring wraps, it will be in two pieces.. one at the end of the ring, 1155 * the other at the start. For performance, rather than loop here, 1156 * we output one chunk, see if there's another one, and if so, output 1157 * it too. 1158 */ 1159 1160 n = ndqb(&tp->t_outq, 0); 1161 buf = tp->t_outq.c_cf; 1162 1163 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1164 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1165 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1166 buf, n, 0); 1167 } 1168 ndflush(&tp->t_outq, n); 1169 1170 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1171 buf = tp->t_outq.c_cf; 1172 1173 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1174 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1175 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1176 buf, n, 0); 1177 } 1178 ndflush(&tp->t_outq, n); 1179 } 1180 1181 s = spltty(); 1182 tp->t_state &= ~TS_BUSY; 1183 /* Come back if there's more to do */ 1184 if (tp->t_outq.c_cc) { 1185 tp->t_state |= TS_TIMEOUT; 1186 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1187 ttrstrt, tp); 1188 } 1189 if (tp->t_outq.c_cc <= tp->t_lowat) { 1190 if (tp->t_state&TS_ASLEEP) { 1191 tp->t_state &= ~TS_ASLEEP; 1192 wakeup(&tp->t_outq); 1193 } 1194 selwakeup(&tp->t_wsel); 1195 } 1196 splx(s); 1197 } 1198 1199 void 1200 wsdisplaystop(struct tty *tp, int flag) 1201 { 1202 int s; 1203 1204 s = spltty(); 1205 if (ISSET(tp->t_state, TS_BUSY)) 1206 if (!ISSET(tp->t_state, TS_TTSTOP)) 1207 SET(tp->t_state, TS_FLUSH); 1208 splx(s); 1209 } 1210 1211 /* Set line parameters. */ 1212 int 1213 wsdisplayparam(struct tty *tp, struct termios *t) 1214 { 1215 1216 tp->t_ispeed = t->c_ispeed; 1217 tp->t_ospeed = t->c_ospeed; 1218 tp->t_cflag = t->c_cflag; 1219 return 0; 1220 } 1221 1222 /* 1223 * Callbacks for the emulation code. 1224 */ 1225 void 1226 wsdisplay_emulbell(void *v) 1227 { 1228 struct wsscreen *scr = v; 1229 1230 if (scr == NULL) /* console, before real attach */ 1231 return; 1232 1233 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1234 return; 1235 1236 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1237 FWRITE, NULL); 1238 } 1239 1240 void 1241 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1242 { 1243 struct wsscreen *scr = v; 1244 struct tty *tp; 1245 1246 if (v == NULL) /* console, before real attach */ 1247 return; 1248 1249 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1250 return; 1251 if (!WSSCREEN_HAS_TTY(scr)) 1252 return; 1253 1254 tp = scr->scr_tty; 1255 while (count-- > 0) 1256 (*tp->t_linesw->l_rint)(*data++, tp); 1257 }; 1258 1259 /* 1260 * Calls from the keyboard interface. 1261 */ 1262 void 1263 wsdisplay_kbdinput(struct device *dev, keysym_t ks) 1264 { 1265 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1266 struct wsscreen *scr; 1267 char *dp; 1268 int count; 1269 struct tty *tp; 1270 1271 KASSERT(sc != NULL); 1272 1273 scr = sc->sc_focus; 1274 1275 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1276 return; 1277 1278 tp = scr->scr_tty; 1279 1280 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1281 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1282 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1283 count = (*scr->scr_dconf->wsemul->translate) 1284 (scr->scr_dconf->wsemulcookie, ks, &dp); 1285 while (count-- > 0) 1286 (*tp->t_linesw->l_rint)(*dp++, tp); 1287 } 1288 } 1289 1290 #if defined(WSDISPLAY_COMPAT_RAWKBD) 1291 int 1292 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1293 { 1294 #if NWSKBD > 0 1295 int s, raw, data, error; 1296 struct wsevsrc *inp; 1297 1298 s = spltty(); 1299 1300 raw = (scr ? scr->scr_rawkbd : 0); 1301 1302 if (scr != sc->sc_focus || 1303 sc->sc_rawkbd == raw) { 1304 splx(s); 1305 return (0); 1306 } 1307 1308 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1309 inp = sc->sc_input; 1310 if (inp == NULL) 1311 return (ENXIO); 1312 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0); 1313 if (!error) 1314 sc->sc_rawkbd = raw; 1315 splx(s); 1316 return (error); 1317 #else 1318 return (0); 1319 #endif 1320 } 1321 #endif 1322 1323 int 1324 wsdisplay_switch3(void *arg, int error, int waitok) 1325 { 1326 struct wsdisplay_softc *sc = arg; 1327 int no; 1328 struct wsscreen *scr; 1329 1330 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1331 printf("wsdisplay_switch3: not switching\n"); 1332 return (EINVAL); 1333 } 1334 1335 no = sc->sc_screenwanted; 1336 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1337 panic("wsdisplay_switch3: invalid screen %d", no); 1338 scr = sc->sc_scr[no]; 1339 if (!scr) { 1340 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1341 error = ENXIO; 1342 } 1343 1344 if (error) { 1345 /* try to recover, avoid recursion */ 1346 1347 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1348 printf("wsdisplay_switch3: giving up\n"); 1349 sc->sc_focus = 0; 1350 #ifdef WSDISPLAY_COMPAT_RAWKBD 1351 wsdisplay_update_rawkbd(sc, 0); 1352 #endif 1353 sc->sc_flags &= ~SC_SWITCHPENDING; 1354 return (error); 1355 } 1356 1357 sc->sc_screenwanted = sc->sc_oldscreen; 1358 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1359 return (wsdisplay_switch1(arg, 0, waitok)); 1360 } 1361 1362 sc->sc_flags &= ~SC_SWITCHPENDING; 1363 1364 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1365 wakeup(scr); 1366 return (error); 1367 } 1368 1369 int 1370 wsdisplay_switch2(void *arg, int error, int waitok) 1371 { 1372 struct wsdisplay_softc *sc = arg; 1373 int no; 1374 struct wsscreen *scr; 1375 1376 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1377 printf("wsdisplay_switch2: not switching\n"); 1378 return (EINVAL); 1379 } 1380 1381 no = sc->sc_screenwanted; 1382 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1383 panic("wsdisplay_switch2: invalid screen %d", no); 1384 scr = sc->sc_scr[no]; 1385 if (!scr) { 1386 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1387 error = ENXIO; 1388 } 1389 1390 if (error) { 1391 /* try to recover, avoid recursion */ 1392 1393 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1394 printf("wsdisplay_switch2: giving up\n"); 1395 sc->sc_focus = 0; 1396 sc->sc_flags &= ~SC_SWITCHPENDING; 1397 return (error); 1398 } 1399 1400 sc->sc_screenwanted = sc->sc_oldscreen; 1401 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1402 return (wsdisplay_switch1(arg, 0, waitok)); 1403 } 1404 1405 sc->sc_focusidx = no; 1406 sc->sc_focus = scr; 1407 1408 #ifdef WSDISPLAY_COMPAT_RAWKBD 1409 (void) wsdisplay_update_rawkbd(sc, scr); 1410 #endif 1411 /* keyboard map??? */ 1412 1413 #define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3) 1414 if (scr->scr_syncops) { 1415 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1416 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1417 if (error == EAGAIN) { 1418 /* switch will be done asynchronously */ 1419 return (0); 1420 } 1421 } 1422 1423 return (wsdisplay_switch3(sc, error, waitok)); 1424 } 1425 1426 int 1427 wsdisplay_switch1(void *arg, int error, int waitok) 1428 { 1429 struct wsdisplay_softc *sc = arg; 1430 int no; 1431 struct wsscreen *scr; 1432 1433 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1434 printf("wsdisplay_switch1: not switching\n"); 1435 return (EINVAL); 1436 } 1437 1438 no = sc->sc_screenwanted; 1439 if (no == WSDISPLAY_NULLSCREEN) { 1440 sc->sc_flags &= ~SC_SWITCHPENDING; 1441 if (!error) { 1442 sc->sc_focus = 0; 1443 } 1444 wakeup(sc); 1445 return (error); 1446 } 1447 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1448 panic("wsdisplay_switch1: invalid screen %d", no); 1449 scr = sc->sc_scr[no]; 1450 if (!scr) { 1451 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1452 error = ENXIO; 1453 } 1454 1455 if (error) { 1456 sc->sc_flags &= ~SC_SWITCHPENDING; 1457 return (error); 1458 } 1459 1460 #define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2) 1461 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1462 scr->scr_dconf->emulcookie, 1463 waitok, 1464 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1465 if (error == EAGAIN) { 1466 /* switch will be done asynchronously */ 1467 return (0); 1468 } 1469 1470 return (wsdisplay_switch2(sc, error, waitok)); 1471 } 1472 1473 int 1474 wsdisplay_switch(struct device *dev, int no, int waitok) 1475 { 1476 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1477 int s, res = 0; 1478 struct wsscreen *scr; 1479 1480 if (no != WSDISPLAY_NULLSCREEN && 1481 (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])) 1482 return (ENXIO); 1483 1484 s = spltty(); 1485 1486 if ((sc->sc_focus && no == sc->sc_focusidx) || 1487 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1488 splx(s); 1489 return (0); 1490 } 1491 1492 if (sc->sc_flags & SC_SWITCHPENDING) { 1493 splx(s); 1494 return (EBUSY); 1495 } 1496 1497 sc->sc_flags |= SC_SWITCHPENDING; 1498 sc->sc_screenwanted = no; 1499 1500 splx(s); 1501 1502 scr = sc->sc_focus; 1503 if (!scr) { 1504 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1505 return (wsdisplay_switch1(sc, 0, waitok)); 1506 } else 1507 sc->sc_oldscreen = sc->sc_focusidx; 1508 1509 #define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1) 1510 if (scr->scr_syncops) { 1511 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1512 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1513 if (res == EAGAIN) { 1514 /* switch will be done asynchronously */ 1515 return (0); 1516 } 1517 } else if (scr->scr_flags & SCR_GRAPHICS) { 1518 /* no way to save state */ 1519 res = EBUSY; 1520 } 1521 1522 return (wsdisplay_switch1(sc, res, waitok)); 1523 } 1524 1525 void 1526 wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op) 1527 { 1528 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1529 struct wsscreen *scr; 1530 1531 KASSERT(sc != NULL); 1532 scr = sc->sc_focus; 1533 1534 if (!scr) 1535 return; 1536 1537 switch (op) { 1538 case WSDISPLAY_RESETEMUL: 1539 if (!WSSCREEN_HAS_EMULATOR(scr)) 1540 break; 1541 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1542 WSEMUL_RESET); 1543 break; 1544 case WSDISPLAY_RESETCLOSE: 1545 wsdisplay_closescreen(sc, scr); 1546 break; 1547 } 1548 } 1549 1550 /* 1551 * Interface for (external) VT switch / process synchronization code 1552 */ 1553 int 1554 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1555 void *cookie) 1556 { 1557 if (scr->scr_syncops) { 1558 /* 1559 * The screen is already claimed. 1560 * Check if the owner is still alive. 1561 */ 1562 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1563 return (EBUSY); 1564 } 1565 scr->scr_syncops = ops; 1566 scr->scr_synccookie = cookie; 1567 return (0); 1568 } 1569 1570 int 1571 wsscreen_detach_sync(struct wsscreen *scr) 1572 { 1573 if (!scr->scr_syncops) 1574 return (EINVAL); 1575 scr->scr_syncops = 0; 1576 return (0); 1577 } 1578 1579 int 1580 wsscreen_lookup_sync(struct wsscreen *scr, 1581 const struct wscons_syncops *ops, /* used as ID */ 1582 void **cookiep) 1583 { 1584 if (!scr->scr_syncops || ops != scr->scr_syncops) 1585 return (EINVAL); 1586 *cookiep = scr->scr_synccookie; 1587 return (0); 1588 } 1589 1590 /* 1591 * Interface to virtual screen stuff 1592 */ 1593 int 1594 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 1595 { 1596 return (WSDISPLAY_MAXSCREEN - 1); 1597 } 1598 1599 int 1600 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 1601 { 1602 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1603 return (EINVAL); 1604 if (!sc->sc_scr[idx]) 1605 return (ENXIO); 1606 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1607 } 1608 1609 int 1610 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 1611 { 1612 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1613 } 1614 1615 int 1616 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 1617 { 1618 struct wsscreen *scr; 1619 int s, res = 0; 1620 1621 if (no == WSDISPLAY_NULLSCREEN) { 1622 s = spltty(); 1623 while (sc->sc_focus && res == 0) { 1624 res = tsleep(sc, PCATCH, "wswait", 0); 1625 } 1626 splx(s); 1627 return (res); 1628 } 1629 1630 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1631 return (ENXIO); 1632 scr = sc->sc_scr[no]; 1633 if (!scr) 1634 return (ENXIO); 1635 1636 s = spltty(); 1637 if (scr != sc->sc_focus) { 1638 scr->scr_flags |= SCR_WAITACTIVE; 1639 res = tsleep(scr, PCATCH, "wswait", 0); 1640 if (scr != sc->sc_scr[no]) 1641 res = ENXIO; /* disappeared in the meantime */ 1642 else 1643 scr->scr_flags &= ~SCR_WAITACTIVE; 1644 } 1645 splx(s); 1646 return (res); 1647 } 1648 1649 void 1650 wsdisplay_kbdholdscreen(struct device *dev, int hold) 1651 { 1652 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1653 struct wsscreen *scr; 1654 1655 scr = sc->sc_focus; 1656 1657 if (hold) 1658 scr->scr_hold_screen = 1; 1659 else { 1660 scr->scr_hold_screen = 0; 1661 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1662 ttrstrt, scr->scr_tty); /* "immediate" */ 1663 } 1664 } 1665 1666 #if NWSKBD > 0 1667 void 1668 wsdisplay_set_console_kbd(struct wsevsrc *src) 1669 { 1670 if (wsdisplay_console_device == NULL) { 1671 src->me_dispdv = NULL; 1672 return; 1673 } 1674 #if NWSMUX > 0 1675 if (wsmux_attach_sc((struct wsmux_softc *) 1676 wsdisplay_console_device->sc_input, src)) { 1677 src->me_dispdv = NULL; 1678 return; 1679 } 1680 #else 1681 wsdisplay_console_device->sc_input = src; 1682 #endif 1683 src->me_dispdv = &wsdisplay_console_device->sc_dv; 1684 } 1685 #endif /* NWSKBD > 0 */ 1686 1687 /* 1688 * Console interface. 1689 */ 1690 void 1691 wsdisplay_cnputc(dev_t dev, int i) 1692 { 1693 struct wsscreen_internal *dc; 1694 char c = i; 1695 1696 if (!wsdisplay_console_initted) 1697 return; 1698 1699 if (wsdisplay_console_device != NULL && 1700 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1701 return; 1702 1703 dc = &wsdisplay_console_conf; 1704 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1705 } 1706 1707 static int 1708 wsdisplay_getc_dummy(dev_t dev) 1709 { 1710 /* panic? */ 1711 return (0); 1712 } 1713 1714 static void 1715 wsdisplay_pollc(dev_t dev, int on) 1716 { 1717 1718 wsdisplay_cons_pollmode = on; 1719 1720 /* notify to fb drivers */ 1721 if (wsdisplay_console_device != NULL && 1722 wsdisplay_console_device->sc_accessops->pollc != NULL) 1723 (*wsdisplay_console_device->sc_accessops->pollc) 1724 (wsdisplay_console_device->sc_accesscookie, on); 1725 1726 /* notify to kbd drivers */ 1727 if (wsdisplay_cons_kbd_pollc) 1728 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 1729 } 1730 1731 void 1732 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 1733 void (*bell)(dev_t, u_int, u_int, u_int)) 1734 { 1735 wsdisplay_cons.cn_getc = get; 1736 wsdisplay_cons.cn_bell = bell; 1737 wsdisplay_cons_kbd_pollc = poll; 1738 } 1739 1740 void 1741 wsdisplay_unset_cons_kbd(void) 1742 { 1743 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1744 wsdisplay_cons.cn_bell = NULL; 1745 wsdisplay_cons_kbd_pollc = 0; 1746 } 1747 1748 /* 1749 * Switch the console display to it's first screen. 1750 */ 1751 void 1752 wsdisplay_switchtoconsole(void) 1753 { 1754 struct wsdisplay_softc *sc; 1755 struct wsscreen *scr; 1756 1757 if (wsdisplay_console_device != NULL) { 1758 sc = wsdisplay_console_device; 1759 scr = sc->sc_scr[0]; 1760 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1761 scr->scr_dconf->emulcookie, 1762 0, NULL, NULL); 1763 } 1764 } 1765 1766 /* 1767 * Switch the console at shutdown. 1768 */ 1769 static void 1770 wsdisplay_shutdownhook(void *arg) 1771 { 1772 1773 wsdisplay_switchtoconsole(); 1774 } 1775