1 /* $NetBSD: wsdisplay.c,v 1.76 2003/09/21 18:47:59 manu 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.76 2003/09/21 18:47:59 manu 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 dev_type_kqfilter(wsdisplaykqfilter); 162 163 const struct cdevsw wsdisplay_cdevsw = { 164 wsdisplayopen, wsdisplayclose, wsdisplayread, wsdisplaywrite, 165 wsdisplayioctl, wsdisplaystop, wsdisplaytty, wsdisplaypoll, 166 wsdisplaymmap, wsdisplaykqfilter, D_TTY 167 }; 168 169 static void wsdisplaystart(struct tty *); 170 static int wsdisplayparam(struct tty *, struct termios *); 171 172 173 /* Internal macros, functions, and variables. */ 174 #define SET(t, f) (t) |= (f) 175 #define CLR(t, f) (t) &= ~(f) 176 #define ISSET(t, f) ((t) & (f)) 177 178 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8) 179 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff) 180 #define ISWSDISPLAYSTAT(dev) (WSDISPLAYSCREEN(dev) == 254) 181 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255) 182 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen)) 183 184 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL) 185 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL) 186 187 static void wsdisplay_common_attach(struct wsdisplay_softc *sc, 188 int console, int kbdmux, const struct wsscreen_list *, 189 const struct wsdisplay_accessops *accessops, 190 void *accesscookie); 191 192 #ifdef WSDISPLAY_COMPAT_RAWKBD 193 int wsdisplay_update_rawkbd(struct wsdisplay_softc *, 194 struct wsscreen *); 195 #endif 196 197 static int wsdisplay_console_initted; 198 static struct wsdisplay_softc *wsdisplay_console_device; 199 static struct wsscreen_internal wsdisplay_console_conf; 200 201 static int wsdisplay_getc_dummy(dev_t); 202 static void wsdisplay_pollc(dev_t, int); 203 204 static int wsdisplay_cons_pollmode; 205 static void (*wsdisplay_cons_kbd_pollc)(dev_t, int); 206 207 static struct consdev wsdisplay_cons = { 208 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc, 209 wsdisplay_pollc, NULL, NULL, NULL, NODEV, CN_NORMAL 210 }; 211 212 #ifndef WSDISPLAY_DEFAULTSCREENS 213 # define WSDISPLAY_DEFAULTSCREENS 0 214 #endif 215 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS; 216 217 int wsdisplay_switch1(void *, int, int); 218 int wsdisplay_switch2(void *, int, int); 219 int wsdisplay_switch3(void *, int, int); 220 221 int wsdisplay_clearonclose; 222 223 struct wsscreen * 224 wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul, 225 const struct wsscreen_descr *type, void *cookie, int ccol, 226 int crow, long defattr) 227 { 228 struct wsscreen_internal *dconf; 229 struct wsscreen *scr; 230 231 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK); 232 if (!scr) 233 return (NULL); 234 235 if (console) { 236 dconf = &wsdisplay_console_conf; 237 /* 238 * If there's an emulation, tell it about the callback argument. 239 * The other stuff is already there. 240 */ 241 if (dconf->wsemul != NULL) 242 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0); 243 } else { /* not console */ 244 dconf = malloc(sizeof(struct wsscreen_internal), 245 M_DEVBUF, M_NOWAIT); 246 dconf->emulops = type->textops; 247 dconf->emulcookie = cookie; 248 if (dconf->emulops) { 249 dconf->wsemul = wsemul_pick(emul); 250 if (dconf->wsemul == NULL) { 251 free(dconf, M_DEVBUF); 252 free(scr, M_DEVBUF); 253 return (NULL); 254 } 255 dconf->wsemulcookie = 256 (*dconf->wsemul->attach)(0, type, cookie, 257 ccol, crow, scr, defattr); 258 } else 259 dconf->wsemul = NULL; 260 dconf->scrdata = type; 261 } 262 263 scr->scr_dconf = dconf; 264 265 scr->scr_tty = ttymalloc(); 266 tty_attach(scr->scr_tty); 267 scr->scr_hold_screen = 0; 268 if (WSSCREEN_HAS_EMULATOR(scr)) 269 scr->scr_flags = 0; 270 else 271 scr->scr_flags = SCR_GRAPHICS; 272 273 scr->scr_syncops = 0; 274 scr->sc = sc; 275 #ifdef WSDISPLAY_COMPAT_RAWKBD 276 scr->scr_rawkbd = 0; 277 #endif 278 return (scr); 279 } 280 281 void 282 wsscreen_detach(struct wsscreen *scr) 283 { 284 u_int ccol, crow; /* XXX */ 285 286 if (WSSCREEN_HAS_TTY(scr)) { 287 tty_detach(scr->scr_tty); 288 ttyfree(scr->scr_tty); 289 } 290 if (WSSCREEN_HAS_EMULATOR(scr)) 291 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie, 292 &ccol, &crow); 293 free(scr->scr_dconf, M_DEVBUF); 294 free(scr, M_DEVBUF); 295 } 296 297 const struct wsscreen_descr * 298 wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name) 299 { 300 int i; 301 const struct wsscreen_descr *scr; 302 303 KASSERT(scrdata->nscreens > 0); 304 305 if (name == NULL) 306 return (scrdata->screens[0]); 307 308 for (i = 0; i < scrdata->nscreens; i++) { 309 scr = scrdata->screens[i]; 310 if (!strcmp(name, scr->name)) 311 return (scr); 312 } 313 314 return (0); 315 } 316 317 /* 318 * print info about attached screen 319 */ 320 static void 321 wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count) 322 { 323 printf("%s: screen %d", sc->sc_dv.dv_xname, idx); 324 if (count > 1) 325 printf("-%d", idx + (count-1)); 326 printf(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name); 327 if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) { 328 printf(", %s emulation", 329 sc->sc_scr[idx]->scr_dconf->wsemul->name); 330 } 331 printf(")\n"); 332 } 333 334 int 335 wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx, 336 const char *screentype, const char *emul) 337 { 338 const struct wsscreen_descr *scrdesc; 339 int error; 340 void *cookie; 341 int ccol, crow; 342 long defattr; 343 struct wsscreen *scr; 344 int s; 345 346 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 347 return (EINVAL); 348 if (sc->sc_scr[idx] != NULL) 349 return (EBUSY); 350 351 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype); 352 if (!scrdesc) 353 return (ENXIO); 354 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie, 355 scrdesc, &cookie, &ccol, &crow, &defattr); 356 if (error) 357 return (error); 358 359 scr = wsscreen_attach(sc, 0, emul, scrdesc, 360 cookie, ccol, crow, defattr); 361 if (scr == NULL) { 362 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 363 cookie); 364 return (ENXIO); 365 } 366 367 sc->sc_scr[idx] = scr; 368 369 /* if no screen has focus yet, activate the first we get */ 370 s = spltty(); 371 if (!sc->sc_focus) { 372 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 373 scr->scr_dconf->emulcookie, 374 0, 0, 0); 375 sc->sc_focusidx = idx; 376 sc->sc_focus = scr; 377 } 378 splx(s); 379 return (0); 380 } 381 382 static void 383 wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr) 384 { 385 int maj, mn, idx; 386 387 /* hangup */ 388 if (WSSCREEN_HAS_TTY(scr)) { 389 struct tty *tp = scr->scr_tty; 390 (*tp->t_linesw->l_modem)(tp, 0); 391 } 392 393 /* locate the major number */ 394 maj = cdevsw_lookup_major(&wsdisplay_cdevsw); 395 /* locate the screen index */ 396 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++) 397 if (scr == sc->sc_scr[idx]) 398 break; 399 #ifdef DIAGNOSTIC 400 if (idx == WSDISPLAY_MAXSCREEN) 401 panic("wsdisplay_forceclose: bad screen"); 402 #endif 403 404 /* nuke the vnodes */ 405 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx); 406 vdevgone(maj, mn, mn, VCHR); 407 } 408 409 int 410 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags) 411 { 412 struct wsscreen *scr; 413 int s; 414 void *cookie; 415 416 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 417 return (EINVAL); 418 if ((scr = sc->sc_scr[idx]) == NULL) 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 aprint_normal("wsdisplay at %s", pnp); 517 #if 0 /* don't bother; it's ugly */ 518 aprint_normal(" 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 aprint_normal("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 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 696 return (ENXIO); 697 698 if (WSSCREEN_HAS_TTY(scr)) { 699 tp = scr->scr_tty; 700 tp->t_oproc = wsdisplaystart; 701 tp->t_param = wsdisplayparam; 702 tp->t_dev = dev; 703 newopen = (tp->t_state & TS_ISOPEN) == 0; 704 if (newopen) { 705 ttychars(tp); 706 tp->t_iflag = TTYDEF_IFLAG; 707 tp->t_oflag = TTYDEF_OFLAG; 708 tp->t_cflag = TTYDEF_CFLAG; 709 tp->t_lflag = TTYDEF_LFLAG; 710 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 711 wsdisplayparam(tp, &tp->t_termios); 712 ttsetwater(tp); 713 } else if ((tp->t_state & TS_XCLUDE) != 0 && 714 p->p_ucred->cr_uid != 0) 715 return EBUSY; 716 tp->t_state |= TS_CARR_ON; 717 718 error = ((*tp->t_linesw->l_open)(dev, tp)); 719 if (error) 720 return (error); 721 722 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 723 /* set window sizes as appropriate, and reset 724 the emulation */ 725 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 726 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 727 728 /* wsdisplay_set_emulation() */ 729 } 730 } 731 732 scr->scr_flags |= SCR_OPEN; 733 return (0); 734 } 735 736 int 737 wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p) 738 { 739 struct wsdisplay_softc *sc; 740 struct tty *tp; 741 struct wsscreen *scr; 742 743 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 744 745 if (ISWSDISPLAYSTAT(dev)) { 746 wsevent_fini(&sc->evar); 747 return (0); 748 } 749 750 if (ISWSDISPLAYCTL(dev)) 751 return (0); 752 753 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 754 return (0); 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 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 815 return (ENXIO); 816 817 if (!WSSCREEN_HAS_TTY(scr)) 818 return (ENODEV); 819 820 tp = scr->scr_tty; 821 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 822 } 823 824 int 825 wsdisplaywrite(dev_t dev, struct uio *uio, int flag) 826 { 827 struct wsdisplay_softc *sc; 828 struct tty *tp; 829 struct wsscreen *scr; 830 831 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 832 833 if (ISWSDISPLAYSTAT(dev)) { 834 return (0); 835 } 836 837 if (ISWSDISPLAYCTL(dev)) 838 return (0); 839 840 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 841 return (ENXIO); 842 843 if (!WSSCREEN_HAS_TTY(scr)) 844 return (ENODEV); 845 846 tp = scr->scr_tty; 847 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 848 } 849 850 int 851 wsdisplaypoll(dev_t dev, int events, struct proc *p) 852 { 853 struct wsdisplay_softc *sc; 854 struct tty *tp; 855 struct wsscreen *scr; 856 857 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 858 859 if (ISWSDISPLAYSTAT(dev)) 860 return (wsevent_poll(&sc->evar, events, p)); 861 862 if (ISWSDISPLAYCTL(dev)) 863 return (0); 864 865 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 866 return (ENXIO); 867 868 if (!WSSCREEN_HAS_TTY(scr)) 869 return (ENODEV); 870 871 tp = scr->scr_tty; 872 return ((*tp->t_linesw->l_poll)(tp, events, p)); 873 } 874 875 int 876 wsdisplaykqfilter(dev, kn) 877 dev_t dev; 878 struct knote *kn; 879 { 880 struct wsdisplay_softc *sc = 881 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 882 struct wsscreen *scr; 883 884 if (ISWSDISPLAYCTL(dev)) 885 return (1); 886 887 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 888 return (1); 889 890 891 if (WSSCREEN_HAS_TTY(scr)) 892 return (ttykqfilter(dev, kn)); 893 else 894 return (1); 895 } 896 897 struct tty * 898 wsdisplaytty(dev_t dev) 899 { 900 struct wsdisplay_softc *sc; 901 struct wsscreen *scr; 902 903 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 904 905 if (ISWSDISPLAYSTAT(dev)) 906 panic("wsdisplaytty() on status device"); 907 908 if (ISWSDISPLAYCTL(dev)) 909 panic("wsdisplaytty() on ctl device"); 910 911 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 912 return NULL; 913 914 return (scr->scr_tty); 915 } 916 917 int 918 wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 919 { 920 struct wsdisplay_softc *sc; 921 struct tty *tp; 922 int error; 923 struct wsscreen *scr; 924 925 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 926 927 #ifdef WSDISPLAY_COMPAT_USL 928 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 929 if (error != EPASSTHROUGH) 930 return (error); 931 #endif 932 933 if (ISWSDISPLAYSTAT(dev)) 934 return (wsdisplay_stat_ioctl(sc, cmd, data, flag, p)); 935 936 if (ISWSDISPLAYCTL(dev)) 937 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 938 939 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 940 return (ENXIO); 941 942 if (WSSCREEN_HAS_TTY(scr)) { 943 tp = scr->scr_tty; 944 945 /* printf("disc\n"); */ 946 /* do the line discipline ioctls first */ 947 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 948 if (error != EPASSTHROUGH) 949 return (error); 950 951 /* printf("tty\n"); */ 952 /* then the tty ioctls */ 953 error = ttioctl(tp, cmd, data, flag, p); 954 if (error != EPASSTHROUGH) 955 return (error); 956 } 957 958 #ifdef WSDISPLAY_COMPAT_USL 959 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 960 if (error != EPASSTHROUGH) 961 return (error); 962 #endif 963 964 return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)); 965 } 966 967 int 968 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp) 969 { 970 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 971 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 972 (caddr_t)dp, 0, NULL)); 973 } 974 975 int 976 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 977 u_long cmd, caddr_t data, int flag, struct proc *p) 978 { 979 int error; 980 char namebuf[16]; 981 struct wsdisplay_font fd; 982 983 #if NWSKBD > 0 984 struct wsevsrc *inp; 985 986 #ifdef WSDISPLAY_COMPAT_RAWKBD 987 switch (cmd) { 988 case WSKBDIO_SETMODE: 989 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 990 return (wsdisplay_update_rawkbd(sc, scr)); 991 case WSKBDIO_GETMODE: 992 *(int *)data = (scr->scr_rawkbd ? 993 WSKBD_RAW : WSKBD_TRANSLATED); 994 return (0); 995 } 996 #endif 997 inp = sc->sc_input; 998 if (inp == NULL) 999 return (ENXIO); 1000 error = wsevsrc_display_ioctl(inp, cmd, data, flag, p); 1001 if (error != EPASSTHROUGH) 1002 return (error); 1003 #endif /* NWSKBD > 0 */ 1004 1005 switch (cmd) { 1006 case WSDISPLAYIO_GMODE: 1007 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 1008 WSDISPLAYIO_MODE_MAPPED : 1009 WSDISPLAYIO_MODE_EMUL); 1010 return (0); 1011 1012 case WSDISPLAYIO_SMODE: 1013 #define d (*(int *)data) 1014 if (d != WSDISPLAYIO_MODE_EMUL && 1015 d != WSDISPLAYIO_MODE_MAPPED) 1016 return (EINVAL); 1017 1018 if (WSSCREEN_HAS_EMULATOR(scr)) { 1019 scr->scr_flags &= ~SCR_GRAPHICS; 1020 if (d == WSDISPLAYIO_MODE_MAPPED) 1021 scr->scr_flags |= SCR_GRAPHICS; 1022 } else if (d == WSDISPLAYIO_MODE_EMUL) 1023 return (EINVAL); 1024 1025 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1026 flag, p); 1027 1028 return (0); 1029 #undef d 1030 1031 case WSDISPLAYIO_SFONT: 1032 #define d ((struct wsdisplay_usefontdata *)data) 1033 if (!sc->sc_accessops->load_font) 1034 return (EINVAL); 1035 if (d->name) { 1036 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 1037 if (error) 1038 return (error); 1039 fd.name = namebuf; 1040 } else 1041 fd.name = 0; 1042 fd.data = 0; 1043 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 1044 scr->scr_dconf->emulcookie, &fd); 1045 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 1046 (*scr->scr_dconf->wsemul->reset) 1047 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 1048 return (error); 1049 #undef d 1050 1051 #if defined(WSDISPLAY_CHARFUNCS) 1052 case WSDISPLAYIO_GETWSCHAR: 1053 #define d ((struct wsdisplay_char *)data) 1054 if (!sc->sc_accessops->getwschar) 1055 return (EINVAL); 1056 return ((*sc->sc_accessops->getwschar) 1057 (scr->scr_dconf->emulcookie, d)); 1058 #undef d 1059 1060 case WSDISPLAYIO_PUTWSCHAR: 1061 #define d ((struct wsdisplay_char *)data) 1062 if (!sc->sc_accessops->putwschar) 1063 return (EINVAL); 1064 return ((*sc->sc_accessops->putwschar) 1065 (scr->scr_dconf->emulcookie, d)); 1066 #undef d 1067 return 1; 1068 #endif /* WSDISPLAY_CHARFUNCS */ 1069 1070 } 1071 1072 /* check ioctls for display */ 1073 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1074 flag, p)); 1075 } 1076 1077 int 1078 wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 1079 int flag, struct proc *p) 1080 { 1081 switch (cmd) { 1082 case WSDISPLAYIO_GETACTIVESCREEN: 1083 *(int*)data = wsdisplay_getactivescreen(sc); 1084 return (0); 1085 } 1086 1087 return (EPASSTHROUGH); 1088 } 1089 1090 int 1091 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 1092 int flag, struct proc *p) 1093 { 1094 int error; 1095 char *type, typebuf[16], *emul, emulbuf[16]; 1096 void *buf; 1097 u_int fontsz; 1098 #if defined(COMPAT_14) && NWSKBD > 0 1099 struct wsmux_device wsmuxdata; 1100 #endif 1101 #if NWSKBD > 0 1102 struct wsevsrc *inp; 1103 #endif 1104 1105 switch (cmd) { 1106 case WSDISPLAYIO_ADDSCREEN: 1107 #define d ((struct wsdisplay_addscreendata *)data) 1108 if (d->screentype) { 1109 error = copyinstr(d->screentype, typebuf, 1110 sizeof(typebuf), 0); 1111 if (error) 1112 return (error); 1113 type = typebuf; 1114 } else 1115 type = 0; 1116 if (d->emul) { 1117 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1118 if (error) 1119 return (error); 1120 emul = emulbuf; 1121 } else 1122 emul = 0; 1123 1124 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1125 wsdisplay_addscreen_print(sc, d->idx, 0); 1126 return (error); 1127 #undef d 1128 case WSDISPLAYIO_DELSCREEN: 1129 #define d ((struct wsdisplay_delscreendata *)data) 1130 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1131 #undef d 1132 case WSDISPLAYIO_LDFONT: 1133 #define d ((struct wsdisplay_font *)data) 1134 if (!sc->sc_accessops->load_font) 1135 return (EINVAL); 1136 if (d->name) { 1137 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1138 if (error) 1139 return (error); 1140 d->name = typebuf; 1141 } else 1142 d->name = "loaded"; /* ??? */ 1143 fontsz = d->fontheight * d->stride * d->numchars; 1144 if (fontsz > WSDISPLAY_MAXFONTSZ) 1145 return (EINVAL); 1146 1147 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1148 error = copyin(d->data, buf, fontsz); 1149 if (error) { 1150 free(buf, M_DEVBUF); 1151 return (error); 1152 } 1153 d->data = buf; 1154 error = 1155 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1156 free(buf, M_DEVBUF); 1157 #undef d 1158 return (error); 1159 1160 #if NWSKBD > 0 1161 #ifdef COMPAT_14 1162 case _O_WSDISPLAYIO_SETKEYBOARD: 1163 #define d ((struct wsdisplay_kbddata *)data) 1164 inp = sc->sc_input; 1165 if (inp == NULL) 1166 return (ENXIO); 1167 switch (d->op) { 1168 case _O_WSDISPLAY_KBD_ADD: 1169 if (d->idx == -1) { 1170 d->idx = wskbd_pickfree(); 1171 if (d->idx == -1) 1172 return (ENXIO); 1173 } 1174 wsmuxdata.type = WSMUX_KBD; 1175 wsmuxdata.idx = d->idx; 1176 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE, 1177 &wsmuxdata, flag, p)); 1178 case _O_WSDISPLAY_KBD_DEL: 1179 wsmuxdata.type = WSMUX_KBD; 1180 wsmuxdata.idx = d->idx; 1181 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE, 1182 &wsmuxdata, flag, p)); 1183 default: 1184 return (EINVAL); 1185 } 1186 #undef d 1187 #endif 1188 1189 case WSMUXIO_ADD_DEVICE: 1190 #define d ((struct wsmux_device *)data) 1191 if (d->idx == -1 && d->type == WSMUX_KBD) 1192 d->idx = wskbd_pickfree(); 1193 #undef d 1194 /* fall into */ 1195 case WSMUXIO_INJECTEVENT: 1196 case WSMUXIO_REMOVE_DEVICE: 1197 case WSMUXIO_LIST_DEVICES: 1198 inp = sc->sc_input; 1199 if (inp == NULL) 1200 return (ENXIO); 1201 return (wsevsrc_ioctl(inp, cmd, data, flag, p)); 1202 #endif /* NWSKBD > 0 */ 1203 1204 } 1205 return (EPASSTHROUGH); 1206 } 1207 1208 int 1209 wsdisplay_stat_inject(struct device *dev, u_int type, int value) 1210 { 1211 struct wsdisplay_softc *sc = (struct wsdisplay_softc *) dev; 1212 struct wseventvar *evar; 1213 struct wscons_event *ev; 1214 struct timeval thistime; 1215 int put; 1216 1217 evar = &sc->evar; 1218 1219 if (evar == NULL) 1220 return (0); 1221 1222 if (evar->q == NULL) 1223 return (1); 1224 1225 put = evar->put; 1226 ev = &evar->q[put]; 1227 put = (put + 1) % WSEVENT_QSIZE; 1228 if (put == evar->get) { 1229 log(LOG_WARNING, "wsdisplay: event queue overflow\n"); 1230 return (1); 1231 } 1232 ev->type = type; 1233 ev->value = value; 1234 microtime(&thistime); 1235 TIMEVAL_TO_TIMESPEC(&thistime, &ev->time); 1236 evar->put = put; 1237 WSEVENT_WAKEUP(evar); 1238 1239 return (0); 1240 } 1241 1242 paddr_t 1243 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1244 { 1245 struct wsdisplay_softc *sc = 1246 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1247 struct wsscreen *scr; 1248 1249 if (ISWSDISPLAYSTAT(dev)) 1250 return (-1); 1251 1252 if (ISWSDISPLAYCTL(dev)) 1253 return (-1); 1254 1255 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1256 return (-1); 1257 1258 if (!(scr->scr_flags & SCR_GRAPHICS)) 1259 return (-1); 1260 1261 /* pass mmap to display */ 1262 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1263 } 1264 1265 void 1266 wsdisplaystart(struct tty *tp) 1267 { 1268 struct wsdisplay_softc *sc; 1269 struct wsscreen *scr; 1270 int s, n; 1271 u_char *buf; 1272 1273 s = spltty(); 1274 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1275 splx(s); 1276 return; 1277 } 1278 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1279 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) { 1280 splx(s); 1281 return; 1282 } 1283 1284 if (scr->scr_hold_screen) { 1285 tp->t_state |= TS_TIMEOUT; 1286 splx(s); 1287 return; 1288 } 1289 tp->t_state |= TS_BUSY; 1290 splx(s); 1291 1292 /* 1293 * Drain output from ring buffer. 1294 * The output will normally be in one contiguous chunk, but when the 1295 * ring wraps, it will be in two pieces.. one at the end of the ring, 1296 * the other at the start. For performance, rather than loop here, 1297 * we output one chunk, see if there's another one, and if so, output 1298 * it too. 1299 */ 1300 1301 n = ndqb(&tp->t_outq, 0); 1302 buf = tp->t_outq.c_cf; 1303 1304 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1305 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1306 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1307 buf, n, 0); 1308 } 1309 ndflush(&tp->t_outq, n); 1310 1311 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1312 buf = tp->t_outq.c_cf; 1313 1314 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1315 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1316 (*scr->scr_dconf->wsemul->output) 1317 (scr->scr_dconf->wsemulcookie, buf, n, 0); 1318 } 1319 ndflush(&tp->t_outq, n); 1320 } 1321 1322 s = spltty(); 1323 tp->t_state &= ~TS_BUSY; 1324 /* Come back if there's more to do */ 1325 if (tp->t_outq.c_cc) { 1326 tp->t_state |= TS_TIMEOUT; 1327 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1328 ttrstrt, tp); 1329 } 1330 if (tp->t_outq.c_cc <= tp->t_lowat) { 1331 if (tp->t_state&TS_ASLEEP) { 1332 tp->t_state &= ~TS_ASLEEP; 1333 wakeup(&tp->t_outq); 1334 } 1335 selwakeup(&tp->t_wsel); 1336 } 1337 splx(s); 1338 } 1339 1340 void 1341 wsdisplaystop(struct tty *tp, int flag) 1342 { 1343 int s; 1344 1345 s = spltty(); 1346 if (ISSET(tp->t_state, TS_BUSY)) 1347 if (!ISSET(tp->t_state, TS_TTSTOP)) 1348 SET(tp->t_state, TS_FLUSH); 1349 splx(s); 1350 } 1351 1352 /* Set line parameters. */ 1353 int 1354 wsdisplayparam(struct tty *tp, struct termios *t) 1355 { 1356 1357 tp->t_ispeed = t->c_ispeed; 1358 tp->t_ospeed = t->c_ospeed; 1359 tp->t_cflag = t->c_cflag; 1360 return 0; 1361 } 1362 1363 /* 1364 * Callbacks for the emulation code. 1365 */ 1366 void 1367 wsdisplay_emulbell(void *v) 1368 { 1369 struct wsscreen *scr = v; 1370 1371 if (scr == NULL) /* console, before real attach */ 1372 return; 1373 1374 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1375 return; 1376 1377 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1378 FWRITE, NULL); 1379 } 1380 1381 void 1382 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1383 { 1384 struct wsscreen *scr = v; 1385 struct tty *tp; 1386 1387 if (v == NULL) /* console, before real attach */ 1388 return; 1389 1390 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1391 return; 1392 if (!WSSCREEN_HAS_TTY(scr)) 1393 return; 1394 1395 tp = scr->scr_tty; 1396 while (count-- > 0) 1397 (*tp->t_linesw->l_rint)(*data++, tp); 1398 } 1399 1400 /* 1401 * Calls from the keyboard interface. 1402 */ 1403 void 1404 wsdisplay_kbdinput(struct device *dev, keysym_t ks) 1405 { 1406 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1407 struct wsscreen *scr; 1408 char *dp; 1409 int count; 1410 struct tty *tp; 1411 1412 KASSERT(sc != NULL); 1413 1414 scr = sc->sc_focus; 1415 1416 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1417 return; 1418 1419 tp = scr->scr_tty; 1420 1421 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1422 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1423 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1424 count = (*scr->scr_dconf->wsemul->translate) 1425 (scr->scr_dconf->wsemulcookie, ks, &dp); 1426 while (count-- > 0) 1427 (*tp->t_linesw->l_rint)(*dp++, tp); 1428 } 1429 } 1430 1431 #if defined(WSDISPLAY_COMPAT_RAWKBD) 1432 int 1433 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1434 { 1435 #if NWSKBD > 0 1436 int s, raw, data, error; 1437 struct wsevsrc *inp; 1438 1439 s = spltty(); 1440 1441 raw = (scr ? scr->scr_rawkbd : 0); 1442 1443 if (scr != sc->sc_focus || 1444 sc->sc_rawkbd == raw) { 1445 splx(s); 1446 return (0); 1447 } 1448 1449 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1450 inp = sc->sc_input; 1451 if (inp == NULL) 1452 return (ENXIO); 1453 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0); 1454 if (!error) 1455 sc->sc_rawkbd = raw; 1456 splx(s); 1457 return (error); 1458 #else 1459 return (0); 1460 #endif 1461 } 1462 #endif 1463 1464 int 1465 wsdisplay_switch3(void *arg, int error, int waitok) 1466 { 1467 struct wsdisplay_softc *sc = arg; 1468 int no; 1469 struct wsscreen *scr; 1470 1471 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1472 printf("wsdisplay_switch3: not switching\n"); 1473 return (EINVAL); 1474 } 1475 1476 no = sc->sc_screenwanted; 1477 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1478 panic("wsdisplay_switch3: invalid screen %d", no); 1479 scr = sc->sc_scr[no]; 1480 if (!scr) { 1481 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1482 error = ENXIO; 1483 } 1484 1485 if (error) { 1486 /* try to recover, avoid recursion */ 1487 1488 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1489 printf("wsdisplay_switch3: giving up\n"); 1490 sc->sc_focus = 0; 1491 #ifdef WSDISPLAY_COMPAT_RAWKBD 1492 wsdisplay_update_rawkbd(sc, 0); 1493 #endif 1494 sc->sc_flags &= ~SC_SWITCHPENDING; 1495 return (error); 1496 } 1497 1498 sc->sc_screenwanted = sc->sc_oldscreen; 1499 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1500 return (wsdisplay_switch1(arg, 0, waitok)); 1501 } 1502 1503 sc->sc_flags &= ~SC_SWITCHPENDING; 1504 1505 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1506 wakeup(scr); 1507 return (error); 1508 } 1509 1510 int 1511 wsdisplay_switch2(void *arg, int error, int waitok) 1512 { 1513 struct wsdisplay_softc *sc = arg; 1514 int no; 1515 struct wsscreen *scr; 1516 1517 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1518 printf("wsdisplay_switch2: not switching\n"); 1519 return (EINVAL); 1520 } 1521 1522 no = sc->sc_screenwanted; 1523 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1524 panic("wsdisplay_switch2: invalid screen %d", no); 1525 scr = sc->sc_scr[no]; 1526 if (!scr) { 1527 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1528 error = ENXIO; 1529 } 1530 1531 if (error) { 1532 /* try to recover, avoid recursion */ 1533 1534 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1535 printf("wsdisplay_switch2: giving up\n"); 1536 sc->sc_focus = 0; 1537 sc->sc_flags &= ~SC_SWITCHPENDING; 1538 return (error); 1539 } 1540 1541 sc->sc_screenwanted = sc->sc_oldscreen; 1542 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1543 return (wsdisplay_switch1(arg, 0, waitok)); 1544 } 1545 1546 sc->sc_focusidx = no; 1547 sc->sc_focus = scr; 1548 1549 #ifdef WSDISPLAY_COMPAT_RAWKBD 1550 (void) wsdisplay_update_rawkbd(sc, scr); 1551 #endif 1552 /* keyboard map??? */ 1553 1554 #define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3) 1555 if (scr->scr_syncops) { 1556 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1557 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1558 if (error == EAGAIN) { 1559 /* switch will be done asynchronously */ 1560 return (0); 1561 } 1562 } 1563 1564 return (wsdisplay_switch3(sc, error, waitok)); 1565 } 1566 1567 int 1568 wsdisplay_switch1(void *arg, int error, int waitok) 1569 { 1570 struct wsdisplay_softc *sc = arg; 1571 int no; 1572 struct wsscreen *scr; 1573 1574 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1575 printf("wsdisplay_switch1: not switching\n"); 1576 return (EINVAL); 1577 } 1578 1579 no = sc->sc_screenwanted; 1580 if (no == WSDISPLAY_NULLSCREEN) { 1581 sc->sc_flags &= ~SC_SWITCHPENDING; 1582 if (!error) { 1583 sc->sc_focus = 0; 1584 } 1585 wakeup(sc); 1586 return (error); 1587 } 1588 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1589 panic("wsdisplay_switch1: invalid screen %d", no); 1590 scr = sc->sc_scr[no]; 1591 if (!scr) { 1592 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1593 error = ENXIO; 1594 } 1595 1596 if (error) { 1597 sc->sc_flags &= ~SC_SWITCHPENDING; 1598 return (error); 1599 } 1600 1601 #define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2) 1602 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1603 scr->scr_dconf->emulcookie, 1604 waitok, 1605 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1606 if (error == EAGAIN) { 1607 /* switch will be done asynchronously */ 1608 return (0); 1609 } 1610 1611 return (wsdisplay_switch2(sc, error, waitok)); 1612 } 1613 1614 int 1615 wsdisplay_switch(struct device *dev, int no, int waitok) 1616 { 1617 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1618 int s, res = 0; 1619 struct wsscreen *scr; 1620 1621 if (no != WSDISPLAY_NULLSCREEN) { 1622 if ((no < 0 || no >= WSDISPLAY_MAXSCREEN)) 1623 return (EINVAL); 1624 if (sc->sc_scr[no] == NULL) 1625 return (ENXIO); 1626 } 1627 1628 wsdisplay_stat_inject(dev, WSCONS_EVENT_SCREEN_SWITCH, no); 1629 1630 s = spltty(); 1631 1632 if ((sc->sc_focus && no == sc->sc_focusidx) || 1633 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1634 splx(s); 1635 return (0); 1636 } 1637 1638 if (sc->sc_flags & SC_SWITCHPENDING) { 1639 splx(s); 1640 return (EBUSY); 1641 } 1642 1643 sc->sc_flags |= SC_SWITCHPENDING; 1644 sc->sc_screenwanted = no; 1645 1646 splx(s); 1647 1648 scr = sc->sc_focus; 1649 if (!scr) { 1650 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1651 return (wsdisplay_switch1(sc, 0, waitok)); 1652 } else 1653 sc->sc_oldscreen = sc->sc_focusidx; 1654 1655 #define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1) 1656 if (scr->scr_syncops) { 1657 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1658 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1659 if (res == EAGAIN) { 1660 /* switch will be done asynchronously */ 1661 return (0); 1662 } 1663 } else if (scr->scr_flags & SCR_GRAPHICS) { 1664 /* no way to save state */ 1665 res = EBUSY; 1666 } 1667 1668 return (wsdisplay_switch1(sc, res, waitok)); 1669 } 1670 1671 void 1672 wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op) 1673 { 1674 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1675 struct wsscreen *scr; 1676 1677 KASSERT(sc != NULL); 1678 scr = sc->sc_focus; 1679 1680 if (!scr) 1681 return; 1682 1683 switch (op) { 1684 case WSDISPLAY_RESETEMUL: 1685 if (!WSSCREEN_HAS_EMULATOR(scr)) 1686 break; 1687 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1688 WSEMUL_RESET); 1689 break; 1690 case WSDISPLAY_RESETCLOSE: 1691 wsdisplay_closescreen(sc, scr); 1692 break; 1693 } 1694 } 1695 1696 /* 1697 * Interface for (external) VT switch / process synchronization code 1698 */ 1699 int 1700 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1701 void *cookie) 1702 { 1703 if (scr->scr_syncops) { 1704 /* 1705 * The screen is already claimed. 1706 * Check if the owner is still alive. 1707 */ 1708 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1709 return (EBUSY); 1710 } 1711 scr->scr_syncops = ops; 1712 scr->scr_synccookie = cookie; 1713 return (0); 1714 } 1715 1716 int 1717 wsscreen_detach_sync(struct wsscreen *scr) 1718 { 1719 if (!scr->scr_syncops) 1720 return (EINVAL); 1721 scr->scr_syncops = 0; 1722 return (0); 1723 } 1724 1725 int 1726 wsscreen_lookup_sync(struct wsscreen *scr, 1727 const struct wscons_syncops *ops, /* used as ID */ 1728 void **cookiep) 1729 { 1730 if (!scr->scr_syncops || ops != scr->scr_syncops) 1731 return (EINVAL); 1732 *cookiep = scr->scr_synccookie; 1733 return (0); 1734 } 1735 1736 /* 1737 * Interface to virtual screen stuff 1738 */ 1739 int 1740 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 1741 { 1742 return (WSDISPLAY_MAXSCREEN - 1); 1743 } 1744 1745 int 1746 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 1747 { 1748 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1749 return (EINVAL); 1750 if (!sc->sc_scr[idx]) 1751 return (ENXIO); 1752 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1753 } 1754 1755 int 1756 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 1757 { 1758 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1759 } 1760 1761 int 1762 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 1763 { 1764 struct wsscreen *scr; 1765 int s, res = 0; 1766 1767 if (no == WSDISPLAY_NULLSCREEN) { 1768 s = spltty(); 1769 while (sc->sc_focus && res == 0) { 1770 res = tsleep(sc, PCATCH, "wswait", 0); 1771 } 1772 splx(s); 1773 return (res); 1774 } 1775 1776 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1777 return (ENXIO); 1778 scr = sc->sc_scr[no]; 1779 if (!scr) 1780 return (ENXIO); 1781 1782 s = spltty(); 1783 if (scr != sc->sc_focus) { 1784 scr->scr_flags |= SCR_WAITACTIVE; 1785 res = tsleep(scr, PCATCH, "wswait", 0); 1786 if (scr != sc->sc_scr[no]) 1787 res = ENXIO; /* disappeared in the meantime */ 1788 else 1789 scr->scr_flags &= ~SCR_WAITACTIVE; 1790 } 1791 splx(s); 1792 return (res); 1793 } 1794 1795 void 1796 wsdisplay_kbdholdscreen(struct device *dev, int hold) 1797 { 1798 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1799 struct wsscreen *scr; 1800 1801 scr = sc->sc_focus; 1802 1803 if (hold) 1804 scr->scr_hold_screen = 1; 1805 else { 1806 scr->scr_hold_screen = 0; 1807 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1808 ttrstrt, scr->scr_tty); /* "immediate" */ 1809 } 1810 } 1811 1812 #if NWSKBD > 0 1813 void 1814 wsdisplay_set_console_kbd(struct wsevsrc *src) 1815 { 1816 if (wsdisplay_console_device == NULL) { 1817 src->me_dispdv = NULL; 1818 return; 1819 } 1820 #if NWSMUX > 0 1821 if (wsmux_attach_sc((struct wsmux_softc *) 1822 wsdisplay_console_device->sc_input, src)) { 1823 src->me_dispdv = NULL; 1824 return; 1825 } 1826 #else 1827 wsdisplay_console_device->sc_input = src; 1828 #endif 1829 src->me_dispdv = &wsdisplay_console_device->sc_dv; 1830 } 1831 #endif /* NWSKBD > 0 */ 1832 1833 /* 1834 * Console interface. 1835 */ 1836 void 1837 wsdisplay_cnputc(dev_t dev, int i) 1838 { 1839 struct wsscreen_internal *dc; 1840 u_char c = i; 1841 1842 if (!wsdisplay_console_initted) 1843 return; 1844 1845 if ((wsdisplay_console_device != NULL) && 1846 (wsdisplay_console_device->sc_scr[0] != NULL) && 1847 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1848 return; 1849 1850 dc = &wsdisplay_console_conf; 1851 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1852 } 1853 1854 static int 1855 wsdisplay_getc_dummy(dev_t dev) 1856 { 1857 /* panic? */ 1858 return (0); 1859 } 1860 1861 static void 1862 wsdisplay_pollc(dev_t dev, int on) 1863 { 1864 1865 wsdisplay_cons_pollmode = on; 1866 1867 /* notify to fb drivers */ 1868 if (wsdisplay_console_device != NULL && 1869 wsdisplay_console_device->sc_accessops->pollc != NULL) 1870 (*wsdisplay_console_device->sc_accessops->pollc) 1871 (wsdisplay_console_device->sc_accesscookie, on); 1872 1873 /* notify to kbd drivers */ 1874 if (wsdisplay_cons_kbd_pollc) 1875 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 1876 } 1877 1878 void 1879 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 1880 void (*bell)(dev_t, u_int, u_int, u_int)) 1881 { 1882 wsdisplay_cons.cn_getc = get; 1883 wsdisplay_cons.cn_bell = bell; 1884 wsdisplay_cons_kbd_pollc = poll; 1885 } 1886 1887 void 1888 wsdisplay_unset_cons_kbd(void) 1889 { 1890 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1891 wsdisplay_cons.cn_bell = NULL; 1892 wsdisplay_cons_kbd_pollc = 0; 1893 } 1894 1895 /* 1896 * Switch the console display to it's first screen. 1897 */ 1898 void 1899 wsdisplay_switchtoconsole(void) 1900 { 1901 struct wsdisplay_softc *sc; 1902 struct wsscreen *scr; 1903 1904 if (wsdisplay_console_device != NULL) { 1905 sc = wsdisplay_console_device; 1906 if ((scr = sc->sc_scr[0]) == NULL) 1907 return; 1908 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1909 scr->scr_dconf->emulcookie, 1910 0, NULL, NULL); 1911 } 1912 } 1913 1914 /* 1915 * Switch the console at shutdown. 1916 */ 1917 static void 1918 wsdisplay_shutdownhook(void *arg) 1919 { 1920 1921 wsdisplay_switchtoconsole(); 1922 } 1923