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