1 /* $NetBSD: wsdisplay.c,v 1.52 2001/08/05 11:26:52 jdolecek 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.52 2001/08/05 11:26:52 jdolecek 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 int 853 wsdisplaypoll(dev, events, p) 854 dev_t dev; 855 int events; 856 struct proc *p; 857 { 858 struct wsdisplay_softc *sc; 859 struct tty *tp; 860 struct wsscreen *scr; 861 862 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 863 864 if (ISWSDISPLAYCTL(dev)) 865 return (0); 866 867 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 868 869 if (!WSSCREEN_HAS_TTY(scr)) 870 return (ENODEV); 871 872 tp = scr->scr_tty; 873 return ((*tp->t_linesw->l_poll)(tp, events, p)); 874 } 875 876 struct tty * 877 wsdisplaytty(dev) 878 dev_t dev; 879 { 880 struct wsdisplay_softc *sc; 881 struct wsscreen *scr; 882 883 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 884 885 if (ISWSDISPLAYCTL(dev)) 886 panic("wsdisplaytty() on ctl device"); 887 888 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 889 890 return (scr->scr_tty); 891 } 892 893 int 894 wsdisplayioctl(dev, cmd, data, flag, p) 895 dev_t dev; 896 u_long cmd; 897 caddr_t data; 898 int flag; 899 struct proc *p; 900 { 901 struct wsdisplay_softc *sc; 902 struct tty *tp; 903 int error; 904 struct wsscreen *scr; 905 906 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 907 908 #ifdef WSDISPLAY_COMPAT_USL 909 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 910 if (error >= 0) 911 return (error); 912 #endif 913 914 if (ISWSDISPLAYCTL(dev)) 915 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 916 917 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 918 919 if (WSSCREEN_HAS_TTY(scr)) { 920 tp = scr->scr_tty; 921 922 /* printf("disc\n"); */ 923 /* do the line discipline ioctls first */ 924 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 925 if (error >= 0) 926 return (error); 927 928 /* printf("tty\n"); */ 929 /* then the tty ioctls */ 930 error = ttioctl(tp, cmd, data, flag, p); 931 if (error >= 0) 932 return (error); 933 } 934 935 #ifdef WSDISPLAY_COMPAT_USL 936 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 937 if (error >= 0) 938 return (error); 939 #endif 940 941 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p); 942 return (error != -1 ? error : ENOTTY); 943 } 944 945 int 946 wsdisplay_param(dev, cmd, dp) 947 struct device *dev; 948 u_long cmd; 949 struct wsdisplay_param *dp; 950 { 951 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 952 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 953 (caddr_t)dp, 0, NULL)); 954 } 955 956 int 957 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p) 958 struct wsdisplay_softc *sc; 959 struct wsscreen *scr; 960 u_long cmd; 961 caddr_t data; 962 int flag; 963 struct proc *p; 964 { 965 int error; 966 char namebuf[16]; 967 struct wsdisplay_font fd; 968 969 #if NWSKBD > 0 970 #ifdef WSDISPLAY_COMPAT_RAWKBD 971 switch (cmd) { 972 case WSKBDIO_SETMODE: 973 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 974 return (wsdisplay_update_rawkbd(sc, scr)); 975 case WSKBDIO_GETMODE: 976 *(int *)data = (scr->scr_rawkbd ? 977 WSKBD_RAW : WSKBD_TRANSLATED); 978 return (0); 979 } 980 #endif 981 error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, cmd, data, flag, p); 982 if (error >= 0) 983 return (error); 984 #endif /* NWSKBD > 0 */ 985 986 switch (cmd) { 987 case WSDISPLAYIO_GMODE: 988 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 989 WSDISPLAYIO_MODE_MAPPED : 990 WSDISPLAYIO_MODE_EMUL); 991 return (0); 992 993 case WSDISPLAYIO_SMODE: 994 #define d (*(int *)data) 995 if (d != WSDISPLAYIO_MODE_EMUL && 996 d != WSDISPLAYIO_MODE_MAPPED) 997 return (EINVAL); 998 999 if (WSSCREEN_HAS_EMULATOR(scr)) { 1000 scr->scr_flags &= ~SCR_GRAPHICS; 1001 if (d == WSDISPLAYIO_MODE_MAPPED) 1002 scr->scr_flags |= SCR_GRAPHICS; 1003 } else if (d == WSDISPLAYIO_MODE_EMUL) 1004 return (EINVAL); 1005 1006 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1007 flag, p); 1008 1009 return (0); 1010 #undef d 1011 1012 case WSDISPLAYIO_USEFONT: 1013 #define d ((struct wsdisplay_usefontdata *)data) 1014 if (!sc->sc_accessops->load_font) 1015 return (EINVAL); 1016 if (d->name) { 1017 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 1018 if (error) 1019 return (error); 1020 fd.name = namebuf; 1021 } else 1022 fd.name = 0; 1023 fd.data = 0; 1024 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 1025 scr->scr_dconf->emulcookie, &fd); 1026 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 1027 (*scr->scr_dconf->wsemul->reset) 1028 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 1029 return (error); 1030 #undef d 1031 } 1032 1033 /* check ioctls for display */ 1034 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1035 flag, p)); 1036 } 1037 1038 int 1039 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p) 1040 struct wsdisplay_softc *sc; 1041 u_long cmd; 1042 caddr_t data; 1043 int flag; 1044 struct proc *p; 1045 { 1046 int error; 1047 char *type, typebuf[16], *emul, emulbuf[16]; 1048 void *buf; 1049 u_int fontsz; 1050 #if defined(COMPAT_14) && NWSKBD > 0 1051 struct wsmux_device wsmuxdata; 1052 #endif 1053 1054 switch (cmd) { 1055 case WSDISPLAYIO_ADDSCREEN: 1056 #define d ((struct wsdisplay_addscreendata *)data) 1057 if (d->screentype) { 1058 error = copyinstr(d->screentype, typebuf, 1059 sizeof(typebuf), 0); 1060 if (error) 1061 return (error); 1062 type = typebuf; 1063 } else 1064 type = 0; 1065 if (d->emul) { 1066 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1067 if (error) 1068 return (error); 1069 emul = emulbuf; 1070 } else 1071 emul = 0; 1072 1073 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1074 wsdisplay_addscreen_print(sc, d->idx, 0); 1075 return (error); 1076 #undef d 1077 case WSDISPLAYIO_DELSCREEN: 1078 #define d ((struct wsdisplay_delscreendata *)data) 1079 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1080 #undef d 1081 case WSDISPLAYIO_LDFONT: 1082 #define d ((struct wsdisplay_font *)data) 1083 if (!sc->sc_accessops->load_font) 1084 return (EINVAL); 1085 if (d->name) { 1086 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1087 if (error) 1088 return (error); 1089 d->name = typebuf; 1090 } else 1091 d->name = "loaded"; /* ??? */ 1092 fontsz = d->fontheight * d->stride * d->numchars; 1093 if (fontsz > WSDISPLAY_MAXFONTSZ) 1094 return (EINVAL); 1095 1096 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1097 error = copyin(d->data, buf, fontsz); 1098 if (error) { 1099 free(buf, M_DEVBUF); 1100 return (error); 1101 } 1102 d->data = buf; 1103 error = 1104 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1105 free(buf, M_DEVBUF); 1106 #undef d 1107 return (error); 1108 1109 #if NWSKBD > 0 1110 #ifdef COMPAT_14 1111 case _O_WSDISPLAYIO_SETKEYBOARD: 1112 #define d ((struct wsdisplay_kbddata *)data) 1113 switch (d->op) { 1114 case _O_WSDISPLAY_KBD_ADD: 1115 if (d->idx == -1) { 1116 d->idx = wskbd_pickfree(); 1117 if (d->idx == -1) 1118 return (ENXIO); 1119 } 1120 wsmuxdata.type = WSMUX_KBD; 1121 wsmuxdata.idx = d->idx; 1122 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, 1123 WSMUX_ADD_DEVICE, 1124 (caddr_t)&wsmuxdata, flag, p)); 1125 case _O_WSDISPLAY_KBD_DEL: 1126 wsmuxdata.type = WSMUX_KBD; 1127 wsmuxdata.idx = d->idx; 1128 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, 1129 WSMUX_REMOVE_DEVICE, 1130 (caddr_t)&wsmuxdata, flag, p)); 1131 default: 1132 return (EINVAL); 1133 } 1134 #undef d 1135 #endif 1136 1137 case WSMUX_ADD_DEVICE: 1138 #define d ((struct wsmux_device *)data) 1139 if (d->idx == -1 && d->type == WSMUX_KBD) 1140 d->idx = wskbd_pickfree(); 1141 #undef d 1142 /* fall into */ 1143 case WSMUX_INJECTEVENT: 1144 case WSMUX_REMOVE_DEVICE: 1145 case WSMUX_LIST_DEVICES: 1146 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, cmd, data, flag,p)); 1147 #endif /* NWSKBD > 0 */ 1148 1149 } 1150 return (EINVAL); 1151 } 1152 1153 paddr_t 1154 wsdisplaymmap(dev, offset, prot) 1155 dev_t dev; 1156 off_t offset; 1157 int prot; 1158 { 1159 struct wsdisplay_softc *sc = 1160 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1161 struct wsscreen *scr; 1162 1163 if (ISWSDISPLAYCTL(dev)) 1164 return (-1); 1165 1166 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1167 1168 if (!(scr->scr_flags & SCR_GRAPHICS)) 1169 return (-1); 1170 1171 /* pass mmap to display */ 1172 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1173 } 1174 1175 void 1176 wsdisplaystart(tp) 1177 struct tty *tp; 1178 { 1179 struct wsdisplay_softc *sc; 1180 struct wsscreen *scr; 1181 int s, n; 1182 u_char *buf; 1183 1184 s = spltty(); 1185 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1186 splx(s); 1187 return; 1188 } 1189 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1190 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1191 if (scr->scr_hold_screen) { 1192 tp->t_state |= TS_TIMEOUT; 1193 splx(s); 1194 return; 1195 } 1196 tp->t_state |= TS_BUSY; 1197 splx(s); 1198 1199 /* 1200 * Drain output from ring buffer. 1201 * The output will normally be in one contiguous chunk, but when the 1202 * ring wraps, it will be in two pieces.. one at the end of the ring, 1203 * the other at the start. For performance, rather than loop here, 1204 * we output one chunk, see if there's another one, and if so, output 1205 * it too. 1206 */ 1207 1208 n = ndqb(&tp->t_outq, 0); 1209 buf = tp->t_outq.c_cf; 1210 1211 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1212 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1213 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1214 buf, n, 0); 1215 } 1216 ndflush(&tp->t_outq, n); 1217 1218 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1219 buf = tp->t_outq.c_cf; 1220 1221 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1222 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1223 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1224 buf, n, 0); 1225 } 1226 ndflush(&tp->t_outq, n); 1227 } 1228 1229 s = spltty(); 1230 tp->t_state &= ~TS_BUSY; 1231 /* Come back if there's more to do */ 1232 if (tp->t_outq.c_cc) { 1233 tp->t_state |= TS_TIMEOUT; 1234 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1235 ttrstrt, tp); 1236 } 1237 if (tp->t_outq.c_cc <= tp->t_lowat) { 1238 if (tp->t_state&TS_ASLEEP) { 1239 tp->t_state &= ~TS_ASLEEP; 1240 wakeup((caddr_t)&tp->t_outq); 1241 } 1242 selwakeup(&tp->t_wsel); 1243 } 1244 splx(s); 1245 } 1246 1247 void 1248 wsdisplaystop(tp, flag) 1249 struct tty *tp; 1250 int flag; 1251 { 1252 int s; 1253 1254 s = spltty(); 1255 if (ISSET(tp->t_state, TS_BUSY)) 1256 if (!ISSET(tp->t_state, TS_TTSTOP)) 1257 SET(tp->t_state, TS_FLUSH); 1258 splx(s); 1259 } 1260 1261 /* Set line parameters. */ 1262 int 1263 wsdisplayparam(tp, t) 1264 struct tty *tp; 1265 struct termios *t; 1266 { 1267 1268 tp->t_ispeed = t->c_ispeed; 1269 tp->t_ospeed = t->c_ospeed; 1270 tp->t_cflag = t->c_cflag; 1271 return 0; 1272 } 1273 1274 /* 1275 * Callbacks for the emulation code. 1276 */ 1277 void 1278 wsdisplay_emulbell(v) 1279 void *v; 1280 { 1281 struct wsscreen *scr = v; 1282 1283 if (scr == NULL) /* console, before real attach */ 1284 return; 1285 1286 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1287 return; 1288 1289 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1290 FWRITE, NULL); 1291 } 1292 1293 void 1294 wsdisplay_emulinput(v, data, count) 1295 void *v; 1296 const u_char *data; 1297 u_int count; 1298 { 1299 struct wsscreen *scr = v; 1300 struct tty *tp; 1301 1302 if (v == NULL) /* console, before real attach */ 1303 return; 1304 1305 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1306 return; 1307 if (!WSSCREEN_HAS_TTY(scr)) 1308 return; 1309 1310 tp = scr->scr_tty; 1311 while (count-- > 0) 1312 (*tp->t_linesw->l_rint)(*data++, tp); 1313 }; 1314 1315 /* 1316 * Calls from the keyboard interface. 1317 */ 1318 void 1319 wsdisplay_kbdinput(dev, ks) 1320 struct device *dev; 1321 keysym_t ks; 1322 { 1323 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1324 struct wsscreen *scr; 1325 char *dp; 1326 int count; 1327 struct tty *tp; 1328 1329 KASSERT(sc != NULL); 1330 1331 scr = sc->sc_focus; 1332 1333 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1334 return; 1335 1336 tp = scr->scr_tty; 1337 1338 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1339 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1340 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1341 count = (*scr->scr_dconf->wsemul->translate) 1342 (scr->scr_dconf->wsemulcookie, ks, &dp); 1343 while (count-- > 0) 1344 (*tp->t_linesw->l_rint)(*dp++, tp); 1345 } 1346 } 1347 1348 #ifdef WSDISPLAY_COMPAT_RAWKBD 1349 int 1350 wsdisplay_update_rawkbd(sc, scr) 1351 struct wsdisplay_softc *sc; 1352 struct wsscreen *scr; 1353 { 1354 int s, raw, data, error; 1355 s = spltty(); 1356 1357 raw = (scr ? scr->scr_rawkbd : 0); 1358 1359 if (scr != sc->sc_focus || 1360 sc->sc_rawkbd == raw) { 1361 splx(s); 1362 return (0); 1363 } 1364 1365 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1366 error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, WSKBDIO_SETMODE, 1367 (caddr_t)&data, 0, 0); 1368 if (!error) 1369 sc->sc_rawkbd = raw; 1370 splx(s); 1371 return (error); 1372 } 1373 #endif 1374 1375 int 1376 wsdisplay_switch3(arg, error, waitok) 1377 void *arg; 1378 int error, waitok; 1379 { 1380 struct wsdisplay_softc *sc = arg; 1381 int no; 1382 struct wsscreen *scr; 1383 1384 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1385 printf("wsdisplay_switch3: not switching\n"); 1386 return (EINVAL); 1387 } 1388 1389 no = sc->sc_screenwanted; 1390 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1391 panic("wsdisplay_switch3: invalid screen %d", no); 1392 scr = sc->sc_scr[no]; 1393 if (!scr) { 1394 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1395 error = ENXIO; 1396 } 1397 1398 if (error) { 1399 /* try to recover, avoid recursion */ 1400 1401 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1402 printf("wsdisplay_switch3: giving up\n"); 1403 sc->sc_focus = 0; 1404 #ifdef WSDISPLAY_COMPAT_RAWKBD 1405 wsdisplay_update_rawkbd(sc, 0); 1406 #endif 1407 sc->sc_flags &= ~SC_SWITCHPENDING; 1408 return (error); 1409 } 1410 1411 sc->sc_screenwanted = sc->sc_oldscreen; 1412 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1413 return (wsdisplay_switch1(arg, 0, waitok)); 1414 } 1415 1416 sc->sc_flags &= ~SC_SWITCHPENDING; 1417 1418 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1419 wakeup(scr); 1420 return (error); 1421 } 1422 1423 int 1424 wsdisplay_switch2(arg, error, waitok) 1425 void *arg; 1426 int error, waitok; 1427 { 1428 struct wsdisplay_softc *sc = arg; 1429 int no; 1430 struct wsscreen *scr; 1431 1432 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1433 printf("wsdisplay_switch2: not switching\n"); 1434 return (EINVAL); 1435 } 1436 1437 no = sc->sc_screenwanted; 1438 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1439 panic("wsdisplay_switch2: invalid screen %d", no); 1440 scr = sc->sc_scr[no]; 1441 if (!scr) { 1442 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1443 error = ENXIO; 1444 } 1445 1446 if (error) { 1447 /* try to recover, avoid recursion */ 1448 1449 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1450 printf("wsdisplay_switch2: giving up\n"); 1451 sc->sc_focus = 0; 1452 sc->sc_flags &= ~SC_SWITCHPENDING; 1453 return (error); 1454 } 1455 1456 sc->sc_screenwanted = sc->sc_oldscreen; 1457 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1458 return (wsdisplay_switch1(arg, 0, waitok)); 1459 } 1460 1461 sc->sc_focusidx = no; 1462 sc->sc_focus = scr; 1463 1464 #ifdef WSDISPLAY_COMPAT_RAWKBD 1465 (void) wsdisplay_update_rawkbd(sc, scr); 1466 #endif 1467 /* keyboard map??? */ 1468 1469 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3) 1470 if (scr->scr_syncops) { 1471 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1472 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1473 if (error == EAGAIN) { 1474 /* switch will be done asynchronously */ 1475 return (0); 1476 } 1477 } 1478 1479 return (wsdisplay_switch3(sc, error, waitok)); 1480 } 1481 1482 int 1483 wsdisplay_switch1(arg, error, waitok) 1484 void *arg; 1485 int error, waitok; 1486 { 1487 struct wsdisplay_softc *sc = arg; 1488 int no; 1489 struct wsscreen *scr; 1490 1491 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1492 printf("wsdisplay_switch1: not switching\n"); 1493 return (EINVAL); 1494 } 1495 1496 no = sc->sc_screenwanted; 1497 if (no == WSDISPLAY_NULLSCREEN) { 1498 sc->sc_flags &= ~SC_SWITCHPENDING; 1499 if (!error) { 1500 sc->sc_focus = 0; 1501 } 1502 wakeup(sc); 1503 return (error); 1504 } 1505 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1506 panic("wsdisplay_switch1: invalid screen %d", no); 1507 scr = sc->sc_scr[no]; 1508 if (!scr) { 1509 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1510 error = ENXIO; 1511 } 1512 1513 if (error) { 1514 sc->sc_flags &= ~SC_SWITCHPENDING; 1515 return (error); 1516 } 1517 1518 #define wsswitch_cb2 ((void (*) __P((void *, int, int)))wsdisplay_switch2) 1519 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1520 scr->scr_dconf->emulcookie, 1521 waitok, 1522 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1523 if (error == EAGAIN) { 1524 /* switch will be done asynchronously */ 1525 return (0); 1526 } 1527 1528 return (wsdisplay_switch2(sc, error, waitok)); 1529 } 1530 1531 int 1532 wsdisplay_switch(dev, no, waitok) 1533 struct device *dev; 1534 int no, waitok; 1535 { 1536 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1537 int s, res = 0; 1538 struct wsscreen *scr; 1539 1540 if (no != WSDISPLAY_NULLSCREEN && 1541 (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])) 1542 return (ENXIO); 1543 1544 s = spltty(); 1545 1546 if ((sc->sc_focus && no == sc->sc_focusidx) || 1547 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1548 splx(s); 1549 return (0); 1550 } 1551 1552 if (sc->sc_flags & SC_SWITCHPENDING) { 1553 splx(s); 1554 return (EBUSY); 1555 } 1556 1557 sc->sc_flags |= SC_SWITCHPENDING; 1558 sc->sc_screenwanted = no; 1559 1560 splx(s); 1561 1562 scr = sc->sc_focus; 1563 if (!scr) { 1564 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1565 return (wsdisplay_switch1(sc, 0, waitok)); 1566 } else 1567 sc->sc_oldscreen = sc->sc_focusidx; 1568 1569 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1) 1570 if (scr->scr_syncops) { 1571 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1572 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1573 if (res == EAGAIN) { 1574 /* switch will be done asynchronously */ 1575 return (0); 1576 } 1577 } else if (scr->scr_flags & SCR_GRAPHICS) { 1578 /* no way to save state */ 1579 res = EBUSY; 1580 } 1581 1582 return (wsdisplay_switch1(sc, res, waitok)); 1583 } 1584 1585 void 1586 wsdisplay_reset(dev, op) 1587 struct device *dev; 1588 enum wsdisplay_resetops op; 1589 { 1590 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1591 struct wsscreen *scr; 1592 1593 KASSERT(sc != NULL); 1594 scr = sc->sc_focus; 1595 1596 if (!scr) 1597 return; 1598 1599 switch (op) { 1600 case WSDISPLAY_RESETEMUL: 1601 if (!WSSCREEN_HAS_EMULATOR(scr)) 1602 break; 1603 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1604 WSEMUL_RESET); 1605 break; 1606 case WSDISPLAY_RESETCLOSE: 1607 wsdisplay_closescreen(sc, scr); 1608 break; 1609 } 1610 } 1611 1612 /* 1613 * Interface for (external) VT switch / process synchronization code 1614 */ 1615 int 1616 wsscreen_attach_sync(scr, ops, cookie) 1617 struct wsscreen *scr; 1618 const struct wscons_syncops *ops; 1619 void *cookie; 1620 { 1621 if (scr->scr_syncops) { 1622 /* 1623 * The screen is already claimed. 1624 * Check if the owner is still alive. 1625 */ 1626 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1627 return (EBUSY); 1628 } 1629 scr->scr_syncops = ops; 1630 scr->scr_synccookie = cookie; 1631 return (0); 1632 } 1633 1634 int 1635 wsscreen_detach_sync(scr) 1636 struct wsscreen *scr; 1637 { 1638 if (!scr->scr_syncops) 1639 return (EINVAL); 1640 scr->scr_syncops = 0; 1641 return (0); 1642 } 1643 1644 int 1645 wsscreen_lookup_sync(scr, ops, cookiep) 1646 struct wsscreen *scr; 1647 const struct wscons_syncops *ops; /* used as ID */ 1648 void **cookiep; 1649 { 1650 if (!scr->scr_syncops || ops != scr->scr_syncops) 1651 return (EINVAL); 1652 *cookiep = scr->scr_synccookie; 1653 return (0); 1654 } 1655 1656 /* 1657 * Interface to virtual screen stuff 1658 */ 1659 int 1660 wsdisplay_maxscreenidx(sc) 1661 struct wsdisplay_softc *sc; 1662 { 1663 return (WSDISPLAY_MAXSCREEN - 1); 1664 } 1665 1666 int 1667 wsdisplay_screenstate(sc, idx) 1668 struct wsdisplay_softc *sc; 1669 int idx; 1670 { 1671 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1672 return (EINVAL); 1673 if (!sc->sc_scr[idx]) 1674 return (ENXIO); 1675 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1676 } 1677 1678 int 1679 wsdisplay_getactivescreen(sc) 1680 struct wsdisplay_softc *sc; 1681 { 1682 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1683 } 1684 1685 int 1686 wsscreen_switchwait(sc, no) 1687 struct wsdisplay_softc *sc; 1688 int no; 1689 { 1690 struct wsscreen *scr; 1691 int s, res = 0; 1692 1693 if (no == WSDISPLAY_NULLSCREEN) { 1694 s = spltty(); 1695 while (sc->sc_focus && res == 0) { 1696 res = tsleep(sc, PCATCH, "wswait", 0); 1697 } 1698 splx(s); 1699 return (res); 1700 } 1701 1702 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1703 return (ENXIO); 1704 scr = sc->sc_scr[no]; 1705 if (!scr) 1706 return (ENXIO); 1707 1708 s = spltty(); 1709 if (scr != sc->sc_focus) { 1710 scr->scr_flags |= SCR_WAITACTIVE; 1711 res = tsleep(scr, PCATCH, "wswait", 0); 1712 if (scr != sc->sc_scr[no]) 1713 res = ENXIO; /* disappeared in the meantime */ 1714 else 1715 scr->scr_flags &= ~SCR_WAITACTIVE; 1716 } 1717 splx(s); 1718 return (res); 1719 } 1720 1721 void 1722 wsdisplay_kbdholdscreen(dev, hold) 1723 struct device *dev; 1724 int hold; 1725 { 1726 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1727 struct wsscreen *scr; 1728 1729 scr = sc->sc_focus; 1730 1731 if (hold) 1732 scr->scr_hold_screen = 1; 1733 else { 1734 scr->scr_hold_screen = 0; 1735 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1736 ttrstrt, scr->scr_tty); /* "immediate" */ 1737 } 1738 } 1739 1740 #if NWSKBD > 0 1741 struct device * 1742 wsdisplay_set_console_kbd(kbddv) 1743 struct device *kbddv; 1744 { 1745 if (!wsdisplay_console_device) 1746 return (0); 1747 if (wskbd_add_mux(kbddv->dv_unit, wsdisplay_console_device->sc_muxdv)) 1748 return (0); 1749 return (&wsdisplay_console_device->sc_dv); 1750 } 1751 #endif /* NWSKBD > 0 */ 1752 1753 /* 1754 * Console interface. 1755 */ 1756 void 1757 wsdisplay_cnputc(dev, i) 1758 dev_t dev; 1759 int i; 1760 { 1761 struct wsscreen_internal *dc; 1762 char c = i; 1763 1764 if (!wsdisplay_console_initted) 1765 return; 1766 1767 if (wsdisplay_console_device != NULL && 1768 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1769 return; 1770 1771 dc = &wsdisplay_console_conf; 1772 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1773 } 1774 1775 static int 1776 wsdisplay_getc_dummy(dev) 1777 dev_t dev; 1778 { 1779 /* panic? */ 1780 return (0); 1781 } 1782 1783 static void 1784 wsdisplay_pollc(dev, on) 1785 dev_t dev; 1786 int on; 1787 { 1788 1789 wsdisplay_cons_pollmode = on; 1790 1791 /* notify to fb drivers */ 1792 if (wsdisplay_console_device != NULL && 1793 wsdisplay_console_device->sc_accessops->pollc != NULL) 1794 (*wsdisplay_console_device->sc_accessops->pollc) 1795 (wsdisplay_console_device->sc_accesscookie, on); 1796 1797 /* notify to kbd drivers */ 1798 if (wsdisplay_cons_kbd_pollc) 1799 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 1800 } 1801 1802 void 1803 wsdisplay_set_cons_kbd(get, poll, bell) 1804 int (*get) __P((dev_t)); 1805 void (*poll) __P((dev_t, int)); 1806 void (*bell) __P((dev_t, u_int, u_int, u_int)); 1807 { 1808 wsdisplay_cons.cn_getc = get; 1809 wsdisplay_cons.cn_bell = bell; 1810 wsdisplay_cons_kbd_pollc = poll; 1811 } 1812 1813 void 1814 wsdisplay_unset_cons_kbd() 1815 { 1816 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1817 wsdisplay_cons.cn_bell = NULL; 1818 wsdisplay_cons_kbd_pollc = 0; 1819 } 1820 1821 /* 1822 * Switch the console display to it's first screen. 1823 */ 1824 void 1825 wsdisplay_switchtoconsole() 1826 { 1827 struct wsdisplay_softc *sc; 1828 struct wsscreen *scr; 1829 1830 if (wsdisplay_console_device != NULL) { 1831 sc = wsdisplay_console_device; 1832 scr = sc->sc_scr[0]; 1833 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1834 scr->scr_dconf->emulcookie, 1835 0, NULL, NULL); 1836 } 1837 } 1838 1839 /* 1840 * Switch the console at shutdown. 1841 */ 1842 static void 1843 wsdisplay_shutdownhook(arg) 1844 void *arg; 1845 { 1846 1847 wsdisplay_switchtoconsole(); 1848 } 1849