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