1 /* $NetBSD: wsdisplay.c,v 1.63 2002/04/07 09:25:47 hannken 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.63 2002/04/07 09:25:47 hannken 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 wsmux_softc *mux; 566 567 if (kbdmux >= 0) 568 mux = wsmux_getmux(kbdmux); 569 else 570 mux = wsmux_create("dmux", sc->sc_dv.dv_unit); 571 /* XXX panic()ing isn't nice, but attach cannot fail */ 572 if (mux == NULL) 573 panic("wsdisplay_common_attach: no memory\n"); 574 sc->sc_input = &mux->sc_base; 575 mux->sc_base.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 #if NWSKBD > 0 && NWSMUX > 0 612 wsmux_set_display(mux, &sc->sc_dv); 613 #endif 614 615 sc->sc_accessops = accessops; 616 sc->sc_accesscookie = accesscookie; 617 sc->sc_scrdata = scrdata; 618 619 /* 620 * Set up a number of virtual screens if wanted. The 621 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 622 * is for special cases like installation kernels. 623 */ 624 for (i = start; i < wsdisplay_defaultscreens; i++) { 625 if (wsdisplay_addscreen(sc, i, 0, 0)) 626 break; 627 } 628 629 if (i > start) 630 wsdisplay_addscreen_print(sc, start, i-start); 631 632 if (hookset == 0) 633 shutdownhook_establish(wsdisplay_shutdownhook, NULL); 634 hookset = 1; 635 } 636 637 void 638 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie, 639 int ccol, int crow, long defattr) 640 { 641 const struct wsemul_ops *wsemul; 642 643 KASSERT(!wsdisplay_console_initted); 644 KASSERT(type->nrows > 0); 645 KASSERT(type->ncols > 0); 646 KASSERT(crow < type->nrows); 647 KASSERT(ccol < type->ncols); 648 649 wsdisplay_console_conf.emulops = type->textops; 650 wsdisplay_console_conf.emulcookie = cookie; 651 wsdisplay_console_conf.scrdata = type; 652 653 wsemul = wsemul_pick(0); /* default */ 654 wsdisplay_console_conf.wsemul = wsemul; 655 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 656 ccol, crow, 657 defattr); 658 659 cn_tab = &wsdisplay_cons; 660 wsdisplay_console_initted = 1; 661 } 662 663 /* 664 * Tty and cdevsw functions. 665 */ 666 int 667 wsdisplayopen(dev_t dev, int flag, int mode, struct proc *p) 668 { 669 struct wsdisplay_softc *sc; 670 struct tty *tp; 671 int newopen, error; 672 struct wsscreen *scr; 673 674 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 675 if (sc == NULL) /* make sure it was attached */ 676 return (ENXIO); 677 678 if (ISWSDISPLAYCTL(dev)) 679 return (0); 680 681 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 682 return (ENXIO); 683 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 684 if (!scr) 685 return (ENXIO); 686 687 if (WSSCREEN_HAS_TTY(scr)) { 688 tp = scr->scr_tty; 689 tp->t_oproc = wsdisplaystart; 690 tp->t_param = wsdisplayparam; 691 tp->t_dev = dev; 692 newopen = (tp->t_state & TS_ISOPEN) == 0; 693 if (newopen) { 694 ttychars(tp); 695 tp->t_iflag = TTYDEF_IFLAG; 696 tp->t_oflag = TTYDEF_OFLAG; 697 tp->t_cflag = TTYDEF_CFLAG; 698 tp->t_lflag = TTYDEF_LFLAG; 699 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 700 wsdisplayparam(tp, &tp->t_termios); 701 ttsetwater(tp); 702 } else if ((tp->t_state & TS_XCLUDE) != 0 && 703 p->p_ucred->cr_uid != 0) 704 return EBUSY; 705 tp->t_state |= TS_CARR_ON; 706 707 error = ((*tp->t_linesw->l_open)(dev, tp)); 708 if (error) 709 return (error); 710 711 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 712 /* set window sizes as appropriate, and reset 713 the emulation */ 714 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 715 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 716 717 /* wsdisplay_set_emulation() */ 718 } 719 } 720 721 scr->scr_flags |= SCR_OPEN; 722 return (0); 723 } 724 725 int 726 wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p) 727 { 728 struct wsdisplay_softc *sc; 729 struct tty *tp; 730 struct wsscreen *scr; 731 732 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 733 734 if (ISWSDISPLAYCTL(dev)) 735 return (0); 736 737 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 738 739 if (WSSCREEN_HAS_TTY(scr)) { 740 if (scr->scr_hold_screen) { 741 int s; 742 743 /* XXX RESET KEYBOARD LEDS, etc. */ 744 s = spltty(); /* avoid conflict with keyboard */ 745 wsdisplay_kbdholdscreen((struct device *)sc, 0); 746 splx(s); 747 } 748 tp = scr->scr_tty; 749 (*tp->t_linesw->l_close)(tp, flag); 750 ttyclose(tp); 751 } 752 753 if (scr->scr_syncops) 754 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 755 756 if (WSSCREEN_HAS_EMULATOR(scr)) { 757 scr->scr_flags &= ~SCR_GRAPHICS; 758 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 759 WSEMUL_RESET); 760 if (wsdisplay_clearonclose) 761 (*scr->scr_dconf->wsemul->reset) 762 (scr->scr_dconf->wsemulcookie, 763 WSEMUL_CLEARSCREEN); 764 } 765 766 #ifdef WSDISPLAY_COMPAT_RAWKBD 767 if (scr->scr_rawkbd) { 768 int kbmode = WSKBD_TRANSLATED; 769 (void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 770 (caddr_t)&kbmode, 0, p); 771 } 772 #endif 773 774 scr->scr_flags &= ~SCR_OPEN; 775 776 return (0); 777 } 778 779 int 780 wsdisplayread(dev_t dev, struct uio *uio, int flag) 781 { 782 struct wsdisplay_softc *sc; 783 struct tty *tp; 784 struct wsscreen *scr; 785 786 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 787 788 if (ISWSDISPLAYCTL(dev)) 789 return (0); 790 791 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 792 793 if (!WSSCREEN_HAS_TTY(scr)) 794 return (ENODEV); 795 796 tp = scr->scr_tty; 797 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 798 } 799 800 int 801 wsdisplaywrite(dev_t dev, struct uio *uio, int flag) 802 { 803 struct wsdisplay_softc *sc; 804 struct tty *tp; 805 struct wsscreen *scr; 806 807 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 808 809 if (ISWSDISPLAYCTL(dev)) 810 return (0); 811 812 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 813 814 if (!WSSCREEN_HAS_TTY(scr)) 815 return (ENODEV); 816 817 tp = scr->scr_tty; 818 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 819 } 820 821 int 822 wsdisplaypoll(dev_t dev, int events, struct proc *p) 823 { 824 struct wsdisplay_softc *sc; 825 struct tty *tp; 826 struct wsscreen *scr; 827 828 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 829 830 if (ISWSDISPLAYCTL(dev)) 831 return (0); 832 833 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 834 835 if (!WSSCREEN_HAS_TTY(scr)) 836 return (ENODEV); 837 838 tp = scr->scr_tty; 839 return ((*tp->t_linesw->l_poll)(tp, events, p)); 840 } 841 842 struct tty * 843 wsdisplaytty(dev_t dev) 844 { 845 struct wsdisplay_softc *sc; 846 struct wsscreen *scr; 847 848 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 849 850 if (ISWSDISPLAYCTL(dev)) 851 panic("wsdisplaytty() on ctl device"); 852 853 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 854 855 return (scr->scr_tty); 856 } 857 858 int 859 wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 860 { 861 struct wsdisplay_softc *sc; 862 struct tty *tp; 863 int error; 864 struct wsscreen *scr; 865 866 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 867 868 #ifdef WSDISPLAY_COMPAT_USL 869 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 870 if (error != EPASSTHROUGH) 871 return (error); 872 #endif 873 874 if (ISWSDISPLAYCTL(dev)) 875 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 876 877 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 878 879 if (WSSCREEN_HAS_TTY(scr)) { 880 tp = scr->scr_tty; 881 882 /* printf("disc\n"); */ 883 /* do the line discipline ioctls first */ 884 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 885 if (error != EPASSTHROUGH) 886 return (error); 887 888 /* printf("tty\n"); */ 889 /* then the tty ioctls */ 890 error = ttioctl(tp, cmd, data, flag, p); 891 if (error != EPASSTHROUGH) 892 return (error); 893 } 894 895 #ifdef WSDISPLAY_COMPAT_USL 896 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 897 if (error != EPASSTHROUGH) 898 return (error); 899 #endif 900 901 return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)); 902 } 903 904 int 905 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp) 906 { 907 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 908 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 909 (caddr_t)dp, 0, NULL)); 910 } 911 912 int 913 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 914 u_long cmd, caddr_t data, int flag, struct proc *p) 915 { 916 int error; 917 char namebuf[16]; 918 struct wsdisplay_font fd; 919 920 #if NWSKBD > 0 921 struct wsevsrc *inp; 922 923 #ifdef WSDISPLAY_COMPAT_RAWKBD 924 switch (cmd) { 925 case WSKBDIO_SETMODE: 926 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 927 return (wsdisplay_update_rawkbd(sc, scr)); 928 case WSKBDIO_GETMODE: 929 *(int *)data = (scr->scr_rawkbd ? 930 WSKBD_RAW : WSKBD_TRANSLATED); 931 return (0); 932 } 933 #endif 934 inp = sc->sc_input; 935 if (inp == NULL) 936 return (ENXIO); 937 error = wsevsrc_display_ioctl(inp, cmd, data, flag, p); 938 if (error != EPASSTHROUGH) 939 return (error); 940 #endif /* NWSKBD > 0 */ 941 942 switch (cmd) { 943 case WSDISPLAYIO_GMODE: 944 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 945 WSDISPLAYIO_MODE_MAPPED : 946 WSDISPLAYIO_MODE_EMUL); 947 return (0); 948 949 case WSDISPLAYIO_SMODE: 950 #define d (*(int *)data) 951 if (d != WSDISPLAYIO_MODE_EMUL && 952 d != WSDISPLAYIO_MODE_MAPPED) 953 return (EINVAL); 954 955 if (WSSCREEN_HAS_EMULATOR(scr)) { 956 scr->scr_flags &= ~SCR_GRAPHICS; 957 if (d == WSDISPLAYIO_MODE_MAPPED) 958 scr->scr_flags |= SCR_GRAPHICS; 959 } else if (d == WSDISPLAYIO_MODE_EMUL) 960 return (EINVAL); 961 962 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 963 flag, p); 964 965 return (0); 966 #undef d 967 968 case WSDISPLAYIO_SFONT: 969 #define d ((struct wsdisplay_usefontdata *)data) 970 if (!sc->sc_accessops->load_font) 971 return (EINVAL); 972 if (d->name) { 973 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 974 if (error) 975 return (error); 976 fd.name = namebuf; 977 } else 978 fd.name = 0; 979 fd.data = 0; 980 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 981 scr->scr_dconf->emulcookie, &fd); 982 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 983 (*scr->scr_dconf->wsemul->reset) 984 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 985 return (error); 986 #undef d 987 } 988 989 /* check ioctls for display */ 990 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 991 flag, p)); 992 } 993 994 int 995 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 996 int flag, struct proc *p) 997 { 998 int error; 999 char *type, typebuf[16], *emul, emulbuf[16]; 1000 void *buf; 1001 u_int fontsz; 1002 #if defined(COMPAT_14) && NWSKBD > 0 1003 struct wsmux_device wsmuxdata; 1004 #endif 1005 #if NWSKBD > 0 1006 struct wsevsrc *inp; 1007 #endif 1008 1009 switch (cmd) { 1010 case WSDISPLAYIO_ADDSCREEN: 1011 #define d ((struct wsdisplay_addscreendata *)data) 1012 if (d->screentype) { 1013 error = copyinstr(d->screentype, typebuf, 1014 sizeof(typebuf), 0); 1015 if (error) 1016 return (error); 1017 type = typebuf; 1018 } else 1019 type = 0; 1020 if (d->emul) { 1021 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1022 if (error) 1023 return (error); 1024 emul = emulbuf; 1025 } else 1026 emul = 0; 1027 1028 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1029 wsdisplay_addscreen_print(sc, d->idx, 0); 1030 return (error); 1031 #undef d 1032 case WSDISPLAYIO_DELSCREEN: 1033 #define d ((struct wsdisplay_delscreendata *)data) 1034 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1035 #undef d 1036 case WSDISPLAYIO_LDFONT: 1037 #define d ((struct wsdisplay_font *)data) 1038 if (!sc->sc_accessops->load_font) 1039 return (EINVAL); 1040 if (d->name) { 1041 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1042 if (error) 1043 return (error); 1044 d->name = typebuf; 1045 } else 1046 d->name = "loaded"; /* ??? */ 1047 fontsz = d->fontheight * d->stride * d->numchars; 1048 if (fontsz > WSDISPLAY_MAXFONTSZ) 1049 return (EINVAL); 1050 1051 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1052 error = copyin(d->data, buf, fontsz); 1053 if (error) { 1054 free(buf, M_DEVBUF); 1055 return (error); 1056 } 1057 d->data = buf; 1058 error = 1059 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1060 free(buf, M_DEVBUF); 1061 #undef d 1062 return (error); 1063 1064 #if NWSKBD > 0 1065 #ifdef COMPAT_14 1066 case _O_WSDISPLAYIO_SETKEYBOARD: 1067 #define d ((struct wsdisplay_kbddata *)data) 1068 inp = sc->sc_input; 1069 if (inp == NULL) 1070 return (ENXIO); 1071 switch (d->op) { 1072 case _O_WSDISPLAY_KBD_ADD: 1073 if (d->idx == -1) { 1074 d->idx = wskbd_pickfree(); 1075 if (d->idx == -1) 1076 return (ENXIO); 1077 } 1078 wsmuxdata.type = WSMUX_KBD; 1079 wsmuxdata.idx = d->idx; 1080 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE, 1081 &wsmuxdata, flag, p)); 1082 case _O_WSDISPLAY_KBD_DEL: 1083 wsmuxdata.type = WSMUX_KBD; 1084 wsmuxdata.idx = d->idx; 1085 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE, 1086 &wsmuxdata, flag, p)); 1087 default: 1088 return (EINVAL); 1089 } 1090 #undef d 1091 #endif 1092 1093 case WSMUXIO_ADD_DEVICE: 1094 #define d ((struct wsmux_device *)data) 1095 if (d->idx == -1 && d->type == WSMUX_KBD) 1096 d->idx = wskbd_pickfree(); 1097 #undef d 1098 /* fall into */ 1099 case WSMUXIO_INJECTEVENT: 1100 case WSMUXIO_REMOVE_DEVICE: 1101 case WSMUXIO_LIST_DEVICES: 1102 inp = sc->sc_input; 1103 if (inp == NULL) 1104 return (ENXIO); 1105 return (wsevsrc_ioctl(inp, cmd, data, flag, p)); 1106 #endif /* NWSKBD > 0 */ 1107 1108 } 1109 return (EPASSTHROUGH); 1110 } 1111 1112 paddr_t 1113 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1114 { 1115 struct wsdisplay_softc *sc = 1116 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1117 struct wsscreen *scr; 1118 1119 if (ISWSDISPLAYCTL(dev)) 1120 return (-1); 1121 1122 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1123 1124 if (!(scr->scr_flags & SCR_GRAPHICS)) 1125 return (-1); 1126 1127 /* pass mmap to display */ 1128 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1129 } 1130 1131 void 1132 wsdisplaystart(struct tty *tp) 1133 { 1134 struct wsdisplay_softc *sc; 1135 struct wsscreen *scr; 1136 int s, n; 1137 u_char *buf; 1138 1139 s = spltty(); 1140 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1141 splx(s); 1142 return; 1143 } 1144 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1145 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1146 if (scr->scr_hold_screen) { 1147 tp->t_state |= TS_TIMEOUT; 1148 splx(s); 1149 return; 1150 } 1151 tp->t_state |= TS_BUSY; 1152 splx(s); 1153 1154 /* 1155 * Drain output from ring buffer. 1156 * The output will normally be in one contiguous chunk, but when the 1157 * ring wraps, it will be in two pieces.. one at the end of the ring, 1158 * the other at the start. For performance, rather than loop here, 1159 * we output one chunk, see if there's another one, and if so, output 1160 * it too. 1161 */ 1162 1163 n = ndqb(&tp->t_outq, 0); 1164 buf = tp->t_outq.c_cf; 1165 1166 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1167 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1168 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1169 buf, n, 0); 1170 } 1171 ndflush(&tp->t_outq, n); 1172 1173 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1174 buf = tp->t_outq.c_cf; 1175 1176 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1177 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1178 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1179 buf, n, 0); 1180 } 1181 ndflush(&tp->t_outq, n); 1182 } 1183 1184 s = spltty(); 1185 tp->t_state &= ~TS_BUSY; 1186 /* Come back if there's more to do */ 1187 if (tp->t_outq.c_cc) { 1188 tp->t_state |= TS_TIMEOUT; 1189 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1190 ttrstrt, tp); 1191 } 1192 if (tp->t_outq.c_cc <= tp->t_lowat) { 1193 if (tp->t_state&TS_ASLEEP) { 1194 tp->t_state &= ~TS_ASLEEP; 1195 wakeup(&tp->t_outq); 1196 } 1197 selwakeup(&tp->t_wsel); 1198 } 1199 splx(s); 1200 } 1201 1202 void 1203 wsdisplaystop(struct tty *tp, int flag) 1204 { 1205 int s; 1206 1207 s = spltty(); 1208 if (ISSET(tp->t_state, TS_BUSY)) 1209 if (!ISSET(tp->t_state, TS_TTSTOP)) 1210 SET(tp->t_state, TS_FLUSH); 1211 splx(s); 1212 } 1213 1214 /* Set line parameters. */ 1215 int 1216 wsdisplayparam(struct tty *tp, struct termios *t) 1217 { 1218 1219 tp->t_ispeed = t->c_ispeed; 1220 tp->t_ospeed = t->c_ospeed; 1221 tp->t_cflag = t->c_cflag; 1222 return 0; 1223 } 1224 1225 /* 1226 * Callbacks for the emulation code. 1227 */ 1228 void 1229 wsdisplay_emulbell(void *v) 1230 { 1231 struct wsscreen *scr = v; 1232 1233 if (scr == NULL) /* console, before real attach */ 1234 return; 1235 1236 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1237 return; 1238 1239 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1240 FWRITE, NULL); 1241 } 1242 1243 void 1244 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1245 { 1246 struct wsscreen *scr = v; 1247 struct tty *tp; 1248 1249 if (v == NULL) /* console, before real attach */ 1250 return; 1251 1252 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1253 return; 1254 if (!WSSCREEN_HAS_TTY(scr)) 1255 return; 1256 1257 tp = scr->scr_tty; 1258 while (count-- > 0) 1259 (*tp->t_linesw->l_rint)(*data++, tp); 1260 }; 1261 1262 /* 1263 * Calls from the keyboard interface. 1264 */ 1265 void 1266 wsdisplay_kbdinput(struct device *dev, keysym_t ks) 1267 { 1268 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1269 struct wsscreen *scr; 1270 char *dp; 1271 int count; 1272 struct tty *tp; 1273 1274 KASSERT(sc != NULL); 1275 1276 scr = sc->sc_focus; 1277 1278 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1279 return; 1280 1281 tp = scr->scr_tty; 1282 1283 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1284 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1285 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1286 count = (*scr->scr_dconf->wsemul->translate) 1287 (scr->scr_dconf->wsemulcookie, ks, &dp); 1288 while (count-- > 0) 1289 (*tp->t_linesw->l_rint)(*dp++, tp); 1290 } 1291 } 1292 1293 #if defined(WSDISPLAY_COMPAT_RAWKBD) 1294 int 1295 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1296 { 1297 #if NWSKBD > 0 1298 int s, raw, data, error; 1299 struct wsevsrc *inp; 1300 1301 s = spltty(); 1302 1303 raw = (scr ? scr->scr_rawkbd : 0); 1304 1305 if (scr != sc->sc_focus || 1306 sc->sc_rawkbd == raw) { 1307 splx(s); 1308 return (0); 1309 } 1310 1311 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1312 inp = sc->sc_input; 1313 if (inp == NULL) 1314 return (ENXIO); 1315 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0); 1316 if (!error) 1317 sc->sc_rawkbd = raw; 1318 splx(s); 1319 return (error); 1320 #else 1321 return (0); 1322 #endif 1323 } 1324 #endif 1325 1326 int 1327 wsdisplay_switch3(void *arg, int error, int waitok) 1328 { 1329 struct wsdisplay_softc *sc = arg; 1330 int no; 1331 struct wsscreen *scr; 1332 1333 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1334 printf("wsdisplay_switch3: not switching\n"); 1335 return (EINVAL); 1336 } 1337 1338 no = sc->sc_screenwanted; 1339 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1340 panic("wsdisplay_switch3: invalid screen %d", no); 1341 scr = sc->sc_scr[no]; 1342 if (!scr) { 1343 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1344 error = ENXIO; 1345 } 1346 1347 if (error) { 1348 /* try to recover, avoid recursion */ 1349 1350 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1351 printf("wsdisplay_switch3: giving up\n"); 1352 sc->sc_focus = 0; 1353 #ifdef WSDISPLAY_COMPAT_RAWKBD 1354 wsdisplay_update_rawkbd(sc, 0); 1355 #endif 1356 sc->sc_flags &= ~SC_SWITCHPENDING; 1357 return (error); 1358 } 1359 1360 sc->sc_screenwanted = sc->sc_oldscreen; 1361 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1362 return (wsdisplay_switch1(arg, 0, waitok)); 1363 } 1364 1365 sc->sc_flags &= ~SC_SWITCHPENDING; 1366 1367 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1368 wakeup(scr); 1369 return (error); 1370 } 1371 1372 int 1373 wsdisplay_switch2(void *arg, int error, int waitok) 1374 { 1375 struct wsdisplay_softc *sc = arg; 1376 int no; 1377 struct wsscreen *scr; 1378 1379 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1380 printf("wsdisplay_switch2: not switching\n"); 1381 return (EINVAL); 1382 } 1383 1384 no = sc->sc_screenwanted; 1385 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1386 panic("wsdisplay_switch2: invalid screen %d", no); 1387 scr = sc->sc_scr[no]; 1388 if (!scr) { 1389 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1390 error = ENXIO; 1391 } 1392 1393 if (error) { 1394 /* try to recover, avoid recursion */ 1395 1396 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1397 printf("wsdisplay_switch2: giving up\n"); 1398 sc->sc_focus = 0; 1399 sc->sc_flags &= ~SC_SWITCHPENDING; 1400 return (error); 1401 } 1402 1403 sc->sc_screenwanted = sc->sc_oldscreen; 1404 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1405 return (wsdisplay_switch1(arg, 0, waitok)); 1406 } 1407 1408 sc->sc_focusidx = no; 1409 sc->sc_focus = scr; 1410 1411 #ifdef WSDISPLAY_COMPAT_RAWKBD 1412 (void) wsdisplay_update_rawkbd(sc, scr); 1413 #endif 1414 /* keyboard map??? */ 1415 1416 #define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3) 1417 if (scr->scr_syncops) { 1418 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1419 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1420 if (error == EAGAIN) { 1421 /* switch will be done asynchronously */ 1422 return (0); 1423 } 1424 } 1425 1426 return (wsdisplay_switch3(sc, error, waitok)); 1427 } 1428 1429 int 1430 wsdisplay_switch1(void *arg, int error, int waitok) 1431 { 1432 struct wsdisplay_softc *sc = arg; 1433 int no; 1434 struct wsscreen *scr; 1435 1436 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1437 printf("wsdisplay_switch1: not switching\n"); 1438 return (EINVAL); 1439 } 1440 1441 no = sc->sc_screenwanted; 1442 if (no == WSDISPLAY_NULLSCREEN) { 1443 sc->sc_flags &= ~SC_SWITCHPENDING; 1444 if (!error) { 1445 sc->sc_focus = 0; 1446 } 1447 wakeup(sc); 1448 return (error); 1449 } 1450 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1451 panic("wsdisplay_switch1: invalid screen %d", no); 1452 scr = sc->sc_scr[no]; 1453 if (!scr) { 1454 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1455 error = ENXIO; 1456 } 1457 1458 if (error) { 1459 sc->sc_flags &= ~SC_SWITCHPENDING; 1460 return (error); 1461 } 1462 1463 #define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2) 1464 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1465 scr->scr_dconf->emulcookie, 1466 waitok, 1467 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1468 if (error == EAGAIN) { 1469 /* switch will be done asynchronously */ 1470 return (0); 1471 } 1472 1473 return (wsdisplay_switch2(sc, error, waitok)); 1474 } 1475 1476 int 1477 wsdisplay_switch(struct device *dev, int no, int waitok) 1478 { 1479 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1480 int s, res = 0; 1481 struct wsscreen *scr; 1482 1483 if (no != WSDISPLAY_NULLSCREEN && 1484 (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])) 1485 return (ENXIO); 1486 1487 s = spltty(); 1488 1489 if ((sc->sc_focus && no == sc->sc_focusidx) || 1490 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1491 splx(s); 1492 return (0); 1493 } 1494 1495 if (sc->sc_flags & SC_SWITCHPENDING) { 1496 splx(s); 1497 return (EBUSY); 1498 } 1499 1500 sc->sc_flags |= SC_SWITCHPENDING; 1501 sc->sc_screenwanted = no; 1502 1503 splx(s); 1504 1505 scr = sc->sc_focus; 1506 if (!scr) { 1507 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1508 return (wsdisplay_switch1(sc, 0, waitok)); 1509 } else 1510 sc->sc_oldscreen = sc->sc_focusidx; 1511 1512 #define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1) 1513 if (scr->scr_syncops) { 1514 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1515 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1516 if (res == EAGAIN) { 1517 /* switch will be done asynchronously */ 1518 return (0); 1519 } 1520 } else if (scr->scr_flags & SCR_GRAPHICS) { 1521 /* no way to save state */ 1522 res = EBUSY; 1523 } 1524 1525 return (wsdisplay_switch1(sc, res, waitok)); 1526 } 1527 1528 void 1529 wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op) 1530 { 1531 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1532 struct wsscreen *scr; 1533 1534 KASSERT(sc != NULL); 1535 scr = sc->sc_focus; 1536 1537 if (!scr) 1538 return; 1539 1540 switch (op) { 1541 case WSDISPLAY_RESETEMUL: 1542 if (!WSSCREEN_HAS_EMULATOR(scr)) 1543 break; 1544 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1545 WSEMUL_RESET); 1546 break; 1547 case WSDISPLAY_RESETCLOSE: 1548 wsdisplay_closescreen(sc, scr); 1549 break; 1550 } 1551 } 1552 1553 /* 1554 * Interface for (external) VT switch / process synchronization code 1555 */ 1556 int 1557 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1558 void *cookie) 1559 { 1560 if (scr->scr_syncops) { 1561 /* 1562 * The screen is already claimed. 1563 * Check if the owner is still alive. 1564 */ 1565 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1566 return (EBUSY); 1567 } 1568 scr->scr_syncops = ops; 1569 scr->scr_synccookie = cookie; 1570 return (0); 1571 } 1572 1573 int 1574 wsscreen_detach_sync(struct wsscreen *scr) 1575 { 1576 if (!scr->scr_syncops) 1577 return (EINVAL); 1578 scr->scr_syncops = 0; 1579 return (0); 1580 } 1581 1582 int 1583 wsscreen_lookup_sync(struct wsscreen *scr, 1584 const struct wscons_syncops *ops, /* used as ID */ 1585 void **cookiep) 1586 { 1587 if (!scr->scr_syncops || ops != scr->scr_syncops) 1588 return (EINVAL); 1589 *cookiep = scr->scr_synccookie; 1590 return (0); 1591 } 1592 1593 /* 1594 * Interface to virtual screen stuff 1595 */ 1596 int 1597 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 1598 { 1599 return (WSDISPLAY_MAXSCREEN - 1); 1600 } 1601 1602 int 1603 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 1604 { 1605 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1606 return (EINVAL); 1607 if (!sc->sc_scr[idx]) 1608 return (ENXIO); 1609 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1610 } 1611 1612 int 1613 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 1614 { 1615 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1616 } 1617 1618 int 1619 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 1620 { 1621 struct wsscreen *scr; 1622 int s, res = 0; 1623 1624 if (no == WSDISPLAY_NULLSCREEN) { 1625 s = spltty(); 1626 while (sc->sc_focus && res == 0) { 1627 res = tsleep(sc, PCATCH, "wswait", 0); 1628 } 1629 splx(s); 1630 return (res); 1631 } 1632 1633 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1634 return (ENXIO); 1635 scr = sc->sc_scr[no]; 1636 if (!scr) 1637 return (ENXIO); 1638 1639 s = spltty(); 1640 if (scr != sc->sc_focus) { 1641 scr->scr_flags |= SCR_WAITACTIVE; 1642 res = tsleep(scr, PCATCH, "wswait", 0); 1643 if (scr != sc->sc_scr[no]) 1644 res = ENXIO; /* disappeared in the meantime */ 1645 else 1646 scr->scr_flags &= ~SCR_WAITACTIVE; 1647 } 1648 splx(s); 1649 return (res); 1650 } 1651 1652 void 1653 wsdisplay_kbdholdscreen(struct device *dev, int hold) 1654 { 1655 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1656 struct wsscreen *scr; 1657 1658 scr = sc->sc_focus; 1659 1660 if (hold) 1661 scr->scr_hold_screen = 1; 1662 else { 1663 scr->scr_hold_screen = 0; 1664 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1665 ttrstrt, scr->scr_tty); /* "immediate" */ 1666 } 1667 } 1668 1669 #if NWSKBD > 0 1670 void 1671 wsdisplay_set_console_kbd(struct wsevsrc *src) 1672 { 1673 if (wsdisplay_console_device == NULL) { 1674 src->me_dispdv = NULL; 1675 return; 1676 } 1677 #if NWSMUX > 0 1678 if (wsmux_attach_sc((struct wsmux_softc *) 1679 wsdisplay_console_device->sc_input, src)) { 1680 src->me_dispdv = NULL; 1681 return; 1682 } 1683 #else 1684 wsdisplay_console_device->sc_input = src; 1685 #endif 1686 src->me_dispdv = &wsdisplay_console_device->sc_dv; 1687 } 1688 #endif /* NWSKBD > 0 */ 1689 1690 /* 1691 * Console interface. 1692 */ 1693 void 1694 wsdisplay_cnputc(dev_t dev, int i) 1695 { 1696 struct wsscreen_internal *dc; 1697 char c = i; 1698 1699 if (!wsdisplay_console_initted) 1700 return; 1701 1702 if (wsdisplay_console_device != NULL && 1703 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1704 return; 1705 1706 dc = &wsdisplay_console_conf; 1707 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1708 } 1709 1710 static int 1711 wsdisplay_getc_dummy(dev_t dev) 1712 { 1713 /* panic? */ 1714 return (0); 1715 } 1716 1717 static void 1718 wsdisplay_pollc(dev_t dev, int on) 1719 { 1720 1721 wsdisplay_cons_pollmode = on; 1722 1723 /* notify to fb drivers */ 1724 if (wsdisplay_console_device != NULL && 1725 wsdisplay_console_device->sc_accessops->pollc != NULL) 1726 (*wsdisplay_console_device->sc_accessops->pollc) 1727 (wsdisplay_console_device->sc_accesscookie, on); 1728 1729 /* notify to kbd drivers */ 1730 if (wsdisplay_cons_kbd_pollc) 1731 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 1732 } 1733 1734 void 1735 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 1736 void (*bell)(dev_t, u_int, u_int, u_int)) 1737 { 1738 wsdisplay_cons.cn_getc = get; 1739 wsdisplay_cons.cn_bell = bell; 1740 wsdisplay_cons_kbd_pollc = poll; 1741 } 1742 1743 void 1744 wsdisplay_unset_cons_kbd(void) 1745 { 1746 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1747 wsdisplay_cons.cn_bell = NULL; 1748 wsdisplay_cons_kbd_pollc = 0; 1749 } 1750 1751 /* 1752 * Switch the console display to it's first screen. 1753 */ 1754 void 1755 wsdisplay_switchtoconsole(void) 1756 { 1757 struct wsdisplay_softc *sc; 1758 struct wsscreen *scr; 1759 1760 if (wsdisplay_console_device != NULL) { 1761 sc = wsdisplay_console_device; 1762 scr = sc->sc_scr[0]; 1763 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1764 scr->scr_dconf->emulcookie, 1765 0, NULL, NULL); 1766 } 1767 } 1768 1769 /* 1770 * Switch the console at shutdown. 1771 */ 1772 static void 1773 wsdisplay_shutdownhook(void *arg) 1774 { 1775 1776 wsdisplay_switchtoconsole(); 1777 } 1778