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