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