1 /* $NetBSD: wsdisplay.c,v 1.70 2002/10/23 09:14:06 jdolecek Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: wsdisplay.c,v 1.70 2002/10/23 09:14:06 jdolecek 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, 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 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 scr = sc->sc_scr[idx]; 419 if (!scr) 420 return (ENXIO); 421 422 if (scr->scr_dconf == &wsdisplay_console_conf || 423 scr->scr_syncops || 424 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE))) 425 return(EBUSY); 426 427 wsdisplay_closescreen(sc, scr); 428 429 /* 430 * delete pointers, so neither device entries 431 * nor keyboard input can reference it anymore 432 */ 433 s = spltty(); 434 if (sc->sc_focus == scr) { 435 sc->sc_focus = 0; 436 #ifdef WSDISPLAY_COMPAT_RAWKBD 437 wsdisplay_update_rawkbd(sc, 0); 438 #endif 439 } 440 sc->sc_scr[idx] = 0; 441 splx(s); 442 443 /* 444 * Wake up processes waiting for the screen to 445 * be activated. Sleepers must check whether 446 * the screen still exists. 447 */ 448 if (scr->scr_flags & SCR_WAITACTIVE) 449 wakeup(scr); 450 451 /* save a reference to the graphics screen */ 452 cookie = scr->scr_dconf->emulcookie; 453 454 wsscreen_detach(scr); 455 456 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, 457 cookie); 458 459 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx); 460 return (0); 461 } 462 463 /* 464 * Autoconfiguration functions. 465 */ 466 int 467 wsdisplay_emul_match(struct device *parent, struct cfdata *match, void *aux) 468 { 469 struct wsemuldisplaydev_attach_args *ap = aux; 470 471 if (match->wsemuldisplaydevcf_console != 472 WSEMULDISPLAYDEVCF_CONSOLE_UNK) { 473 /* 474 * If console-ness of device specified, either match 475 * exactly (at high priority), or fail. 476 */ 477 if (match->wsemuldisplaydevcf_console != 0 && 478 ap->console != 0) 479 return (10); 480 else 481 return (0); 482 } 483 484 /* If console-ness unspecified, it wins. */ 485 return (1); 486 } 487 488 void 489 wsdisplay_emul_attach(struct device *parent, struct device *self, void *aux) 490 { 491 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 492 struct wsemuldisplaydev_attach_args *ap = aux; 493 494 wsdisplay_common_attach(sc, ap->console, 495 sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, ap->scrdata, 496 ap->accessops, ap->accesscookie); 497 498 if (ap->console) { 499 int maj; 500 501 /* locate the major number */ 502 maj = cdevsw_lookup_major(&wsdisplay_cdevsw); 503 504 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0)); 505 } 506 } 507 508 /* Print function (for parent devices). */ 509 int 510 wsemuldisplaydevprint(void *aux, const char *pnp) 511 { 512 #if 0 /* -Wunused */ 513 struct wsemuldisplaydev_attach_args *ap = aux; 514 #endif 515 516 if (pnp) 517 printf("wsdisplay at %s", pnp); 518 #if 0 /* don't bother; it's ugly */ 519 printf(" console %d", ap->console); 520 #endif 521 522 return (UNCONF); 523 } 524 525 int 526 wsdisplay_noemul_match(struct device *parent, struct cfdata *match, void *aux) 527 { 528 #if 0 /* -Wunused */ 529 struct wsdisplaydev_attach_args *ap = aux; 530 #endif 531 532 /* Always match. */ 533 return (1); 534 } 535 536 void 537 wsdisplay_noemul_attach(struct device *parent, struct device *self, void *aux) 538 { 539 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 540 struct wsdisplaydev_attach_args *ap = aux; 541 542 wsdisplay_common_attach(sc, 0, 543 sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_kbdmux, NULL, 544 ap->accessops, ap->accesscookie); 545 } 546 547 /* Print function (for parent devices). */ 548 int 549 wsdisplaydevprint(void *aux, const char *pnp) 550 { 551 #if 0 /* -Wunused */ 552 struct wsdisplaydev_attach_args *ap = aux; 553 #endif 554 555 if (pnp) 556 printf("wsdisplay at %s", pnp); 557 558 return (UNCONF); 559 } 560 561 static void 562 wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux, 563 const struct wsscreen_list *scrdata, 564 const struct wsdisplay_accessops *accessops, 565 void *accesscookie) 566 { 567 static int hookset; 568 int i, start=0; 569 #if NWSKBD > 0 570 struct wsevsrc *kme; 571 #if NWSMUX > 0 572 struct wsmux_softc *mux; 573 574 if (kbdmux >= 0) 575 mux = wsmux_getmux(kbdmux); 576 else 577 mux = wsmux_create("dmux", sc->sc_dv.dv_unit); 578 /* XXX panic()ing isn't nice, but attach cannot fail */ 579 if (mux == NULL) 580 panic("wsdisplay_common_attach: no memory"); 581 sc->sc_input = &mux->sc_base; 582 mux->sc_base.me_dispdv = &sc->sc_dv; 583 printf(" kbdmux %d", kbdmux); 584 #else 585 if (kbdmux >= 0) 586 printf(" (kbdmux ignored)"); 587 #endif 588 #endif 589 590 sc->sc_isconsole = console; 591 592 if (console) { 593 KASSERT(wsdisplay_console_initted); 594 KASSERT(wsdisplay_console_device == NULL); 595 596 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0); 597 wsdisplay_console_device = sc; 598 599 printf(": console (%s, %s emulation)", 600 wsdisplay_console_conf.scrdata->name, 601 wsdisplay_console_conf.wsemul->name); 602 603 #if NWSKBD > 0 604 kme = wskbd_set_console_display(&sc->sc_dv, sc->sc_input); 605 if (kme != NULL) 606 printf(", using %s", kme->me_dv.dv_xname); 607 #if NWSMUX == 0 608 sc->sc_input = kme; 609 #endif 610 #endif 611 612 sc->sc_focusidx = 0; 613 sc->sc_focus = sc->sc_scr[0]; 614 start = 1; 615 } 616 printf("\n"); 617 618 #if NWSKBD > 0 && NWSMUX > 0 619 wsmux_set_display(mux, &sc->sc_dv); 620 #endif 621 622 sc->sc_accessops = accessops; 623 sc->sc_accesscookie = accesscookie; 624 sc->sc_scrdata = scrdata; 625 626 /* 627 * Set up a number of virtual screens if wanted. The 628 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 629 * is for special cases like installation kernels. 630 */ 631 for (i = start; i < wsdisplay_defaultscreens; i++) { 632 if (wsdisplay_addscreen(sc, i, 0, 0)) 633 break; 634 } 635 636 if (i > start) 637 wsdisplay_addscreen_print(sc, start, i-start); 638 639 if (hookset == 0) 640 shutdownhook_establish(wsdisplay_shutdownhook, NULL); 641 hookset = 1; 642 } 643 644 void 645 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie, 646 int ccol, int crow, long defattr) 647 { 648 const struct wsemul_ops *wsemul; 649 650 KASSERT(!wsdisplay_console_initted); 651 KASSERT(type->nrows > 0); 652 KASSERT(type->ncols > 0); 653 KASSERT(crow < type->nrows); 654 KASSERT(ccol < type->ncols); 655 656 wsdisplay_console_conf.emulops = type->textops; 657 wsdisplay_console_conf.emulcookie = cookie; 658 wsdisplay_console_conf.scrdata = type; 659 660 wsemul = wsemul_pick(0); /* default */ 661 wsdisplay_console_conf.wsemul = wsemul; 662 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie, 663 ccol, crow, 664 defattr); 665 666 cn_tab = &wsdisplay_cons; 667 wsdisplay_console_initted = 1; 668 } 669 670 /* 671 * Tty and cdevsw functions. 672 */ 673 int 674 wsdisplayopen(dev_t dev, int flag, int mode, struct proc *p) 675 { 676 struct wsdisplay_softc *sc; 677 struct tty *tp; 678 int newopen, error; 679 struct wsscreen *scr; 680 681 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 682 if (sc == NULL) /* make sure it was attached */ 683 return (ENXIO); 684 685 if (ISWSDISPLAYSTAT(dev)) { 686 wsevent_init(&sc->evar); 687 sc->evar.io = p; 688 return (0); 689 } 690 691 if (ISWSDISPLAYCTL(dev)) 692 return (0); 693 694 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 695 return (ENXIO); 696 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 697 if (!scr) 698 return (ENXIO); 699 700 if (WSSCREEN_HAS_TTY(scr)) { 701 tp = scr->scr_tty; 702 tp->t_oproc = wsdisplaystart; 703 tp->t_param = wsdisplayparam; 704 tp->t_dev = dev; 705 newopen = (tp->t_state & TS_ISOPEN) == 0; 706 if (newopen) { 707 ttychars(tp); 708 tp->t_iflag = TTYDEF_IFLAG; 709 tp->t_oflag = TTYDEF_OFLAG; 710 tp->t_cflag = TTYDEF_CFLAG; 711 tp->t_lflag = TTYDEF_LFLAG; 712 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 713 wsdisplayparam(tp, &tp->t_termios); 714 ttsetwater(tp); 715 } else if ((tp->t_state & TS_XCLUDE) != 0 && 716 p->p_ucred->cr_uid != 0) 717 return EBUSY; 718 tp->t_state |= TS_CARR_ON; 719 720 error = ((*tp->t_linesw->l_open)(dev, tp)); 721 if (error) 722 return (error); 723 724 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) { 725 /* set window sizes as appropriate, and reset 726 the emulation */ 727 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 728 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 729 730 /* wsdisplay_set_emulation() */ 731 } 732 } 733 734 scr->scr_flags |= SCR_OPEN; 735 return (0); 736 } 737 738 int 739 wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p) 740 { 741 struct wsdisplay_softc *sc; 742 struct tty *tp; 743 struct wsscreen *scr; 744 745 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 746 747 if (ISWSDISPLAYSTAT(dev)) { 748 wsevent_fini(&sc->evar); 749 return (0); 750 } 751 752 if (ISWSDISPLAYCTL(dev)) 753 return (0); 754 755 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 756 757 if (WSSCREEN_HAS_TTY(scr)) { 758 if (scr->scr_hold_screen) { 759 int s; 760 761 /* XXX RESET KEYBOARD LEDS, etc. */ 762 s = spltty(); /* avoid conflict with keyboard */ 763 wsdisplay_kbdholdscreen((struct device *)sc, 0); 764 splx(s); 765 } 766 tp = scr->scr_tty; 767 (*tp->t_linesw->l_close)(tp, flag); 768 ttyclose(tp); 769 } 770 771 if (scr->scr_syncops) 772 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 773 774 if (WSSCREEN_HAS_EMULATOR(scr)) { 775 scr->scr_flags &= ~SCR_GRAPHICS; 776 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 777 WSEMUL_RESET); 778 if (wsdisplay_clearonclose) 779 (*scr->scr_dconf->wsemul->reset) 780 (scr->scr_dconf->wsemulcookie, 781 WSEMUL_CLEARSCREEN); 782 } 783 784 #ifdef WSDISPLAY_COMPAT_RAWKBD 785 if (scr->scr_rawkbd) { 786 int kbmode = WSKBD_TRANSLATED; 787 (void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 788 (caddr_t)&kbmode, 0, p); 789 } 790 #endif 791 792 scr->scr_flags &= ~SCR_OPEN; 793 794 return (0); 795 } 796 797 int 798 wsdisplayread(dev_t dev, struct uio *uio, int flag) 799 { 800 struct wsdisplay_softc *sc; 801 struct tty *tp; 802 struct wsscreen *scr; 803 int error; 804 805 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 806 807 if (ISWSDISPLAYSTAT(dev)) { 808 error = wsevent_read(&sc->evar, uio, flag); 809 return (error); 810 } 811 812 if (ISWSDISPLAYCTL(dev)) 813 return (0); 814 815 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 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 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 841 842 if (!WSSCREEN_HAS_TTY(scr)) 843 return (ENODEV); 844 845 tp = scr->scr_tty; 846 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 847 } 848 849 int 850 wsdisplaypoll(dev_t dev, int events, struct proc *p) 851 { 852 struct wsdisplay_softc *sc; 853 struct tty *tp; 854 struct wsscreen *scr; 855 856 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 857 858 if (ISWSDISPLAYSTAT(dev)) 859 return (wsevent_poll(&sc->evar, events, p)); 860 861 if (ISWSDISPLAYCTL(dev)) 862 return (0); 863 864 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 865 866 if (!WSSCREEN_HAS_TTY(scr)) 867 return (ENODEV); 868 869 tp = scr->scr_tty; 870 return ((*tp->t_linesw->l_poll)(tp, events, p)); 871 } 872 873 int 874 wsdisplaykqfilter(dev, kn) 875 dev_t dev; 876 struct knote *kn; 877 { 878 struct wsdisplay_softc *sc = 879 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 880 struct wsscreen *scr; 881 882 if (ISWSDISPLAYCTL(dev)) 883 return (1); 884 885 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 886 887 if (WSSCREEN_HAS_TTY(scr)) 888 return (ttykqfilter(dev, kn)); 889 else 890 return (1); 891 } 892 893 struct tty * 894 wsdisplaytty(dev_t dev) 895 { 896 struct wsdisplay_softc *sc; 897 struct wsscreen *scr; 898 899 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 900 901 if (ISWSDISPLAYSTAT(dev)) 902 panic("wsdisplaytty() on status device"); 903 904 if (ISWSDISPLAYCTL(dev)) 905 panic("wsdisplaytty() on ctl device"); 906 907 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 908 909 return (scr->scr_tty); 910 } 911 912 int 913 wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 914 { 915 struct wsdisplay_softc *sc; 916 struct tty *tp; 917 int error; 918 struct wsscreen *scr; 919 920 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 921 922 #ifdef WSDISPLAY_COMPAT_USL 923 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 924 if (error != EPASSTHROUGH) 925 return (error); 926 #endif 927 928 if (ISWSDISPLAYSTAT(dev)) 929 return (wsdisplay_stat_ioctl(sc, cmd, data, flag, p)); 930 931 if (ISWSDISPLAYCTL(dev)) 932 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 933 934 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 935 936 if (WSSCREEN_HAS_TTY(scr)) { 937 tp = scr->scr_tty; 938 939 /* printf("disc\n"); */ 940 /* do the line discipline ioctls first */ 941 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 942 if (error != EPASSTHROUGH) 943 return (error); 944 945 /* printf("tty\n"); */ 946 /* then the tty ioctls */ 947 error = ttioctl(tp, cmd, data, flag, p); 948 if (error != EPASSTHROUGH) 949 return (error); 950 } 951 952 #ifdef WSDISPLAY_COMPAT_USL 953 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 954 if (error != EPASSTHROUGH) 955 return (error); 956 #endif 957 958 return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)); 959 } 960 961 int 962 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp) 963 { 964 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 965 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 966 (caddr_t)dp, 0, NULL)); 967 } 968 969 int 970 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 971 u_long cmd, caddr_t data, int flag, struct proc *p) 972 { 973 int error; 974 char namebuf[16]; 975 struct wsdisplay_font fd; 976 977 #if NWSKBD > 0 978 struct wsevsrc *inp; 979 980 #ifdef WSDISPLAY_COMPAT_RAWKBD 981 switch (cmd) { 982 case WSKBDIO_SETMODE: 983 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 984 return (wsdisplay_update_rawkbd(sc, scr)); 985 case WSKBDIO_GETMODE: 986 *(int *)data = (scr->scr_rawkbd ? 987 WSKBD_RAW : WSKBD_TRANSLATED); 988 return (0); 989 } 990 #endif 991 inp = sc->sc_input; 992 if (inp == NULL) 993 return (ENXIO); 994 error = wsevsrc_display_ioctl(inp, cmd, data, flag, p); 995 if (error != EPASSTHROUGH) 996 return (error); 997 #endif /* NWSKBD > 0 */ 998 999 switch (cmd) { 1000 case WSDISPLAYIO_GMODE: 1001 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ? 1002 WSDISPLAYIO_MODE_MAPPED : 1003 WSDISPLAYIO_MODE_EMUL); 1004 return (0); 1005 1006 case WSDISPLAYIO_SMODE: 1007 #define d (*(int *)data) 1008 if (d != WSDISPLAYIO_MODE_EMUL && 1009 d != WSDISPLAYIO_MODE_MAPPED) 1010 return (EINVAL); 1011 1012 if (WSSCREEN_HAS_EMULATOR(scr)) { 1013 scr->scr_flags &= ~SCR_GRAPHICS; 1014 if (d == WSDISPLAYIO_MODE_MAPPED) 1015 scr->scr_flags |= SCR_GRAPHICS; 1016 } else if (d == WSDISPLAYIO_MODE_EMUL) 1017 return (EINVAL); 1018 1019 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1020 flag, p); 1021 1022 return (0); 1023 #undef d 1024 1025 case WSDISPLAYIO_SFONT: 1026 #define d ((struct wsdisplay_usefontdata *)data) 1027 if (!sc->sc_accessops->load_font) 1028 return (EINVAL); 1029 if (d->name) { 1030 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0); 1031 if (error) 1032 return (error); 1033 fd.name = namebuf; 1034 } else 1035 fd.name = 0; 1036 fd.data = 0; 1037 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 1038 scr->scr_dconf->emulcookie, &fd); 1039 if (!error && WSSCREEN_HAS_EMULATOR(scr)) 1040 (*scr->scr_dconf->wsemul->reset) 1041 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 1042 return (error); 1043 #undef d 1044 1045 #if defined(WSDISPLAY_CHARFUNCS) 1046 case WSDISPLAYIO_GETWSCHAR: 1047 #define d ((struct wsdisplay_char *)data) 1048 if (!sc->sc_accessops->getwschar) 1049 return (EINVAL); 1050 return ((*sc->sc_accessops->getwschar) 1051 (scr->scr_dconf->emulcookie, d)); 1052 #undef d 1053 1054 case WSDISPLAYIO_PUTWSCHAR: 1055 #define d ((struct wsdisplay_char *)data) 1056 if (!sc->sc_accessops->putwschar) 1057 return (EINVAL); 1058 return ((*sc->sc_accessops->putwschar) 1059 (scr->scr_dconf->emulcookie, d)); 1060 #undef d 1061 return 1; 1062 #endif /* WSDISPLAY_CHARFUNCS */ 1063 1064 } 1065 1066 /* check ioctls for display */ 1067 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1068 flag, p)); 1069 } 1070 1071 int 1072 wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 1073 int flag, struct proc *p) 1074 { 1075 switch (cmd) { 1076 case WSDISPLAYIO_GETACTIVESCREEN: 1077 *(int*)data = wsdisplay_getactivescreen(sc); 1078 return (0); 1079 } 1080 1081 return (EPASSTHROUGH); 1082 } 1083 1084 int 1085 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 1086 int flag, struct proc *p) 1087 { 1088 int error; 1089 char *type, typebuf[16], *emul, emulbuf[16]; 1090 void *buf; 1091 u_int fontsz; 1092 #if defined(COMPAT_14) && NWSKBD > 0 1093 struct wsmux_device wsmuxdata; 1094 #endif 1095 #if NWSKBD > 0 1096 struct wsevsrc *inp; 1097 #endif 1098 1099 switch (cmd) { 1100 case WSDISPLAYIO_ADDSCREEN: 1101 #define d ((struct wsdisplay_addscreendata *)data) 1102 if (d->screentype) { 1103 error = copyinstr(d->screentype, typebuf, 1104 sizeof(typebuf), 0); 1105 if (error) 1106 return (error); 1107 type = typebuf; 1108 } else 1109 type = 0; 1110 if (d->emul) { 1111 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0); 1112 if (error) 1113 return (error); 1114 emul = emulbuf; 1115 } else 1116 emul = 0; 1117 1118 if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0) 1119 wsdisplay_addscreen_print(sc, d->idx, 0); 1120 return (error); 1121 #undef d 1122 case WSDISPLAYIO_DELSCREEN: 1123 #define d ((struct wsdisplay_delscreendata *)data) 1124 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1125 #undef d 1126 case WSDISPLAYIO_LDFONT: 1127 #define d ((struct wsdisplay_font *)data) 1128 if (!sc->sc_accessops->load_font) 1129 return (EINVAL); 1130 if (d->name) { 1131 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0); 1132 if (error) 1133 return (error); 1134 d->name = typebuf; 1135 } else 1136 d->name = "loaded"; /* ??? */ 1137 fontsz = d->fontheight * d->stride * d->numchars; 1138 if (fontsz > WSDISPLAY_MAXFONTSZ) 1139 return (EINVAL); 1140 1141 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1142 error = copyin(d->data, buf, fontsz); 1143 if (error) { 1144 free(buf, M_DEVBUF); 1145 return (error); 1146 } 1147 d->data = buf; 1148 error = 1149 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1150 free(buf, M_DEVBUF); 1151 #undef d 1152 return (error); 1153 1154 #if NWSKBD > 0 1155 #ifdef COMPAT_14 1156 case _O_WSDISPLAYIO_SETKEYBOARD: 1157 #define d ((struct wsdisplay_kbddata *)data) 1158 inp = sc->sc_input; 1159 if (inp == NULL) 1160 return (ENXIO); 1161 switch (d->op) { 1162 case _O_WSDISPLAY_KBD_ADD: 1163 if (d->idx == -1) { 1164 d->idx = wskbd_pickfree(); 1165 if (d->idx == -1) 1166 return (ENXIO); 1167 } 1168 wsmuxdata.type = WSMUX_KBD; 1169 wsmuxdata.idx = d->idx; 1170 return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE, 1171 &wsmuxdata, flag, p)); 1172 case _O_WSDISPLAY_KBD_DEL: 1173 wsmuxdata.type = WSMUX_KBD; 1174 wsmuxdata.idx = d->idx; 1175 return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE, 1176 &wsmuxdata, flag, p)); 1177 default: 1178 return (EINVAL); 1179 } 1180 #undef d 1181 #endif 1182 1183 case WSMUXIO_ADD_DEVICE: 1184 #define d ((struct wsmux_device *)data) 1185 if (d->idx == -1 && d->type == WSMUX_KBD) 1186 d->idx = wskbd_pickfree(); 1187 #undef d 1188 /* fall into */ 1189 case WSMUXIO_INJECTEVENT: 1190 case WSMUXIO_REMOVE_DEVICE: 1191 case WSMUXIO_LIST_DEVICES: 1192 inp = sc->sc_input; 1193 if (inp == NULL) 1194 return (ENXIO); 1195 return (wsevsrc_ioctl(inp, cmd, data, flag, p)); 1196 #endif /* NWSKBD > 0 */ 1197 1198 } 1199 return (EPASSTHROUGH); 1200 } 1201 1202 int 1203 wsdisplay_stat_inject(struct device *dev, u_int type, int value) 1204 { 1205 struct wsdisplay_softc *sc = (struct wsdisplay_softc *) dev; 1206 struct wseventvar *evar; 1207 struct wscons_event *ev; 1208 struct timeval thistime; 1209 int put; 1210 1211 evar = &sc->evar; 1212 1213 if (evar == NULL) 1214 return (0); 1215 1216 if (evar->q == NULL) 1217 return (1); 1218 1219 put = evar->put; 1220 ev = &evar->q[put]; 1221 put = (put + 1) % WSEVENT_QSIZE; 1222 if (put == evar->get) { 1223 log(LOG_WARNING, "wsdisplay: event queue overflow\n"); 1224 return (1); 1225 } 1226 ev->type = type; 1227 ev->value = value; 1228 microtime(&thistime); 1229 TIMEVAL_TO_TIMESPEC(&thistime, &ev->time); 1230 evar->put = put; 1231 WSEVENT_WAKEUP(evar); 1232 1233 return (0); 1234 } 1235 1236 paddr_t 1237 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1238 { 1239 struct wsdisplay_softc *sc = 1240 device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev)); 1241 struct wsscreen *scr; 1242 1243 if (ISWSDISPLAYSTAT(dev)) 1244 return (-1); 1245 1246 if (ISWSDISPLAYCTL(dev)) 1247 return (-1); 1248 1249 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1250 1251 if (!(scr->scr_flags & SCR_GRAPHICS)) 1252 return (-1); 1253 1254 /* pass mmap to display */ 1255 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1256 } 1257 1258 void 1259 wsdisplaystart(struct tty *tp) 1260 { 1261 struct wsdisplay_softc *sc; 1262 struct wsscreen *scr; 1263 int s, n; 1264 u_char *buf; 1265 1266 s = spltty(); 1267 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1268 splx(s); 1269 return; 1270 } 1271 sc = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev)); 1272 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1273 if (scr->scr_hold_screen) { 1274 tp->t_state |= TS_TIMEOUT; 1275 splx(s); 1276 return; 1277 } 1278 tp->t_state |= TS_BUSY; 1279 splx(s); 1280 1281 /* 1282 * Drain output from ring buffer. 1283 * The output will normally be in one contiguous chunk, but when the 1284 * ring wraps, it will be in two pieces.. one at the end of the ring, 1285 * the other at the start. For performance, rather than loop here, 1286 * we output one chunk, see if there's another one, and if so, output 1287 * it too. 1288 */ 1289 1290 n = ndqb(&tp->t_outq, 0); 1291 buf = tp->t_outq.c_cf; 1292 1293 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1294 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1295 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1296 buf, n, 0); 1297 } 1298 ndflush(&tp->t_outq, n); 1299 1300 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1301 buf = tp->t_outq.c_cf; 1302 1303 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1304 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1305 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1306 buf, n, 0); 1307 } 1308 ndflush(&tp->t_outq, n); 1309 } 1310 1311 s = spltty(); 1312 tp->t_state &= ~TS_BUSY; 1313 /* Come back if there's more to do */ 1314 if (tp->t_outq.c_cc) { 1315 tp->t_state |= TS_TIMEOUT; 1316 callout_reset(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1, 1317 ttrstrt, tp); 1318 } 1319 if (tp->t_outq.c_cc <= tp->t_lowat) { 1320 if (tp->t_state&TS_ASLEEP) { 1321 tp->t_state &= ~TS_ASLEEP; 1322 wakeup(&tp->t_outq); 1323 } 1324 selwakeup(&tp->t_wsel); 1325 } 1326 splx(s); 1327 } 1328 1329 void 1330 wsdisplaystop(struct tty *tp, int flag) 1331 { 1332 int s; 1333 1334 s = spltty(); 1335 if (ISSET(tp->t_state, TS_BUSY)) 1336 if (!ISSET(tp->t_state, TS_TTSTOP)) 1337 SET(tp->t_state, TS_FLUSH); 1338 splx(s); 1339 } 1340 1341 /* Set line parameters. */ 1342 int 1343 wsdisplayparam(struct tty *tp, struct termios *t) 1344 { 1345 1346 tp->t_ispeed = t->c_ispeed; 1347 tp->t_ospeed = t->c_ospeed; 1348 tp->t_cflag = t->c_cflag; 1349 return 0; 1350 } 1351 1352 /* 1353 * Callbacks for the emulation code. 1354 */ 1355 void 1356 wsdisplay_emulbell(void *v) 1357 { 1358 struct wsscreen *scr = v; 1359 1360 if (scr == NULL) /* console, before real attach */ 1361 return; 1362 1363 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1364 return; 1365 1366 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1367 FWRITE, NULL); 1368 } 1369 1370 void 1371 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1372 { 1373 struct wsscreen *scr = v; 1374 struct tty *tp; 1375 1376 if (v == NULL) /* console, before real attach */ 1377 return; 1378 1379 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1380 return; 1381 if (!WSSCREEN_HAS_TTY(scr)) 1382 return; 1383 1384 tp = scr->scr_tty; 1385 while (count-- > 0) 1386 (*tp->t_linesw->l_rint)(*data++, tp); 1387 }; 1388 1389 /* 1390 * Calls from the keyboard interface. 1391 */ 1392 void 1393 wsdisplay_kbdinput(struct device *dev, keysym_t ks) 1394 { 1395 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1396 struct wsscreen *scr; 1397 char *dp; 1398 int count; 1399 struct tty *tp; 1400 1401 KASSERT(sc != NULL); 1402 1403 scr = sc->sc_focus; 1404 1405 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1406 return; 1407 1408 tp = scr->scr_tty; 1409 1410 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1411 (*tp->t_linesw->l_rint)(KS_VALUE(ks), tp); 1412 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1413 count = (*scr->scr_dconf->wsemul->translate) 1414 (scr->scr_dconf->wsemulcookie, ks, &dp); 1415 while (count-- > 0) 1416 (*tp->t_linesw->l_rint)(*dp++, tp); 1417 } 1418 } 1419 1420 #if defined(WSDISPLAY_COMPAT_RAWKBD) 1421 int 1422 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1423 { 1424 #if NWSKBD > 0 1425 int s, raw, data, error; 1426 struct wsevsrc *inp; 1427 1428 s = spltty(); 1429 1430 raw = (scr ? scr->scr_rawkbd : 0); 1431 1432 if (scr != sc->sc_focus || 1433 sc->sc_rawkbd == raw) { 1434 splx(s); 1435 return (0); 1436 } 1437 1438 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1439 inp = sc->sc_input; 1440 if (inp == NULL) 1441 return (ENXIO); 1442 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0); 1443 if (!error) 1444 sc->sc_rawkbd = raw; 1445 splx(s); 1446 return (error); 1447 #else 1448 return (0); 1449 #endif 1450 } 1451 #endif 1452 1453 int 1454 wsdisplay_switch3(void *arg, int error, int waitok) 1455 { 1456 struct wsdisplay_softc *sc = arg; 1457 int no; 1458 struct wsscreen *scr; 1459 1460 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1461 printf("wsdisplay_switch3: not switching\n"); 1462 return (EINVAL); 1463 } 1464 1465 no = sc->sc_screenwanted; 1466 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1467 panic("wsdisplay_switch3: invalid screen %d", no); 1468 scr = sc->sc_scr[no]; 1469 if (!scr) { 1470 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1471 error = ENXIO; 1472 } 1473 1474 if (error) { 1475 /* try to recover, avoid recursion */ 1476 1477 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1478 printf("wsdisplay_switch3: giving up\n"); 1479 sc->sc_focus = 0; 1480 #ifdef WSDISPLAY_COMPAT_RAWKBD 1481 wsdisplay_update_rawkbd(sc, 0); 1482 #endif 1483 sc->sc_flags &= ~SC_SWITCHPENDING; 1484 return (error); 1485 } 1486 1487 sc->sc_screenwanted = sc->sc_oldscreen; 1488 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1489 return (wsdisplay_switch1(arg, 0, waitok)); 1490 } 1491 1492 sc->sc_flags &= ~SC_SWITCHPENDING; 1493 1494 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1495 wakeup(scr); 1496 return (error); 1497 } 1498 1499 int 1500 wsdisplay_switch2(void *arg, int error, int waitok) 1501 { 1502 struct wsdisplay_softc *sc = arg; 1503 int no; 1504 struct wsscreen *scr; 1505 1506 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1507 printf("wsdisplay_switch2: not switching\n"); 1508 return (EINVAL); 1509 } 1510 1511 no = sc->sc_screenwanted; 1512 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1513 panic("wsdisplay_switch2: invalid screen %d", no); 1514 scr = sc->sc_scr[no]; 1515 if (!scr) { 1516 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1517 error = ENXIO; 1518 } 1519 1520 if (error) { 1521 /* try to recover, avoid recursion */ 1522 1523 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1524 printf("wsdisplay_switch2: giving up\n"); 1525 sc->sc_focus = 0; 1526 sc->sc_flags &= ~SC_SWITCHPENDING; 1527 return (error); 1528 } 1529 1530 sc->sc_screenwanted = sc->sc_oldscreen; 1531 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1532 return (wsdisplay_switch1(arg, 0, waitok)); 1533 } 1534 1535 sc->sc_focusidx = no; 1536 sc->sc_focus = scr; 1537 1538 #ifdef WSDISPLAY_COMPAT_RAWKBD 1539 (void) wsdisplay_update_rawkbd(sc, scr); 1540 #endif 1541 /* keyboard map??? */ 1542 1543 #define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3) 1544 if (scr->scr_syncops) { 1545 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1546 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1547 if (error == EAGAIN) { 1548 /* switch will be done asynchronously */ 1549 return (0); 1550 } 1551 } 1552 1553 return (wsdisplay_switch3(sc, error, waitok)); 1554 } 1555 1556 int 1557 wsdisplay_switch1(void *arg, int error, int waitok) 1558 { 1559 struct wsdisplay_softc *sc = arg; 1560 int no; 1561 struct wsscreen *scr; 1562 1563 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1564 printf("wsdisplay_switch1: not switching\n"); 1565 return (EINVAL); 1566 } 1567 1568 no = sc->sc_screenwanted; 1569 if (no == WSDISPLAY_NULLSCREEN) { 1570 sc->sc_flags &= ~SC_SWITCHPENDING; 1571 if (!error) { 1572 sc->sc_focus = 0; 1573 } 1574 wakeup(sc); 1575 return (error); 1576 } 1577 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1578 panic("wsdisplay_switch1: invalid screen %d", no); 1579 scr = sc->sc_scr[no]; 1580 if (!scr) { 1581 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1582 error = ENXIO; 1583 } 1584 1585 if (error) { 1586 sc->sc_flags &= ~SC_SWITCHPENDING; 1587 return (error); 1588 } 1589 1590 #define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2) 1591 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1592 scr->scr_dconf->emulcookie, 1593 waitok, 1594 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1595 if (error == EAGAIN) { 1596 /* switch will be done asynchronously */ 1597 return (0); 1598 } 1599 1600 return (wsdisplay_switch2(sc, error, waitok)); 1601 } 1602 1603 int 1604 wsdisplay_switch(struct device *dev, int no, int waitok) 1605 { 1606 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1607 int s, res = 0; 1608 struct wsscreen *scr; 1609 1610 if (no != WSDISPLAY_NULLSCREEN && 1611 (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])) 1612 return (ENXIO); 1613 1614 wsdisplay_stat_inject(dev, WSCONS_EVENT_SCREEN_SWITCH, no); 1615 1616 s = spltty(); 1617 1618 if ((sc->sc_focus && no == sc->sc_focusidx) || 1619 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1620 splx(s); 1621 return (0); 1622 } 1623 1624 if (sc->sc_flags & SC_SWITCHPENDING) { 1625 splx(s); 1626 return (EBUSY); 1627 } 1628 1629 sc->sc_flags |= SC_SWITCHPENDING; 1630 sc->sc_screenwanted = no; 1631 1632 splx(s); 1633 1634 scr = sc->sc_focus; 1635 if (!scr) { 1636 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1637 return (wsdisplay_switch1(sc, 0, waitok)); 1638 } else 1639 sc->sc_oldscreen = sc->sc_focusidx; 1640 1641 #define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1) 1642 if (scr->scr_syncops) { 1643 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1644 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1645 if (res == EAGAIN) { 1646 /* switch will be done asynchronously */ 1647 return (0); 1648 } 1649 } else if (scr->scr_flags & SCR_GRAPHICS) { 1650 /* no way to save state */ 1651 res = EBUSY; 1652 } 1653 1654 return (wsdisplay_switch1(sc, res, waitok)); 1655 } 1656 1657 void 1658 wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op) 1659 { 1660 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1661 struct wsscreen *scr; 1662 1663 KASSERT(sc != NULL); 1664 scr = sc->sc_focus; 1665 1666 if (!scr) 1667 return; 1668 1669 switch (op) { 1670 case WSDISPLAY_RESETEMUL: 1671 if (!WSSCREEN_HAS_EMULATOR(scr)) 1672 break; 1673 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1674 WSEMUL_RESET); 1675 break; 1676 case WSDISPLAY_RESETCLOSE: 1677 wsdisplay_closescreen(sc, scr); 1678 break; 1679 } 1680 } 1681 1682 /* 1683 * Interface for (external) VT switch / process synchronization code 1684 */ 1685 int 1686 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1687 void *cookie) 1688 { 1689 if (scr->scr_syncops) { 1690 /* 1691 * The screen is already claimed. 1692 * Check if the owner is still alive. 1693 */ 1694 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1695 return (EBUSY); 1696 } 1697 scr->scr_syncops = ops; 1698 scr->scr_synccookie = cookie; 1699 return (0); 1700 } 1701 1702 int 1703 wsscreen_detach_sync(struct wsscreen *scr) 1704 { 1705 if (!scr->scr_syncops) 1706 return (EINVAL); 1707 scr->scr_syncops = 0; 1708 return (0); 1709 } 1710 1711 int 1712 wsscreen_lookup_sync(struct wsscreen *scr, 1713 const struct wscons_syncops *ops, /* used as ID */ 1714 void **cookiep) 1715 { 1716 if (!scr->scr_syncops || ops != scr->scr_syncops) 1717 return (EINVAL); 1718 *cookiep = scr->scr_synccookie; 1719 return (0); 1720 } 1721 1722 /* 1723 * Interface to virtual screen stuff 1724 */ 1725 int 1726 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 1727 { 1728 return (WSDISPLAY_MAXSCREEN - 1); 1729 } 1730 1731 int 1732 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 1733 { 1734 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1735 return (EINVAL); 1736 if (!sc->sc_scr[idx]) 1737 return (ENXIO); 1738 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1739 } 1740 1741 int 1742 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 1743 { 1744 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1745 } 1746 1747 int 1748 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 1749 { 1750 struct wsscreen *scr; 1751 int s, res = 0; 1752 1753 if (no == WSDISPLAY_NULLSCREEN) { 1754 s = spltty(); 1755 while (sc->sc_focus && res == 0) { 1756 res = tsleep(sc, PCATCH, "wswait", 0); 1757 } 1758 splx(s); 1759 return (res); 1760 } 1761 1762 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1763 return (ENXIO); 1764 scr = sc->sc_scr[no]; 1765 if (!scr) 1766 return (ENXIO); 1767 1768 s = spltty(); 1769 if (scr != sc->sc_focus) { 1770 scr->scr_flags |= SCR_WAITACTIVE; 1771 res = tsleep(scr, PCATCH, "wswait", 0); 1772 if (scr != sc->sc_scr[no]) 1773 res = ENXIO; /* disappeared in the meantime */ 1774 else 1775 scr->scr_flags &= ~SCR_WAITACTIVE; 1776 } 1777 splx(s); 1778 return (res); 1779 } 1780 1781 void 1782 wsdisplay_kbdholdscreen(struct device *dev, int hold) 1783 { 1784 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1785 struct wsscreen *scr; 1786 1787 scr = sc->sc_focus; 1788 1789 if (hold) 1790 scr->scr_hold_screen = 1; 1791 else { 1792 scr->scr_hold_screen = 0; 1793 callout_reset(&scr->scr_tty->t_rstrt_ch, 0, 1794 ttrstrt, scr->scr_tty); /* "immediate" */ 1795 } 1796 } 1797 1798 #if NWSKBD > 0 1799 void 1800 wsdisplay_set_console_kbd(struct wsevsrc *src) 1801 { 1802 if (wsdisplay_console_device == NULL) { 1803 src->me_dispdv = NULL; 1804 return; 1805 } 1806 #if NWSMUX > 0 1807 if (wsmux_attach_sc((struct wsmux_softc *) 1808 wsdisplay_console_device->sc_input, src)) { 1809 src->me_dispdv = NULL; 1810 return; 1811 } 1812 #else 1813 wsdisplay_console_device->sc_input = src; 1814 #endif 1815 src->me_dispdv = &wsdisplay_console_device->sc_dv; 1816 } 1817 #endif /* NWSKBD > 0 */ 1818 1819 /* 1820 * Console interface. 1821 */ 1822 void 1823 wsdisplay_cnputc(dev_t dev, int i) 1824 { 1825 struct wsscreen_internal *dc; 1826 char c = i; 1827 1828 if (!wsdisplay_console_initted) 1829 return; 1830 1831 if (wsdisplay_console_device != NULL && 1832 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1833 return; 1834 1835 dc = &wsdisplay_console_conf; 1836 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1837 } 1838 1839 static int 1840 wsdisplay_getc_dummy(dev_t dev) 1841 { 1842 /* panic? */ 1843 return (0); 1844 } 1845 1846 static void 1847 wsdisplay_pollc(dev_t dev, int on) 1848 { 1849 1850 wsdisplay_cons_pollmode = on; 1851 1852 /* notify to fb drivers */ 1853 if (wsdisplay_console_device != NULL && 1854 wsdisplay_console_device->sc_accessops->pollc != NULL) 1855 (*wsdisplay_console_device->sc_accessops->pollc) 1856 (wsdisplay_console_device->sc_accesscookie, on); 1857 1858 /* notify to kbd drivers */ 1859 if (wsdisplay_cons_kbd_pollc) 1860 (*wsdisplay_cons_kbd_pollc)(NODEV, on); 1861 } 1862 1863 void 1864 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 1865 void (*bell)(dev_t, u_int, u_int, u_int)) 1866 { 1867 wsdisplay_cons.cn_getc = get; 1868 wsdisplay_cons.cn_bell = bell; 1869 wsdisplay_cons_kbd_pollc = poll; 1870 } 1871 1872 void 1873 wsdisplay_unset_cons_kbd(void) 1874 { 1875 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1876 wsdisplay_cons.cn_bell = NULL; 1877 wsdisplay_cons_kbd_pollc = 0; 1878 } 1879 1880 /* 1881 * Switch the console display to it's first screen. 1882 */ 1883 void 1884 wsdisplay_switchtoconsole(void) 1885 { 1886 struct wsdisplay_softc *sc; 1887 struct wsscreen *scr; 1888 1889 if (wsdisplay_console_device != NULL) { 1890 sc = wsdisplay_console_device; 1891 scr = sc->sc_scr[0]; 1892 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1893 scr->scr_dconf->emulcookie, 1894 0, NULL, NULL); 1895 } 1896 } 1897 1898 /* 1899 * Switch the console at shutdown. 1900 */ 1901 static void 1902 wsdisplay_shutdownhook(void *arg) 1903 { 1904 1905 wsdisplay_switchtoconsole(); 1906 } 1907