1 /* $OpenBSD: wsdisplay.c,v 1.94 2009/09/14 04:10:42 miod Exp $ */ 2 /* $NetBSD: wsdisplay.c,v 1.82 2005/02/27 00:27:52 perry Exp $ */ 3 4 /* 5 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef SMALL_KERNEL 35 #define WSMOUSED_SUPPORT 36 #define BURNER_SUPPORT 37 #define SCROLLBACK_SUPPORT 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 #include <sys/ioctl.h> 44 #include <sys/kernel.h> 45 #include <sys/proc.h> 46 #include <sys/malloc.h> 47 #include <sys/syslog.h> 48 #include <sys/systm.h> 49 #include <sys/tty.h> 50 #include <sys/signalvar.h> 51 #include <sys/errno.h> 52 #include <sys/fcntl.h> 53 #include <sys/vnode.h> 54 #include <sys/timeout.h> 55 #include <sys/poll.h> 56 57 #include <dev/wscons/wsconsio.h> 58 #include <dev/wscons/wsdisplayvar.h> 59 #include <dev/wscons/wsksymvar.h> 60 #include <dev/wscons/wsksymdef.h> 61 #include <dev/wscons/wsemulvar.h> 62 #include <dev/wscons/wscons_callbacks.h> 63 #include <dev/cons.h> 64 65 #include "wsdisplay.h" 66 #include "wskbd.h" 67 #include "wsmouse.h" 68 #include "wsmux.h" 69 70 #if NWSKBD > 0 71 #include <dev/wscons/wseventvar.h> 72 #include <dev/wscons/wsmuxvar.h> 73 #endif 74 75 #if NWSMOUSE > 0 76 #include <dev/wscons/wsmousevar.h> 77 #endif 78 79 #include "wsmoused.h" 80 81 #if NWSMOUSE > 0 82 extern struct cfdriver wsmouse_cd; 83 #endif /* NWSMOUSE > 0 */ 84 85 struct wsscreen_internal { 86 const struct wsdisplay_emulops *emulops; 87 void *emulcookie; 88 89 const struct wsscreen_descr *scrdata; 90 91 const struct wsemul_ops *wsemul; 92 void *wsemulcookie; 93 }; 94 95 struct wsscreen { 96 struct wsscreen_internal *scr_dconf; 97 98 struct tty *scr_tty; 99 int scr_hold_screen; /* hold tty output */ 100 101 int scr_flags; 102 #define SCR_OPEN 1 /* is it open? */ 103 #define SCR_WAITACTIVE 2 /* someone waiting on activation */ 104 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */ 105 #define SCR_DUMBFB 8 /* in use as dumb fb (iff SCR_GRAPHICS) */ 106 107 #ifdef WSDISPLAY_COMPAT_USL 108 const struct wscons_syncops *scr_syncops; 109 void *scr_synccookie; 110 #endif 111 112 #ifdef WSDISPLAY_COMPAT_RAWKBD 113 int scr_rawkbd; 114 #endif 115 116 struct wsdisplay_softc *sc; 117 118 #ifdef WSMOUSED_SUPPORT 119 /* mouse console support via wsmoused(8) */ 120 u_int mouse; /* mouse cursor position */ 121 u_int cursor; /* selection cursor position (if 122 different from mouse cursor pos) */ 123 u_int cpy_start; /* position of the copy start mark*/ 124 u_int cpy_end; /* position of the copy end mark */ 125 u_int orig_start; /* position of the original sel. start*/ 126 u_int orig_end; /* position of the original sel. end */ 127 128 u_int mouse_flags; /* flags, status of the mouse */ 129 #define MOUSE_VISIBLE 0x01 /* flag, the mouse cursor is visible */ 130 #define SEL_EXISTS 0x02 /* flag, a selection exists */ 131 #define SEL_IN_PROGRESS 0x04 /* flag, a selection is in progress */ 132 #define SEL_EXT_AFTER 0x08 /* flag, selection is extended after */ 133 #define BLANK_TO_EOL 0x10 /* flag, there are only blanks 134 characters to eol */ 135 #define SEL_BY_CHAR 0x20 /* flag, select character by character*/ 136 #define SEL_BY_WORD 0x40 /* flag, select word by word */ 137 #define SEL_BY_LINE 0x80 /* flag, select line by line */ 138 139 #define IS_MOUSE_VISIBLE(scr) ((scr)->mouse_flags & MOUSE_VISIBLE) 140 #define IS_SEL_EXISTS(scr) ((scr)->mouse_flags & SEL_EXISTS) 141 #define IS_SEL_IN_PROGRESS(scr) ((scr)->mouse_flags & SEL_IN_PROGRESS) 142 #define IS_SEL_EXT_AFTER(scr) ((scr)->mouse_flags & SEL_EXT_AFTER) 143 #define IS_BLANK_TO_EOL(scr) ((scr)->mouse_flags & BLANK_TO_EOL) 144 #define IS_SEL_BY_CHAR(scr) ((scr)->mouse_flags & SEL_BY_CHAR) 145 #define IS_SEL_BY_WORD(scr) ((scr)->mouse_flags & SEL_BY_WORD) 146 #define IS_SEL_BY_LINE(scr) ((scr)->mouse_flags & SEL_BY_LINE) 147 #endif /* WSMOUSED_SUPPORT */ 148 }; 149 150 struct wsscreen *wsscreen_attach(struct wsdisplay_softc *, int, const char *, 151 const struct wsscreen_descr *, void *, int, int, long); 152 void wsscreen_detach(struct wsscreen *); 153 int wsdisplay_addscreen(struct wsdisplay_softc *, int, const char *, 154 const char *); 155 int wsdisplay_getscreen(struct wsdisplay_softc *, 156 struct wsdisplay_addscreendata *); 157 void wsdisplay_shutdownhook(void *); 158 void wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int); 159 void wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *); 160 int wsdisplay_delscreen(struct wsdisplay_softc *, int, int); 161 void wsdisplay_burner(void *v); 162 163 struct wsdisplay_softc { 164 struct device sc_dv; 165 166 const struct wsdisplay_accessops *sc_accessops; 167 void *sc_accesscookie; 168 169 const struct wsscreen_list *sc_scrdata; 170 171 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN]; 172 int sc_focusidx; /* available only if sc_focus isn't null */ 173 struct wsscreen *sc_focus; 174 175 #ifdef BURNER_SUPPORT 176 struct timeout sc_burner; 177 int sc_burnoutintvl; 178 int sc_burninintvl; 179 int sc_burnout; 180 int sc_burnman; 181 int sc_burnflags; 182 #endif 183 184 struct wsdisplay_font sc_fonts[WSDISPLAY_MAXFONT]; 185 186 int sc_isconsole; 187 188 int sc_flags; 189 #define SC_SWITCHPENDING 0x01 190 #define SC_PASTE_AVAIL 0x02 191 int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */ 192 193 #if NWSKBD > 0 194 struct wsevsrc *sc_input; 195 #ifdef WSDISPLAY_COMPAT_RAWKBD 196 int sc_rawkbd; 197 #endif 198 #endif /* NWSKBD > 0 */ 199 200 #ifdef WSMOUSED_SUPPORT 201 dev_t wsmoused_dev; /* device opened by wsmoused(8), when active */ 202 int wsmoused_sleep; /* true when wsmoused(8) is sleeping */ 203 204 char *sc_copybuffer; 205 u_int sc_copybuffer_size; 206 #endif 207 }; 208 209 extern struct cfdriver wsdisplay_cd; 210 211 /* Autoconfiguration definitions. */ 212 int wsdisplay_emul_match(struct device *, void *, void *); 213 void wsdisplay_emul_attach(struct device *, struct device *, void *); 214 int wsdisplay_emul_detach(struct device *, int); 215 216 struct cfdriver wsdisplay_cd = { 217 NULL, "wsdisplay", DV_TTY 218 }; 219 220 struct cfattach wsdisplay_emul_ca = { 221 sizeof(struct wsdisplay_softc), wsdisplay_emul_match, 222 wsdisplay_emul_attach, wsdisplay_emul_detach 223 }; 224 225 void wsdisplaystart(struct tty *); 226 int wsdisplayparam(struct tty *, struct termios *); 227 228 /* Internal macros, functions, and variables. */ 229 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8) 230 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff) 231 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255) 232 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen)) 233 234 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL) 235 236 void wsdisplay_common_attach(struct wsdisplay_softc *sc, 237 int console, int mux, const struct wsscreen_list *, 238 const struct wsdisplay_accessops *accessops, 239 void *accesscookie, u_int defaultscreens); 240 int wsdisplay_common_detach(struct wsdisplay_softc *, int); 241 void wsdisplay_kbdholdscr(struct wsscreen *, int); 242 243 #ifdef WSDISPLAY_COMPAT_RAWKBD 244 int wsdisplay_update_rawkbd(struct wsdisplay_softc *, struct wsscreen *); 245 #endif 246 247 int wsdisplay_console_initted; 248 struct wsdisplay_softc *wsdisplay_console_device; 249 struct wsscreen_internal wsdisplay_console_conf; 250 251 int wsdisplay_getc_dummy(dev_t); 252 void wsdisplay_pollc(dev_t, int); 253 254 int wsdisplay_cons_pollmode; 255 void (*wsdisplay_cons_kbd_pollc)(dev_t, int); 256 257 struct consdev wsdisplay_cons = { 258 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc, 259 wsdisplay_pollc, NULL, NODEV, CN_LOWPRI 260 }; 261 262 #ifndef WSDISPLAY_DEFAULTSCREENS 263 #define WSDISPLAY_DEFAULTSCREENS 1 264 #endif 265 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS; 266 267 int wsdisplay_switch1(void *, int, int); 268 int wsdisplay_switch2(void *, int, int); 269 int wsdisplay_switch3(void *, int, int); 270 271 int wsdisplay_clearonclose; 272 273 struct wsscreen * 274 wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul, 275 const struct wsscreen_descr *type, void *cookie, int ccol, int crow, 276 long defattr) 277 { 278 struct wsscreen_internal *dconf; 279 struct wsscreen *scr; 280 281 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_ZERO | M_NOWAIT); 282 if (!scr) 283 return (NULL); 284 285 if (console) { 286 dconf = &wsdisplay_console_conf; 287 /* 288 * Tell the emulation about the callback argument. 289 * The other stuff is already there. 290 */ 291 (void)(*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0); 292 } else { /* not console */ 293 dconf = malloc(sizeof(struct wsscreen_internal), 294 M_DEVBUF, M_NOWAIT); 295 if (dconf == NULL) 296 goto fail; 297 dconf->emulops = type->textops; 298 dconf->emulcookie = cookie; 299 if (dconf->emulops == NULL || 300 (dconf->wsemul = wsemul_pick(emul)) == NULL) 301 goto fail; 302 dconf->wsemulcookie = (*dconf->wsemul->attach)(0, type, cookie, 303 ccol, crow, scr, defattr); 304 if (dconf->wsemulcookie == NULL) 305 goto fail; 306 dconf->scrdata = type; 307 } 308 309 scr->scr_dconf = dconf; 310 scr->scr_tty = ttymalloc(); 311 scr->sc = sc; 312 return (scr); 313 314 fail: 315 if (dconf != NULL) 316 free(dconf, M_DEVBUF); 317 free(scr, M_DEVBUF); 318 return (NULL); 319 } 320 321 void 322 wsscreen_detach(struct wsscreen *scr) 323 { 324 int ccol, crow; /* XXX */ 325 326 if (WSSCREEN_HAS_TTY(scr)) { 327 timeout_del(&scr->scr_tty->t_rstrt_to); 328 ttyfree(scr->scr_tty); 329 } 330 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie, 331 &ccol, &crow); 332 free(scr->scr_dconf, M_DEVBUF); 333 free(scr, M_DEVBUF); 334 } 335 336 const struct wsscreen_descr * 337 wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name) 338 { 339 int i; 340 const struct wsscreen_descr *scr; 341 342 KASSERT(scrdata->nscreens > 0); 343 344 if (name == NULL || *name == '\0') 345 return (scrdata->screens[0]); 346 347 for (i = 0; i < scrdata->nscreens; i++) { 348 scr = scrdata->screens[i]; 349 if (!strncmp(name, scr->name, WSSCREEN_NAME_SIZE)) 350 return (scr); 351 } 352 353 return (0); 354 } 355 356 /* 357 * print info about attached screen 358 */ 359 void 360 wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count) 361 { 362 printf("%s: screen %d", sc->sc_dv.dv_xname, idx); 363 if (count > 1) 364 printf("-%d", idx + (count-1)); 365 printf(" added (%s, %s emulation)\n", 366 sc->sc_scr[idx]->scr_dconf->scrdata->name, 367 sc->sc_scr[idx]->scr_dconf->wsemul->name); 368 } 369 370 int 371 wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx, 372 const char *screentype, const char *emul) 373 { 374 const struct wsscreen_descr *scrdesc; 375 int error; 376 void *cookie; 377 int ccol, crow; 378 long defattr; 379 struct wsscreen *scr; 380 int s; 381 382 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 383 return (EINVAL); 384 if (sc->sc_scr[idx] != NULL) 385 return (EBUSY); 386 387 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype); 388 if (!scrdesc) 389 return (ENXIO); 390 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie, 391 scrdesc, &cookie, &ccol, &crow, &defattr); 392 if (error) 393 return (error); 394 395 scr = wsscreen_attach(sc, 0, emul, scrdesc, 396 cookie, ccol, crow, defattr); 397 if (scr == NULL) { 398 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, cookie); 399 return (ENXIO); 400 } 401 402 sc->sc_scr[idx] = scr; 403 404 /* if no screen has focus yet, activate the first we get */ 405 s = spltty(); 406 if (!sc->sc_focus) { 407 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 408 scr->scr_dconf->emulcookie, 0, 0, 0); 409 sc->sc_focusidx = idx; 410 sc->sc_focus = scr; 411 } 412 splx(s); 413 414 #ifdef WSMOUSED_SUPPORT 415 allocate_copybuffer(sc); /* enlarge the copy buffer if necessary */ 416 #endif 417 return (0); 418 } 419 420 int 421 wsdisplay_getscreen(struct wsdisplay_softc *sc, 422 struct wsdisplay_addscreendata *sd) 423 { 424 struct wsscreen *scr; 425 426 if (sd->idx < 0 && sc->sc_focus) 427 sd->idx = sc->sc_focusidx; 428 429 if (sd->idx < 0 || sd->idx >= WSDISPLAY_MAXSCREEN) 430 return (EINVAL); 431 432 scr = sc->sc_scr[sd->idx]; 433 if (scr == NULL) 434 return (ENXIO); 435 436 strncpy(sd->screentype, scr->scr_dconf->scrdata->name, 437 WSSCREEN_NAME_SIZE); 438 strncpy(sd->emul, scr->scr_dconf->wsemul->name, WSEMUL_NAME_SIZE); 439 440 return (0); 441 } 442 443 void 444 wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr) 445 { 446 int maj, mn, idx; 447 448 /* hangup */ 449 if (WSSCREEN_HAS_TTY(scr)) { 450 struct tty *tp = scr->scr_tty; 451 (*linesw[tp->t_line].l_modem)(tp, 0); 452 } 453 454 /* locate the major number */ 455 for (maj = 0; maj < nchrdev; maj++) 456 if (cdevsw[maj].d_open == wsdisplayopen) 457 break; 458 /* locate the screen index */ 459 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++) 460 if (scr == sc->sc_scr[idx]) 461 break; 462 #ifdef DIAGNOSTIC 463 if (idx == WSDISPLAY_MAXSCREEN) 464 panic("wsdisplay_forceclose: bad screen"); 465 #endif 466 467 /* nuke the vnodes */ 468 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx); 469 vdevgone(maj, mn, mn, VCHR); 470 } 471 472 int 473 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags) 474 { 475 struct wsscreen *scr; 476 int s; 477 void *cookie; 478 479 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 480 return (EINVAL); 481 if ((scr = sc->sc_scr[idx]) == NULL) 482 return (ENXIO); 483 484 if (scr->scr_dconf == &wsdisplay_console_conf || 485 #ifdef WSDISPLAY_COMPAT_USL 486 scr->scr_syncops || 487 #endif 488 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE))) 489 return (EBUSY); 490 491 wsdisplay_closescreen(sc, scr); 492 493 /* 494 * delete pointers, so neither device entries 495 * nor keyboard input can reference it anymore 496 */ 497 s = spltty(); 498 if (sc->sc_focus == scr) { 499 sc->sc_focus = 0; 500 #ifdef WSDISPLAY_COMPAT_RAWKBD 501 wsdisplay_update_rawkbd(sc, 0); 502 #endif 503 } 504 sc->sc_scr[idx] = 0; 505 splx(s); 506 507 /* 508 * Wake up processes waiting for the screen to 509 * be activated. Sleepers must check whether 510 * the screen still exists. 511 */ 512 if (scr->scr_flags & SCR_WAITACTIVE) 513 wakeup(scr); 514 515 /* save a reference to the graphics screen */ 516 cookie = scr->scr_dconf->emulcookie; 517 518 wsscreen_detach(scr); 519 520 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie, cookie); 521 522 if ((flags & WSDISPLAY_DELSCR_QUIET) == 0) 523 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx); 524 return (0); 525 } 526 527 /* 528 * Autoconfiguration functions. 529 */ 530 int 531 wsdisplay_emul_match(struct device *parent, void *match, void *aux) 532 { 533 struct cfdata *cf = match; 534 struct wsemuldisplaydev_attach_args *ap = aux; 535 536 if (cf->wsemuldisplaydevcf_console != WSEMULDISPLAYDEVCF_CONSOLE_UNK) { 537 /* 538 * If console-ness of device specified, either match 539 * exactly (at high priority), or fail. 540 */ 541 if (cf->wsemuldisplaydevcf_console != 0 && ap->console != 0) 542 return (10); 543 else 544 return (0); 545 } 546 547 /* If console-ness unspecified, it wins. */ 548 return (1); 549 } 550 551 void 552 wsdisplay_emul_attach(struct device *parent, struct device *self, void *aux) 553 { 554 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 555 struct wsemuldisplaydev_attach_args *ap = aux; 556 557 wsdisplay_common_attach(sc, ap->console, 558 sc->sc_dv.dv_cfdata->wsemuldisplaydevcf_mux, ap->scrdata, 559 ap->accessops, ap->accesscookie, ap->defaultscreens); 560 561 if (ap->console && cn_tab == &wsdisplay_cons) { 562 int maj; 563 564 /* locate the major number */ 565 for (maj = 0; maj < nchrdev; maj++) 566 if (cdevsw[maj].d_open == wsdisplayopen) 567 break; 568 569 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0)); 570 } 571 } 572 573 /* 574 * Detach a display. 575 */ 576 int 577 wsdisplay_emul_detach(struct device *self, int flags) 578 { 579 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self; 580 581 return (wsdisplay_common_detach(sc, flags)); 582 } 583 584 int 585 wsdisplay_common_detach(struct wsdisplay_softc *sc, int flags) 586 { 587 int i; 588 int rc; 589 590 /* We don't support detaching the console display yet. */ 591 if (sc->sc_isconsole) 592 return (EBUSY); 593 594 /* Delete all screens managed by this display */ 595 for (i = 0; i < WSDISPLAY_MAXSCREEN; i++) 596 if (sc->sc_scr[i] != NULL) { 597 if ((rc = wsdisplay_delscreen(sc, i, 598 WSDISPLAY_DELSCR_QUIET | (flags & DETACH_FORCE ? 599 WSDISPLAY_DELSCR_FORCE : 0))) != 0) 600 return (rc); 601 } 602 603 #ifdef BURNER_SUPPORT 604 timeout_del(&sc->sc_burner); 605 #endif 606 607 #if NWSKBD > 0 608 if (sc->sc_input != NULL) { 609 #if NWSMUX > 0 610 /* 611 * If we are the display of the mux we are attached to, 612 * disconnect all input devices from us. 613 */ 614 if (sc->sc_input->me_dispdv == &sc->sc_dv) { 615 if ((rc = wsmux_set_display((struct wsmux_softc *) 616 sc->sc_input, NULL)) != 0) 617 return (rc); 618 } 619 620 /* 621 * XXX 622 * If we created a standalone mux (dmux), we should destroy it 623 * there, but there is currently no support for this in wsmux. 624 */ 625 #else 626 if ((rc = wskbd_set_display((struct device *)sc->sc_input, 627 NULL)) != 0) 628 return (rc); 629 #endif 630 } 631 #endif 632 633 return (0); 634 } 635 636 /* Print function (for parent devices). */ 637 int 638 wsemuldisplaydevprint(void *aux, const char *pnp) 639 { 640 #if 0 /* -Wunused */ 641 struct wsemuldisplaydev_attach_args *ap = aux; 642 #endif 643 644 if (pnp) 645 printf("wsdisplay at %s", pnp); 646 #if 0 /* don't bother; it's ugly */ 647 printf(" console %d", ap->console); 648 #endif 649 650 return (UNCONF); 651 } 652 653 void 654 wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux, 655 const struct wsscreen_list *scrdata, 656 const struct wsdisplay_accessops *accessops, void *accesscookie, 657 u_int defaultscreens) 658 { 659 static int hookset = 0; 660 int i, start = 0; 661 #if NWSKBD > 0 662 struct wsevsrc *kme; 663 #if NWSMUX > 0 664 struct wsmux_softc *mux; 665 666 if (kbdmux >= 0) 667 mux = wsmux_getmux(kbdmux); 668 else 669 mux = wsmux_create("dmux", sc->sc_dv.dv_unit); 670 /* XXX panic()ing isn't nice, but attach cannot fail */ 671 if (mux == NULL) 672 panic("wsdisplay_common_attach: no memory"); 673 sc->sc_input = &mux->sc_base; 674 675 if (kbdmux >= 0) 676 printf(" mux %d", kbdmux); 677 #else 678 #if 0 /* not worth keeping, especially since the default value is not -1... */ 679 if (kbdmux >= 0) 680 printf(" (mux ignored)"); 681 #endif 682 #endif /* NWSMUX > 0 */ 683 #endif /* NWSKBD > 0 */ 684 685 sc->sc_isconsole = console; 686 687 if (console) { 688 KASSERT(wsdisplay_console_initted); 689 KASSERT(wsdisplay_console_device == NULL); 690 691 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0); 692 if (sc->sc_scr[0] == NULL) 693 return; 694 wsdisplay_console_device = sc; 695 696 printf(": console (%s, %s emulation)", 697 wsdisplay_console_conf.scrdata->name, 698 wsdisplay_console_conf.wsemul->name); 699 700 #if NWSKBD > 0 701 kme = wskbd_set_console_display(&sc->sc_dv, sc->sc_input); 702 if (kme != NULL) 703 printf(", using %s", kme->me_dv.dv_xname); 704 #if NWSMUX == 0 705 sc->sc_input = kme; 706 #endif 707 #endif 708 709 sc->sc_focusidx = 0; 710 sc->sc_focus = sc->sc_scr[0]; 711 start = 1; 712 } 713 printf("\n"); 714 715 #if NWSKBD > 0 && NWSMUX > 0 716 /* 717 * If this mux did not have a display device yet, volunteer for 718 * the job. 719 */ 720 if (mux->sc_displaydv == NULL) 721 wsmux_set_display(mux, &sc->sc_dv); 722 #endif 723 724 sc->sc_accessops = accessops; 725 sc->sc_accesscookie = accesscookie; 726 sc->sc_scrdata = scrdata; 727 728 /* 729 * Set up a number of virtual screens if wanted. The 730 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code 731 * is for special cases like installation kernels, as well as 732 * sane multihead defaults. 733 */ 734 if (defaultscreens == 0) 735 defaultscreens = wsdisplay_defaultscreens; 736 for (i = start; i < defaultscreens; i++) { 737 if (wsdisplay_addscreen(sc, i, 0, 0)) 738 break; 739 } 740 741 if (i > start) 742 wsdisplay_addscreen_print(sc, start, i-start); 743 744 #ifdef BURNER_SUPPORT 745 sc->sc_burnoutintvl = (hz * WSDISPLAY_DEFBURNOUT) / 1000; 746 sc->sc_burninintvl = (hz * WSDISPLAY_DEFBURNIN ) / 1000; 747 sc->sc_burnflags = 0; /* off by default */ 748 timeout_set(&sc->sc_burner, wsdisplay_burner, sc); 749 sc->sc_burnout = sc->sc_burnoutintvl; 750 wsdisplay_burn(sc, sc->sc_burnflags); 751 #endif 752 753 if (hookset == 0) 754 shutdownhook_establish(wsdisplay_shutdownhook, NULL); 755 hookset = 1; 756 757 #if NWSKBD > 0 && NWSMUX == 0 758 if (console == 0) { 759 /* 760 * In the non-wsmux world, always connect wskbd0 and wsdisplay0 761 * together. 762 */ 763 extern struct cfdriver wskbd_cd; 764 765 if (wskbd_cd.cd_ndevs != 0 && sc->sc_dv.dv_unit == 0) { 766 if (wsdisplay_set_kbd(&sc->sc_dv, 767 (struct wsevsrc *)wskbd_cd.cd_devs[0]) == 0) 768 wskbd_set_display(wskbd_cd.cd_devs[0], 769 &sc->sc_dv); 770 } 771 } 772 #endif 773 } 774 775 void 776 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol, 777 int crow, long defattr) 778 { 779 const struct wsemul_ops *wsemul; 780 const struct wsdisplay_emulops *emulops; 781 782 KASSERT(!wsdisplay_console_initted); 783 KASSERT(type->nrows > 0); 784 KASSERT(type->ncols > 0); 785 KASSERT(crow < type->nrows); 786 KASSERT(ccol < type->ncols); 787 788 wsdisplay_console_conf.emulops = emulops = type->textops; 789 wsdisplay_console_conf.emulcookie = cookie; 790 wsdisplay_console_conf.scrdata = type; 791 792 #ifdef WSEMUL_DUMB 793 /* 794 * If the emulops structure is crippled, force a dumb emulation. 795 */ 796 if (emulops->cursor == NULL || 797 emulops->copycols == NULL || emulops->copyrows == NULL || 798 emulops->erasecols == NULL || emulops->eraserows == NULL) 799 wsemul = wsemul_pick("dumb"); 800 else 801 #endif 802 wsemul = wsemul_pick(""); 803 wsdisplay_console_conf.wsemul = wsemul; 804 wsdisplay_console_conf.wsemulcookie = 805 (*wsemul->cnattach)(type, cookie, ccol, crow, defattr); 806 807 cn_tab = &wsdisplay_cons; 808 809 wsdisplay_console_initted = 1; 810 } 811 812 /* 813 * Tty and cdevsw functions. 814 */ 815 int 816 wsdisplayopen(dev_t dev, int flag, int mode, struct proc *p) 817 { 818 struct wsdisplay_softc *sc; 819 struct tty *tp; 820 int unit, newopen, error; 821 struct wsscreen *scr; 822 823 unit = WSDISPLAYUNIT(dev); 824 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */ 825 (sc = wsdisplay_cd.cd_devs[unit]) == NULL) 826 return (ENXIO); 827 828 if (ISWSDISPLAYCTL(dev)) 829 return (0); 830 831 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 832 return (ENXIO); 833 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 834 return (ENXIO); 835 836 if (WSSCREEN_HAS_TTY(scr)) { 837 tp = scr->scr_tty; 838 tp->t_oproc = wsdisplaystart; 839 tp->t_param = wsdisplayparam; 840 tp->t_dev = dev; 841 newopen = (tp->t_state & TS_ISOPEN) == 0; 842 if (newopen) { 843 ttychars(tp); 844 tp->t_iflag = TTYDEF_IFLAG; 845 tp->t_oflag = TTYDEF_OFLAG; 846 tp->t_cflag = TTYDEF_CFLAG; 847 tp->t_lflag = TTYDEF_LFLAG; 848 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 849 wsdisplayparam(tp, &tp->t_termios); 850 ttsetwater(tp); 851 } else if ((tp->t_state & TS_XCLUDE) != 0 && 852 p->p_ucred->cr_uid != 0) 853 return (EBUSY); 854 tp->t_state |= TS_CARR_ON; 855 856 error = ((*linesw[tp->t_line].l_open)(dev, tp)); 857 if (error) 858 return (error); 859 860 if (newopen) { 861 /* set window sizes as appropriate, and reset 862 the emulation */ 863 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows; 864 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols; 865 } 866 } 867 868 scr->scr_flags |= SCR_OPEN; 869 return (0); 870 } 871 872 int 873 wsdisplayclose(dev_t dev, int flag, int mode, struct proc *p) 874 { 875 struct wsdisplay_softc *sc; 876 struct tty *tp; 877 int unit; 878 struct wsscreen *scr; 879 880 unit = WSDISPLAYUNIT(dev); 881 sc = wsdisplay_cd.cd_devs[unit]; 882 883 if (ISWSDISPLAYCTL(dev)) 884 return (0); 885 886 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 887 return (ENXIO); 888 889 if (WSSCREEN_HAS_TTY(scr)) { 890 if (scr->scr_hold_screen) { 891 int s; 892 893 /* XXX RESET KEYBOARD LEDS, etc. */ 894 s = spltty(); /* avoid conflict with keyboard */ 895 wsdisplay_kbdholdscr(scr, 0); 896 splx(s); 897 } 898 tp = scr->scr_tty; 899 (*linesw[tp->t_line].l_close)(tp, flag); 900 ttyclose(tp); 901 } 902 903 #ifdef WSDISPLAY_COMPAT_USL 904 if (scr->scr_syncops) 905 (*scr->scr_syncops->destroy)(scr->scr_synccookie); 906 #endif 907 908 scr->scr_flags &= ~SCR_GRAPHICS; 909 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 910 WSEMUL_RESET); 911 if (wsdisplay_clearonclose) 912 (*scr->scr_dconf->wsemul->reset) 913 (scr->scr_dconf->wsemulcookie, WSEMUL_CLEARSCREEN); 914 915 #ifdef WSDISPLAY_COMPAT_RAWKBD 916 if (scr->scr_rawkbd) { 917 int kbmode = WSKBD_TRANSLATED; 918 (void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE, 919 (caddr_t)&kbmode, FWRITE, p); 920 } 921 #endif 922 923 scr->scr_flags &= ~SCR_OPEN; 924 925 #ifdef WSMOUSED_SUPPORT 926 /* remove the selection at logout */ 927 if (sc->sc_copybuffer != NULL) 928 bzero(sc->sc_copybuffer, sc->sc_copybuffer_size); 929 CLR(sc->sc_flags, SC_PASTE_AVAIL); 930 #endif 931 932 return (0); 933 } 934 935 int 936 wsdisplayread(dev_t dev, struct uio *uio, int flag) 937 { 938 struct wsdisplay_softc *sc; 939 struct tty *tp; 940 int unit; 941 struct wsscreen *scr; 942 943 unit = WSDISPLAYUNIT(dev); 944 sc = wsdisplay_cd.cd_devs[unit]; 945 946 if (ISWSDISPLAYCTL(dev)) 947 return (0); 948 949 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 950 return (ENXIO); 951 952 if (!WSSCREEN_HAS_TTY(scr)) 953 return (ENODEV); 954 955 tp = scr->scr_tty; 956 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 957 } 958 959 int 960 wsdisplaywrite(dev_t dev, struct uio *uio, int flag) 961 { 962 struct wsdisplay_softc *sc; 963 struct tty *tp; 964 int unit; 965 struct wsscreen *scr; 966 967 unit = WSDISPLAYUNIT(dev); 968 sc = wsdisplay_cd.cd_devs[unit]; 969 970 if (ISWSDISPLAYCTL(dev)) 971 return (0); 972 973 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 974 return (ENXIO); 975 976 if (!WSSCREEN_HAS_TTY(scr)) 977 return (ENODEV); 978 979 tp = scr->scr_tty; 980 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 981 } 982 983 struct tty * 984 wsdisplaytty(dev_t dev) 985 { 986 struct wsdisplay_softc *sc; 987 int unit; 988 struct wsscreen *scr; 989 990 unit = WSDISPLAYUNIT(dev); 991 sc = wsdisplay_cd.cd_devs[unit]; 992 993 if (ISWSDISPLAYCTL(dev)) 994 panic("wsdisplaytty() on ctl device"); 995 996 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 997 return (NULL); 998 999 return (scr->scr_tty); 1000 } 1001 1002 int 1003 wsdisplayioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1004 { 1005 struct wsdisplay_softc *sc; 1006 struct tty *tp; 1007 int unit, error; 1008 struct wsscreen *scr; 1009 1010 unit = WSDISPLAYUNIT(dev); 1011 sc = wsdisplay_cd.cd_devs[unit]; 1012 1013 #ifdef WSDISPLAY_COMPAT_USL 1014 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p); 1015 if (error >= 0) 1016 return (error); 1017 #endif 1018 1019 if (ISWSDISPLAYCTL(dev)) 1020 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)); 1021 1022 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN) 1023 return (ENODEV); 1024 1025 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1026 return (ENXIO); 1027 1028 if (WSSCREEN_HAS_TTY(scr)) { 1029 tp = scr->scr_tty; 1030 1031 /* printf("disc\n"); */ 1032 /* do the line discipline ioctls first */ 1033 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 1034 if (error >= 0) 1035 return (error); 1036 1037 /* printf("tty\n"); */ 1038 /* then the tty ioctls */ 1039 error = ttioctl(tp, cmd, data, flag, p); 1040 if (error >= 0) 1041 return (error); 1042 } 1043 1044 #ifdef WSDISPLAY_COMPAT_USL 1045 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p); 1046 if (error >= 0) 1047 return (error); 1048 #endif 1049 1050 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p); 1051 return (error != -1 ? error : ENOTTY); 1052 } 1053 1054 int 1055 wsdisplay_param(struct device *dev, u_long cmd, struct wsdisplay_param *dp) 1056 { 1057 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1058 1059 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 1060 (caddr_t)dp, 0, NULL)); 1061 } 1062 1063 int 1064 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr, 1065 u_long cmd, caddr_t data, int flag, struct proc *p) 1066 { 1067 int error; 1068 1069 #if NWSKBD > 0 1070 struct wsevsrc *inp; 1071 1072 #ifdef WSDISPLAY_COMPAT_RAWKBD 1073 switch (cmd) { 1074 case WSKBDIO_SETMODE: 1075 if ((flag & FWRITE) == 0) 1076 return (EACCES); 1077 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW); 1078 return (wsdisplay_update_rawkbd(sc, scr)); 1079 case WSKBDIO_GETMODE: 1080 *(int *)data = (scr->scr_rawkbd ? 1081 WSKBD_RAW : WSKBD_TRANSLATED); 1082 return (0); 1083 } 1084 #endif 1085 inp = sc->sc_input; 1086 if (inp != NULL) { 1087 error = wsevsrc_display_ioctl(inp, cmd, data, flag, p); 1088 if (error >= 0) 1089 return (error); 1090 } 1091 #endif /* NWSKBD > 0 */ 1092 1093 switch (cmd) { 1094 case WSDISPLAYIO_SMODE: 1095 case WSDISPLAYIO_USEFONT: 1096 #ifdef BURNER_SUPPORT 1097 case WSDISPLAYIO_SVIDEO: 1098 case WSDISPLAYIO_SBURNER: 1099 #endif 1100 case WSDISPLAYIO_SETSCREEN: 1101 if ((flag & FWRITE) == 0) 1102 return (EACCES); 1103 } 1104 1105 switch (cmd) { 1106 case WSDISPLAYIO_GMODE: 1107 if (scr->scr_flags & SCR_GRAPHICS) { 1108 if (scr->scr_flags & SCR_DUMBFB) 1109 *(u_int *)data = WSDISPLAYIO_MODE_DUMBFB; 1110 else 1111 *(u_int *)data = WSDISPLAYIO_MODE_MAPPED; 1112 } else 1113 *(u_int *)data = WSDISPLAYIO_MODE_EMUL; 1114 return (0); 1115 1116 case WSDISPLAYIO_SMODE: 1117 #define d (*(int *)data) 1118 if (d != WSDISPLAYIO_MODE_EMUL && 1119 d != WSDISPLAYIO_MODE_MAPPED && 1120 d != WSDISPLAYIO_MODE_DUMBFB) 1121 return (EINVAL); 1122 1123 scr->scr_flags &= ~SCR_GRAPHICS; 1124 if (d == WSDISPLAYIO_MODE_MAPPED || 1125 d == WSDISPLAYIO_MODE_DUMBFB) { 1126 scr->scr_flags |= SCR_GRAPHICS | 1127 ((d == WSDISPLAYIO_MODE_DUMBFB) ? SCR_DUMBFB : 0); 1128 1129 #ifdef WSMOUSED_SUPPORT 1130 /* 1131 * wsmoused cohabitation with X-Window support 1132 * X-Window is starting 1133 */ 1134 wsmoused_release(sc); 1135 #endif 1136 1137 /* clear cursor */ 1138 (*scr->scr_dconf->wsemul->reset) 1139 (scr->scr_dconf->wsemulcookie, WSEMUL_CLEARCURSOR); 1140 1141 #ifdef BURNER_SUPPORT 1142 /* enable video _immediately_ if it nedes to be... */ 1143 if (sc->sc_burnman) 1144 wsdisplay_burner(sc); 1145 /* ...and disable the burner while X is running */ 1146 if (sc->sc_burnout) 1147 timeout_del(&sc->sc_burner); 1148 #endif 1149 } else { 1150 #ifdef BURNER_SUPPORT 1151 /* reenable the burner after exiting from X */ 1152 if (!sc->sc_burnman) 1153 wsdisplay_burn(sc, sc->sc_burnflags); 1154 #endif 1155 1156 #ifdef WSMOUSED_SUPPORT 1157 /* 1158 * wsmoused cohabitation with X-Window support 1159 * X-Window is ending 1160 */ 1161 wsmoused_wakeup(sc); 1162 #endif 1163 } 1164 1165 (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1166 flag, p); 1167 1168 return (0); 1169 #undef d 1170 1171 case WSDISPLAYIO_USEFONT: 1172 #define d ((struct wsdisplay_font *)data) 1173 if (!sc->sc_accessops->load_font) 1174 return (EINVAL); 1175 d->data = 0; 1176 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 1177 scr->scr_dconf->emulcookie, d); 1178 if (!error) 1179 (*scr->scr_dconf->wsemul->reset) 1180 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT); 1181 return (error); 1182 #undef d 1183 #ifdef BURNER_SUPPORT 1184 case WSDISPLAYIO_GVIDEO: 1185 *(u_int *)data = !sc->sc_burnman; 1186 break; 1187 1188 case WSDISPLAYIO_SVIDEO: 1189 if (*(u_int *)data != WSDISPLAYIO_VIDEO_OFF && 1190 *(u_int *)data != WSDISPLAYIO_VIDEO_ON) 1191 return (EINVAL); 1192 if (sc->sc_accessops->burn_screen == NULL) 1193 return (EOPNOTSUPP); 1194 (*sc->sc_accessops->burn_screen)(sc->sc_accesscookie, 1195 *(u_int *)data, sc->sc_burnflags); 1196 sc->sc_burnman = *(u_int *)data == WSDISPLAYIO_VIDEO_OFF; 1197 break; 1198 1199 case WSDISPLAYIO_GBURNER: 1200 #define d ((struct wsdisplay_burner *)data) 1201 d->on = sc->sc_burninintvl * 1000 / hz; 1202 d->off = sc->sc_burnoutintvl * 1000 / hz; 1203 d->flags = sc->sc_burnflags; 1204 return (0); 1205 1206 case WSDISPLAYIO_SBURNER: 1207 if (d->flags & ~(WSDISPLAY_BURN_VBLANK | WSDISPLAY_BURN_KBD | 1208 WSDISPLAY_BURN_MOUSE | WSDISPLAY_BURN_OUTPUT)) 1209 error = EINVAL; 1210 else { 1211 error = 0; 1212 sc->sc_burnflags = d->flags; 1213 /* disable timeout if necessary */ 1214 if ((sc->sc_burnflags & (WSDISPLAY_BURN_OUTPUT | 1215 WSDISPLAY_BURN_KBD | WSDISPLAY_BURN_MOUSE)) == 0) { 1216 if (sc->sc_burnout) 1217 timeout_del(&sc->sc_burner); 1218 } 1219 } 1220 if (d->on) { 1221 error = 0; 1222 sc->sc_burninintvl = hz * d->on / 1000; 1223 if (sc->sc_burnman) { 1224 sc->sc_burnout = sc->sc_burninintvl; 1225 /* reinit timeout if changed */ 1226 if ((scr->scr_flags & SCR_GRAPHICS) == 0) 1227 wsdisplay_burn(sc, sc->sc_burnflags); 1228 } 1229 } 1230 if (d->off) { 1231 error = 0; 1232 sc->sc_burnoutintvl = hz * d->off / 1000; 1233 if (!sc->sc_burnman) { 1234 sc->sc_burnout = sc->sc_burnoutintvl; 1235 /* reinit timeout if changed */ 1236 if ((scr->scr_flags & SCR_GRAPHICS) == 0) 1237 wsdisplay_burn(sc, sc->sc_burnflags); 1238 } 1239 } 1240 return (error); 1241 #undef d 1242 #endif /* BURNER_SUPPORT */ 1243 case WSDISPLAYIO_GETSCREEN: 1244 return (wsdisplay_getscreen(sc, 1245 (struct wsdisplay_addscreendata *)data)); 1246 1247 case WSDISPLAYIO_SETSCREEN: 1248 return (wsdisplay_switch((void *)sc, *(int *)data, 1)); 1249 } 1250 1251 /* check ioctls for display */ 1252 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1253 flag, p)); 1254 } 1255 1256 int 1257 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 1258 int flag, struct proc *p) 1259 { 1260 int error; 1261 void *buf; 1262 size_t fontsz; 1263 #if NWSKBD > 0 1264 struct wsevsrc *inp; 1265 #endif 1266 1267 switch (cmd) { 1268 #ifdef WSMOUSED_SUPPORT 1269 case WSDISPLAYIO_WSMOUSED: 1270 error = wsmoused(sc, cmd, data, flag, p); 1271 return (error); 1272 #endif 1273 case WSDISPLAYIO_ADDSCREEN: 1274 #define d ((struct wsdisplay_addscreendata *)data) 1275 if ((error = wsdisplay_addscreen(sc, d->idx, 1276 d->screentype, d->emul)) == 0) 1277 wsdisplay_addscreen_print(sc, d->idx, 0); 1278 return (error); 1279 #undef d 1280 case WSDISPLAYIO_DELSCREEN: 1281 #define d ((struct wsdisplay_delscreendata *)data) 1282 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1283 #undef d 1284 case WSDISPLAYIO_GETSCREEN: 1285 return (wsdisplay_getscreen(sc, 1286 (struct wsdisplay_addscreendata *)data)); 1287 case WSDISPLAYIO_SETSCREEN: 1288 return (wsdisplay_switch((void *)sc, *(int *)data, 1)); 1289 case WSDISPLAYIO_LDFONT: 1290 #define d ((struct wsdisplay_font *)data) 1291 if (!sc->sc_accessops->load_font) 1292 return (EINVAL); 1293 if (d->index >= WSDISPLAY_MAXFONT) 1294 return (EINVAL); 1295 fontsz = d->fontheight * d->stride * d->numchars; 1296 if (fontsz > WSDISPLAY_MAXFONTSZ) 1297 return (EINVAL); 1298 1299 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1300 error = copyin(d->data, buf, fontsz); 1301 if (error) { 1302 free(buf, M_DEVBUF); 1303 return (error); 1304 } 1305 d->data = buf; 1306 error = 1307 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1308 if (error) 1309 free(buf, M_DEVBUF); 1310 else if (d->index >= 0 || d->index < WSDISPLAY_MAXFONT) 1311 sc->sc_fonts[d->index] = *d; 1312 return (error); 1313 1314 case WSDISPLAYIO_LSFONT: 1315 if (d->index < 0 || d->index >= WSDISPLAY_MAXFONT) 1316 return (EINVAL); 1317 *d = sc->sc_fonts[d->index]; 1318 return (0); 1319 1320 case WSDISPLAYIO_DELFONT: 1321 return (EINVAL); 1322 #undef d 1323 1324 #if NWSKBD > 0 1325 case WSMUXIO_ADD_DEVICE: 1326 #define d ((struct wsmux_device *)data) 1327 if (d->idx == -1 && d->type == WSMUX_KBD) 1328 d->idx = wskbd_pickfree(); 1329 #undef d 1330 /* FALLTHROUGH */ 1331 case WSMUXIO_INJECTEVENT: 1332 case WSMUXIO_REMOVE_DEVICE: 1333 case WSMUXIO_LIST_DEVICES: 1334 inp = sc->sc_input; 1335 if (inp == NULL) 1336 return (ENXIO); 1337 return (wsevsrc_ioctl(inp, cmd, data, flag,p)); 1338 #endif /* NWSKBD > 0 */ 1339 1340 } 1341 return (EINVAL); 1342 } 1343 1344 paddr_t 1345 wsdisplaymmap(dev_t dev, off_t offset, int prot) 1346 { 1347 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1348 struct wsscreen *scr; 1349 1350 if (ISWSDISPLAYCTL(dev)) 1351 return (-1); 1352 1353 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1354 return (-1); 1355 1356 if (!(scr->scr_flags & SCR_GRAPHICS)) 1357 return (-1); 1358 1359 /* pass mmap to display */ 1360 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1361 } 1362 1363 int 1364 wsdisplaypoll(dev_t dev, int events, struct proc *p) 1365 { 1366 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1367 struct wsscreen *scr; 1368 1369 if (ISWSDISPLAYCTL(dev)) 1370 return (0); 1371 1372 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1373 return (POLLERR); 1374 1375 if (!WSSCREEN_HAS_TTY(scr)) 1376 return (POLLERR); 1377 1378 return (ttpoll(dev, events, p)); 1379 } 1380 1381 int 1382 wsdisplaykqfilter(dev_t dev, struct knote *kn) 1383 { 1384 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1385 struct wsscreen *scr; 1386 1387 if (ISWSDISPLAYCTL(dev)) 1388 return (1); 1389 1390 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL) 1391 return (1); 1392 1393 if (WSSCREEN_HAS_TTY(scr)) 1394 return (ttkqfilter(dev, kn)); 1395 else 1396 return (1); 1397 } 1398 1399 void 1400 wsdisplaystart(struct tty *tp) 1401 { 1402 struct wsdisplay_softc *sc; 1403 struct wsscreen *scr; 1404 int s, n, done, unit; 1405 u_char *buf; 1406 1407 unit = WSDISPLAYUNIT(tp->t_dev); 1408 if (unit >= wsdisplay_cd.cd_ndevs || 1409 (sc = wsdisplay_cd.cd_devs[unit]) == NULL) 1410 return; 1411 1412 s = spltty(); 1413 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1414 splx(s); 1415 return; 1416 } 1417 if (tp->t_outq.c_cc == 0 && tp->t_wsel.si_selpid == 0) 1418 goto low; 1419 1420 if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) { 1421 splx(s); 1422 return; 1423 } 1424 if (scr->scr_hold_screen) { 1425 tp->t_state |= TS_TIMEOUT; 1426 splx(s); 1427 return; 1428 } 1429 tp->t_state |= TS_BUSY; 1430 splx(s); 1431 1432 /* 1433 * Drain output from ring buffer. 1434 * The output will normally be in one contiguous chunk, but when the 1435 * ring wraps, it will be in two pieces.. one at the end of the ring, 1436 * the other at the start. For performance, rather than loop here, 1437 * we output one chunk, see if there's another one, and if so, output 1438 * it too. 1439 */ 1440 1441 n = ndqb(&tp->t_outq, 0); 1442 buf = tp->t_outq.c_cf; 1443 1444 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1445 #ifdef BURNER_SUPPORT 1446 wsdisplay_burn(sc, WSDISPLAY_BURN_OUTPUT); 1447 #endif 1448 #ifdef WSMOUSED_SUPPORT 1449 if (scr == sc->sc_focus) { 1450 if (ISSET(scr->mouse_flags, SEL_EXISTS)) 1451 /* hide a potential selection */ 1452 remove_selection(scr); 1453 /* hide a potential mouse cursor */ 1454 mouse_hide(scr); 1455 } 1456 #endif 1457 done = (*scr->scr_dconf->wsemul->output) 1458 (scr->scr_dconf->wsemulcookie, buf, n, 0); 1459 } else 1460 done = n; 1461 ndflush(&tp->t_outq, done); 1462 1463 if (done == n) { 1464 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1465 buf = tp->t_outq.c_cf; 1466 1467 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1468 done = (*scr->scr_dconf->wsemul->output) 1469 (scr->scr_dconf->wsemulcookie, buf, n, 0); 1470 } else 1471 done = n; 1472 ndflush(&tp->t_outq, done); 1473 } 1474 } 1475 1476 s = spltty(); 1477 tp->t_state &= ~TS_BUSY; 1478 /* Come back if there's more to do */ 1479 if (tp->t_outq.c_cc) { 1480 tp->t_state |= TS_TIMEOUT; 1481 timeout_add(&tp->t_rstrt_to, (hz > 128) ? (hz / 128) : 1); 1482 } 1483 if (tp->t_outq.c_cc <= tp->t_lowat) { 1484 low: 1485 if (tp->t_state & TS_ASLEEP) { 1486 tp->t_state &= ~TS_ASLEEP; 1487 wakeup((caddr_t)&tp->t_outq); 1488 } 1489 selwakeup(&tp->t_wsel); 1490 } 1491 splx(s); 1492 } 1493 1494 int 1495 wsdisplaystop(struct tty *tp, int flag) 1496 { 1497 int s; 1498 1499 s = spltty(); 1500 if (ISSET(tp->t_state, TS_BUSY)) 1501 if (!ISSET(tp->t_state, TS_TTSTOP)) 1502 SET(tp->t_state, TS_FLUSH); 1503 splx(s); 1504 1505 return (0); 1506 } 1507 1508 /* Set line parameters. */ 1509 int 1510 wsdisplayparam(struct tty *tp, struct termios *t) 1511 { 1512 1513 tp->t_ispeed = t->c_ispeed; 1514 tp->t_ospeed = t->c_ospeed; 1515 tp->t_cflag = t->c_cflag; 1516 return (0); 1517 } 1518 1519 /* 1520 * Callbacks for the emulation code. 1521 */ 1522 void 1523 wsdisplay_emulbell(void *v) 1524 { 1525 struct wsscreen *scr = v; 1526 1527 if (scr == NULL) /* console, before real attach */ 1528 return; 1529 1530 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1531 return; 1532 1533 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1534 FWRITE, NULL); 1535 } 1536 1537 #if !defined(WSEMUL_NO_VT100) 1538 void 1539 wsdisplay_emulinput(void *v, const u_char *data, u_int count) 1540 { 1541 struct wsscreen *scr = v; 1542 struct tty *tp; 1543 1544 if (v == NULL) /* console, before real attach */ 1545 return; 1546 1547 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1548 return; 1549 if (!WSSCREEN_HAS_TTY(scr)) 1550 return; 1551 1552 tp = scr->scr_tty; 1553 while (count-- > 0) 1554 (*linesw[tp->t_line].l_rint)(*data++, tp); 1555 } 1556 #endif 1557 1558 /* 1559 * Calls from the keyboard interface. 1560 */ 1561 void 1562 wsdisplay_kbdinput(struct device *dev, keysym_t ks) 1563 { 1564 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1565 struct wsscreen *scr; 1566 const char *dp; 1567 int count; 1568 struct tty *tp; 1569 1570 KASSERT(sc != NULL); 1571 1572 scr = sc->sc_focus; 1573 1574 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1575 return; 1576 1577 tp = scr->scr_tty; 1578 1579 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1580 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp); 1581 else { 1582 count = (*scr->scr_dconf->wsemul->translate) 1583 (scr->scr_dconf->wsemulcookie, ks, &dp); 1584 while (count-- > 0) 1585 (*linesw[tp->t_line].l_rint)(*dp++, tp); 1586 } 1587 } 1588 1589 #ifdef WSDISPLAY_COMPAT_RAWKBD 1590 int 1591 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr) 1592 { 1593 #if NWSKBD > 0 1594 int s, raw, data, error; 1595 struct wsevsrc *inp; 1596 1597 s = spltty(); 1598 1599 raw = (scr ? scr->scr_rawkbd : 0); 1600 1601 if (scr != sc->sc_focus || sc->sc_rawkbd == raw) { 1602 splx(s); 1603 return (0); 1604 } 1605 1606 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1607 inp = sc->sc_input; 1608 if (inp == NULL) { 1609 splx(s); 1610 return (ENXIO); 1611 } 1612 error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, FWRITE, 0); 1613 if (!error) 1614 sc->sc_rawkbd = raw; 1615 splx(s); 1616 return (error); 1617 #else 1618 return (0); 1619 #endif 1620 } 1621 #endif 1622 1623 int 1624 wsdisplay_switch3(void *arg, int error, int waitok) 1625 { 1626 struct wsdisplay_softc *sc = arg; 1627 int no; 1628 struct wsscreen *scr; 1629 1630 #ifdef WSDISPLAY_COMPAT_USL 1631 if (!ISSET(sc->sc_flags, SC_SWITCHPENDING)) { 1632 printf("wsdisplay_switch3: not switching\n"); 1633 return (EINVAL); 1634 } 1635 1636 no = sc->sc_screenwanted; 1637 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1638 panic("wsdisplay_switch3: invalid screen %d", no); 1639 scr = sc->sc_scr[no]; 1640 if (!scr) { 1641 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1642 error = ENXIO; 1643 } 1644 1645 if (error) { 1646 /* try to recover, avoid recursion */ 1647 1648 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1649 printf("wsdisplay_switch3: giving up\n"); 1650 sc->sc_focus = 0; 1651 #ifdef WSDISPLAY_COMPAT_RAWKBD 1652 wsdisplay_update_rawkbd(sc, 0); 1653 #endif 1654 CLR(sc->sc_flags, SC_SWITCHPENDING); 1655 return (error); 1656 } 1657 1658 sc->sc_screenwanted = sc->sc_oldscreen; 1659 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1660 return (wsdisplay_switch1(arg, 0, waitok)); 1661 } 1662 #else 1663 /* 1664 * If we do not have syncops support, we come straight from 1665 * wsdisplay_switch2 which has already validated our arguments 1666 * and did not sleep. 1667 */ 1668 no = sc->sc_screenwanted; 1669 scr = sc->sc_scr[no]; 1670 #endif 1671 1672 CLR(sc->sc_flags, SC_SWITCHPENDING); 1673 1674 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1675 wakeup(scr); 1676 return (error); 1677 } 1678 1679 int 1680 wsdisplay_switch2(void *arg, int error, int waitok) 1681 { 1682 struct wsdisplay_softc *sc = arg; 1683 int no; 1684 struct wsscreen *scr; 1685 1686 if (!ISSET(sc->sc_flags, SC_SWITCHPENDING)) { 1687 printf("wsdisplay_switch2: not switching\n"); 1688 return (EINVAL); 1689 } 1690 1691 no = sc->sc_screenwanted; 1692 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1693 panic("wsdisplay_switch2: invalid screen %d", no); 1694 scr = sc->sc_scr[no]; 1695 if (!scr) { 1696 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1697 error = ENXIO; 1698 } 1699 1700 if (error) { 1701 /* try to recover, avoid recursion */ 1702 1703 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1704 printf("wsdisplay_switch2: giving up\n"); 1705 sc->sc_focus = 0; 1706 CLR(sc->sc_flags, SC_SWITCHPENDING); 1707 return (error); 1708 } 1709 1710 sc->sc_screenwanted = sc->sc_oldscreen; 1711 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1712 return (wsdisplay_switch1(arg, 0, waitok)); 1713 } 1714 1715 sc->sc_focusidx = no; 1716 sc->sc_focus = scr; 1717 1718 #ifdef WSDISPLAY_COMPAT_RAWKBD 1719 (void) wsdisplay_update_rawkbd(sc, scr); 1720 #endif 1721 /* keyboard map??? */ 1722 1723 #ifdef WSDISPLAY_COMPAT_USL 1724 #define wsswitch_cb3 ((void (*)(void *, int, int))wsdisplay_switch3) 1725 if (scr->scr_syncops) { 1726 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1727 sc->sc_isconsole && wsdisplay_cons_pollmode ? 1728 0 : wsswitch_cb3, sc); 1729 if (error == EAGAIN) { 1730 /* switch will be done asynchronously */ 1731 return (0); 1732 } 1733 } 1734 #endif 1735 1736 return (wsdisplay_switch3(sc, error, waitok)); 1737 } 1738 1739 int 1740 wsdisplay_switch1(void *arg, int error, int waitok) 1741 { 1742 struct wsdisplay_softc *sc = arg; 1743 int no; 1744 struct wsscreen *scr; 1745 1746 if (!ISSET(sc->sc_flags, SC_SWITCHPENDING)) { 1747 printf("wsdisplay_switch1: not switching\n"); 1748 return (EINVAL); 1749 } 1750 1751 no = sc->sc_screenwanted; 1752 if (no == WSDISPLAY_NULLSCREEN) { 1753 CLR(sc->sc_flags, SC_SWITCHPENDING); 1754 if (!error) { 1755 sc->sc_focus = 0; 1756 } 1757 wakeup(sc); 1758 return (error); 1759 } 1760 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1761 panic("wsdisplay_switch1: invalid screen %d", no); 1762 scr = sc->sc_scr[no]; 1763 if (!scr) { 1764 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1765 error = ENXIO; 1766 } 1767 1768 if (error) { 1769 CLR(sc->sc_flags, SC_SWITCHPENDING); 1770 return (error); 1771 } 1772 1773 #define wsswitch_cb2 ((void (*)(void *, int, int))wsdisplay_switch2) 1774 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1775 scr->scr_dconf->emulcookie, waitok, 1776 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1777 if (error == EAGAIN) { 1778 /* switch will be done asynchronously */ 1779 return (0); 1780 } 1781 1782 return (wsdisplay_switch2(sc, error, waitok)); 1783 } 1784 1785 int 1786 wsdisplay_switch(struct device *dev, int no, int waitok) 1787 { 1788 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1789 int s, res = 0; 1790 struct wsscreen *scr; 1791 1792 if (no != WSDISPLAY_NULLSCREEN) { 1793 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1794 return (EINVAL); 1795 if (sc->sc_scr[no] == NULL) 1796 return (ENXIO); 1797 } 1798 1799 s = spltty(); 1800 1801 if ((sc->sc_focus && no == sc->sc_focusidx) || 1802 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1803 splx(s); 1804 return (0); 1805 } 1806 1807 if (ISSET(sc->sc_flags, SC_SWITCHPENDING)) { 1808 splx(s); 1809 return (EBUSY); 1810 } 1811 1812 SET(sc->sc_flags, SC_SWITCHPENDING); 1813 sc->sc_screenwanted = no; 1814 1815 splx(s); 1816 1817 scr = sc->sc_focus; 1818 if (!scr) { 1819 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1820 return (wsdisplay_switch1(sc, 0, waitok)); 1821 } else 1822 sc->sc_oldscreen = sc->sc_focusidx; 1823 1824 1825 #ifdef WSMOUSED_SUPPORT 1826 /* 1827 * wsmoused cohabitation with X-Window support 1828 * 1829 * Detect switch from a graphic to text console and vice-versa 1830 * This only happen when switching from X-Window to text mode and 1831 * switching back from text mode to X-Window. 1832 * 1833 * scr_flags is not yet flagged with SCR_GRAPHICS when X-Window starts 1834 * (KD_GRAPHICS ioctl happens after VT_ACTIVATE ioctl in 1835 * xf86OpenPcvt()). Conversely, scr_flags is no longer flagged with 1836 * SCR_GRAPHICS when X-Window stops. In this case, the first of the 1837 * three following 'if' statements is evaluated. 1838 * We handle wsmoused(8) events the WSDISPLAYIO_SMODE ioctl. 1839 */ 1840 1841 if (!(scr->scr_flags & SCR_GRAPHICS) && 1842 (no == WSDISPLAY_NULLSCREEN || 1843 !(sc->sc_scr[no]->scr_flags & SCR_GRAPHICS))) { 1844 /* switching from a text console to another text console */ 1845 /* XXX evaluated when the X-server starts or stops, see above */ 1846 1847 /* remove a potential wsmoused(8) selection */ 1848 mouse_remove(scr); 1849 } 1850 1851 if (!(scr->scr_flags & SCR_GRAPHICS) && 1852 (no != WSDISPLAY_NULLSCREEN && 1853 (sc->sc_scr[no]->scr_flags & SCR_GRAPHICS))) { 1854 /* switching from a text console to a graphic console */ 1855 1856 /* remove a potential wsmoused(8) selection */ 1857 mouse_remove(scr); 1858 wsmoused_release(sc); 1859 } 1860 1861 if ((scr->scr_flags & SCR_GRAPHICS) && 1862 (no == WSDISPLAY_NULLSCREEN || 1863 !(sc->sc_scr[no]->scr_flags & SCR_GRAPHICS))) { 1864 /* switching from a graphic console to a text console */ 1865 1866 wsmoused_wakeup(sc); 1867 } 1868 #endif /* WSMOUSED_SUPPORT */ 1869 1870 #ifdef WSDISPLAY_COMPAT_USL 1871 #define wsswitch_cb1 ((void (*)(void *, int, int))wsdisplay_switch1) 1872 if (scr->scr_syncops) { 1873 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1874 sc->sc_isconsole && wsdisplay_cons_pollmode ? 1875 0 : wsswitch_cb1, sc); 1876 if (res == EAGAIN) { 1877 /* switch will be done asynchronously */ 1878 return (0); 1879 } 1880 } else if (scr->scr_flags & SCR_GRAPHICS) { 1881 /* no way to save state */ 1882 res = EBUSY; 1883 } 1884 #endif 1885 1886 return (wsdisplay_switch1(sc, res, waitok)); 1887 } 1888 1889 void 1890 wsdisplay_reset(struct device *dev, enum wsdisplay_resetops op) 1891 { 1892 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1893 struct wsscreen *scr; 1894 1895 KASSERT(sc != NULL); 1896 scr = sc->sc_focus; 1897 1898 if (!scr) 1899 return; 1900 1901 switch (op) { 1902 case WSDISPLAY_RESETEMUL: 1903 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1904 WSEMUL_RESET); 1905 break; 1906 case WSDISPLAY_RESETCLOSE: 1907 wsdisplay_closescreen(sc, scr); 1908 break; 1909 } 1910 } 1911 1912 #ifdef WSDISPLAY_COMPAT_USL 1913 /* 1914 * Interface for (external) VT switch / process synchronization code 1915 */ 1916 int 1917 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops, 1918 void *cookie) 1919 { 1920 if (scr->scr_syncops) { 1921 /* 1922 * The screen is already claimed. 1923 * Check if the owner is still alive. 1924 */ 1925 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1926 return (EBUSY); 1927 } 1928 scr->scr_syncops = ops; 1929 scr->scr_synccookie = cookie; 1930 return (0); 1931 } 1932 1933 int 1934 wsscreen_detach_sync(struct wsscreen *scr) 1935 { 1936 if (!scr->scr_syncops) 1937 return (EINVAL); 1938 scr->scr_syncops = 0; 1939 return (0); 1940 } 1941 1942 int 1943 wsscreen_lookup_sync(struct wsscreen *scr, 1944 const struct wscons_syncops *ops, /* used as ID */ 1945 void **cookiep) 1946 { 1947 if (!scr->scr_syncops || ops != scr->scr_syncops) 1948 return (EINVAL); 1949 *cookiep = scr->scr_synccookie; 1950 return (0); 1951 } 1952 #endif 1953 1954 /* 1955 * Interface to virtual screen stuff 1956 */ 1957 int 1958 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc) 1959 { 1960 return (WSDISPLAY_MAXSCREEN - 1); 1961 } 1962 1963 int 1964 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx) 1965 { 1966 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1967 return (EINVAL); 1968 if (!sc->sc_scr[idx]) 1969 return (ENXIO); 1970 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1971 } 1972 1973 int 1974 wsdisplay_getactivescreen(struct wsdisplay_softc *sc) 1975 { 1976 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1977 } 1978 1979 int 1980 wsscreen_switchwait(struct wsdisplay_softc *sc, int no) 1981 { 1982 struct wsscreen *scr; 1983 int s, res = 0; 1984 1985 if (no == WSDISPLAY_NULLSCREEN) { 1986 s = spltty(); 1987 while (sc->sc_focus && res == 0) { 1988 res = tsleep(sc, PCATCH, "wswait", 0); 1989 } 1990 splx(s); 1991 return (res); 1992 } 1993 1994 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1995 return (ENXIO); 1996 scr = sc->sc_scr[no]; 1997 if (!scr) 1998 return (ENXIO); 1999 2000 s = spltty(); 2001 if (scr != sc->sc_focus) { 2002 scr->scr_flags |= SCR_WAITACTIVE; 2003 res = tsleep(scr, PCATCH, "wswait", 0); 2004 if (scr != sc->sc_scr[no]) 2005 res = ENXIO; /* disappeared in the meantime */ 2006 else 2007 scr->scr_flags &= ~SCR_WAITACTIVE; 2008 } 2009 splx(s); 2010 return (res); 2011 } 2012 2013 void 2014 wsdisplay_kbdholdscr(struct wsscreen *scr, int hold) 2015 { 2016 if (hold) 2017 scr->scr_hold_screen = 1; 2018 else { 2019 scr->scr_hold_screen = 0; 2020 timeout_add(&scr->scr_tty->t_rstrt_to, 0); /* "immediate" */ 2021 } 2022 } 2023 2024 void 2025 wsdisplay_kbdholdscreen(struct device *dev, int hold) 2026 { 2027 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 2028 struct wsscreen *scr; 2029 2030 scr = sc->sc_focus; 2031 if (scr != NULL && WSSCREEN_HAS_TTY(scr)) 2032 wsdisplay_kbdholdscr(scr, hold); 2033 } 2034 2035 #if NWSKBD > 0 2036 void 2037 wsdisplay_set_console_kbd(struct wsevsrc *src) 2038 { 2039 if (wsdisplay_console_device == NULL) { 2040 src->me_dispdv = NULL; 2041 return; 2042 } 2043 #if NWSMUX > 0 2044 if (wsmux_attach_sc((struct wsmux_softc *) 2045 wsdisplay_console_device->sc_input, src)) { 2046 src->me_dispdv = NULL; 2047 return; 2048 } 2049 #else 2050 wsdisplay_console_device->sc_input = src; 2051 #endif 2052 src->me_dispdv = &wsdisplay_console_device->sc_dv; 2053 } 2054 2055 #if NWSMUX == 0 2056 int 2057 wsdisplay_set_kbd(struct device *disp, struct wsevsrc *kbd) 2058 { 2059 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)disp; 2060 2061 if (sc->sc_input != NULL) 2062 return (EBUSY); 2063 2064 sc->sc_input = kbd; 2065 2066 return (0); 2067 } 2068 #endif 2069 2070 #endif /* NWSKBD > 0 */ 2071 2072 /* 2073 * Console interface. 2074 */ 2075 void 2076 wsdisplay_cnputc(dev_t dev, int i) 2077 { 2078 struct wsscreen_internal *dc; 2079 char c = i; 2080 2081 if (!wsdisplay_console_initted) 2082 return; 2083 2084 if (wsdisplay_console_device != NULL && 2085 (wsdisplay_console_device->sc_scr[0] != NULL) && 2086 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 2087 return; 2088 2089 dc = &wsdisplay_console_conf; 2090 #ifdef BURNER_SUPPORT 2091 /*wsdisplay_burn(wsdisplay_console_device, WSDISPLAY_BURN_OUTPUT);*/ 2092 #endif 2093 (void)(*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 2094 } 2095 2096 int 2097 wsdisplay_getc_dummy(dev_t dev) 2098 { 2099 /* panic? */ 2100 return (0); 2101 } 2102 2103 void 2104 wsdisplay_pollc(dev_t dev, int on) 2105 { 2106 2107 wsdisplay_cons_pollmode = on; 2108 2109 /* notify to fb drivers */ 2110 if (wsdisplay_console_device != NULL && 2111 wsdisplay_console_device->sc_accessops->pollc != NULL) 2112 (*wsdisplay_console_device->sc_accessops->pollc) 2113 (wsdisplay_console_device->sc_accesscookie, on); 2114 2115 /* notify to kbd drivers */ 2116 if (wsdisplay_cons_kbd_pollc) 2117 (*wsdisplay_cons_kbd_pollc)(dev, on); 2118 } 2119 2120 void 2121 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int), 2122 void (*bell)(dev_t, u_int, u_int, u_int)) 2123 { 2124 wsdisplay_cons.cn_getc = get; 2125 wsdisplay_cons.cn_bell = bell; 2126 wsdisplay_cons_kbd_pollc = poll; 2127 } 2128 2129 void 2130 wsdisplay_unset_cons_kbd() 2131 { 2132 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 2133 wsdisplay_cons.cn_bell = NULL; 2134 wsdisplay_cons_kbd_pollc = 0; 2135 } 2136 2137 /* 2138 * Switch the console display to its first screen. 2139 */ 2140 void 2141 wsdisplay_switchtoconsole() 2142 { 2143 struct wsdisplay_softc *sc; 2144 struct wsscreen *scr; 2145 2146 if (wsdisplay_console_device != NULL) { 2147 sc = wsdisplay_console_device; 2148 if ((scr = sc->sc_scr[0]) == NULL) 2149 return; 2150 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 2151 scr->scr_dconf->emulcookie, 0, NULL, NULL); 2152 } 2153 } 2154 2155 #ifdef SCROLLBACK_SUPPORT 2156 void 2157 wsscrollback(void *arg, int op) 2158 { 2159 struct wsdisplay_softc *sc = arg; 2160 int lines; 2161 2162 if (sc->sc_focus == NULL) 2163 return; 2164 2165 if (op == WSDISPLAY_SCROLL_RESET) 2166 lines = 0; 2167 else { 2168 lines = sc->sc_focus->scr_dconf->scrdata->nrows - 1; 2169 if (op == WSDISPLAY_SCROLL_BACKWARD) 2170 lines = -lines; 2171 } 2172 2173 if (sc->sc_accessops->scrollback) { 2174 (*sc->sc_accessops->scrollback)(sc->sc_accesscookie, 2175 sc->sc_focus->scr_dconf->emulcookie, lines); 2176 } 2177 } 2178 #endif 2179 2180 #ifdef BURNER_SUPPORT 2181 void 2182 wsdisplay_burn(void *v, u_int flags) 2183 { 2184 struct wsdisplay_softc *sc = v; 2185 2186 if ((flags & sc->sc_burnflags & (WSDISPLAY_BURN_OUTPUT | 2187 WSDISPLAY_BURN_KBD | WSDISPLAY_BURN_MOUSE)) && 2188 sc->sc_accessops->burn_screen) { 2189 if (sc->sc_burnout) 2190 timeout_add(&sc->sc_burner, sc->sc_burnout); 2191 if (sc->sc_burnman) 2192 sc->sc_burnout = 0; 2193 } 2194 } 2195 2196 void 2197 wsdisplay_burner(void *v) 2198 { 2199 struct wsdisplay_softc *sc = v; 2200 int s; 2201 2202 if (sc->sc_accessops->burn_screen) { 2203 (*sc->sc_accessops->burn_screen)(sc->sc_accesscookie, 2204 sc->sc_burnman, sc->sc_burnflags); 2205 s = spltty(); 2206 if (sc->sc_burnman) { 2207 sc->sc_burnout = sc->sc_burnoutintvl; 2208 timeout_add(&sc->sc_burner, sc->sc_burnout); 2209 } else 2210 sc->sc_burnout = sc->sc_burninintvl; 2211 sc->sc_burnman = !sc->sc_burnman; 2212 splx(s); 2213 } 2214 } 2215 #endif 2216 2217 /* 2218 * Switch the console at shutdown. 2219 */ 2220 void 2221 wsdisplay_shutdownhook(void *arg) 2222 { 2223 wsdisplay_switchtoconsole(); 2224 } 2225 2226 #ifdef WSMOUSED_SUPPORT 2227 /* 2228 * wsmoused(8) support functions 2229 */ 2230 2231 /* 2232 * Main function, called from wsdisplay_cfg_ioctl. 2233 */ 2234 int 2235 wsmoused(struct wsdisplay_softc *sc, u_long cmd, caddr_t data, 2236 int flag, struct proc *p) 2237 { 2238 struct wscons_event mouse_event = *(struct wscons_event *)data; 2239 2240 if (cmd == WSDISPLAYIO_WSMOUSED) { 2241 if (IS_MOTION_EVENT(mouse_event.type)) { 2242 if (sc->sc_focus != NULL) 2243 motion_event(sc->sc_focus, mouse_event.type, 2244 mouse_event.value); 2245 return 0; 2246 } 2247 if (IS_BUTTON_EVENT(mouse_event.type)) { 2248 if (sc->sc_focus != NULL) { 2249 /* XXX tv_sec contains the number of clicks */ 2250 if (mouse_event.type == 2251 WSCONS_EVENT_MOUSE_DOWN) { 2252 button_event(sc->sc_focus, 2253 mouse_event.value, 2254 mouse_event.time.tv_sec); 2255 } else 2256 button_event(sc->sc_focus, 2257 mouse_event.value, 0); 2258 } 2259 return (0); 2260 } 2261 if (IS_CTRL_EVENT(mouse_event.type)) { 2262 return ctrl_event(sc, mouse_event.type, 2263 mouse_event.value, p); 2264 } 2265 } 2266 return -1; 2267 } 2268 2269 /* 2270 * Mouse motion events 2271 */ 2272 void 2273 motion_event(struct wsscreen *scr, u_int type, int value) 2274 { 2275 switch (type) { 2276 case WSCONS_EVENT_MOUSE_DELTA_X: 2277 mouse_moverel(scr, value, 0); 2278 break; 2279 case WSCONS_EVENT_MOUSE_DELTA_Y: 2280 mouse_moverel(scr, 0, -value); 2281 break; 2282 case WSCONS_EVENT_MOUSE_DELTA_Z: 2283 mouse_zaxis(scr, value); 2284 break; 2285 default: 2286 break; 2287 } 2288 } 2289 2290 /* 2291 * Button clicks events 2292 */ 2293 void 2294 button_event(struct wsscreen *scr, int button, int clicks) 2295 { 2296 switch (button) { 2297 case MOUSE_COPY_BUTTON: 2298 switch (clicks % 4) { 2299 case 0: /* button is up */ 2300 mouse_copy_end(scr); 2301 mouse_copy_selection(scr); 2302 break; 2303 case 1: /* single click */ 2304 mouse_copy_start(scr); 2305 mouse_copy_selection(scr); 2306 break; 2307 case 2: /* double click */ 2308 mouse_copy_word(scr); 2309 mouse_copy_selection(scr); 2310 break; 2311 case 3: /* triple click */ 2312 mouse_copy_line(scr); 2313 mouse_copy_selection(scr); 2314 break; 2315 } 2316 break; 2317 case MOUSE_PASTE_BUTTON: 2318 if (clicks != 0) 2319 mouse_paste(scr); 2320 break; 2321 case MOUSE_EXTEND_BUTTON: 2322 if (clicks != 0) 2323 mouse_copy_extend_after(scr); 2324 break; 2325 default: 2326 break; 2327 } 2328 } 2329 2330 /* 2331 * Control events 2332 */ 2333 int 2334 ctrl_event(struct wsdisplay_softc *sc, u_int type, int value, struct proc *p) 2335 { 2336 struct wsscreen *scr; 2337 int i, error; 2338 2339 switch (type) { 2340 case WSCONS_EVENT_WSMOUSED_OFF: 2341 CLR(sc->sc_flags, SC_PASTE_AVAIL); 2342 sc->wsmoused_dev = 0; 2343 return (0); 2344 case WSCONS_EVENT_WSMOUSED_SLEEP: 2345 /* sleeping until next switch to text mode */ 2346 sc->wsmoused_sleep = 1; 2347 error = 0; 2348 while (sc->wsmoused_sleep && error == 0) 2349 error = tsleep(&sc->wsmoused_sleep, PPAUSE, 2350 "wsmoused_sleep", 0); 2351 return (error); 2352 case WSCONS_EVENT_WSMOUSED_ON: 2353 if (!sc->sc_accessops->getchar) 2354 /* no wsmoused(8) support in the display driver */ 2355 return (1); 2356 allocate_copybuffer(sc); 2357 CLR(sc->sc_flags, SC_PASTE_AVAIL); 2358 sc->wsmoused_dev = value; 2359 2360 for (i = 0 ; i < WSDISPLAY_DEFAULTSCREENS ; i++) 2361 if ((scr = sc->sc_scr[i]) != NULL) { 2362 scr->mouse = 2363 (WS_NCOLS(scr) * WS_NROWS(scr)) / 2; 2364 scr->cursor = scr->mouse; 2365 scr->cpy_start = 0; 2366 scr->cpy_end = 0; 2367 scr->orig_start = 0; 2368 scr->orig_end = 0; 2369 scr->mouse_flags = 0; 2370 } 2371 return (0); 2372 default: /* can't happen, really */ 2373 return 0; 2374 } 2375 } 2376 2377 void 2378 mouse_moverel(struct wsscreen *scr, int dx, int dy) 2379 { 2380 struct wsscreen_internal *dconf = scr->scr_dconf; 2381 u_int old_mouse = scr->mouse; 2382 int mouse_col = scr->mouse % N_COLS(dconf); 2383 int mouse_row = scr->mouse / N_COLS(dconf); 2384 2385 /* update position */ 2386 if (mouse_col + dx >= MAXCOL(dconf)) 2387 mouse_col = MAXCOL(dconf); 2388 else { 2389 if (mouse_col + dx <= 0) 2390 mouse_col = 0; 2391 else 2392 mouse_col += dx; 2393 } 2394 if (mouse_row + dy >= MAXROW(dconf)) 2395 mouse_row = MAXROW(dconf); 2396 else { 2397 if (mouse_row + dy <= 0) 2398 mouse_row = 0; 2399 else 2400 mouse_row += dy; 2401 } 2402 scr->mouse = mouse_row * N_COLS(dconf) + mouse_col; 2403 2404 /* if we have moved */ 2405 if (old_mouse != scr->mouse) { 2406 /* XXX unblank screen if display.ms_act */ 2407 if (ISSET(scr->mouse_flags, SEL_IN_PROGRESS)) { 2408 /* selection in progress */ 2409 mouse_copy_extend(scr); 2410 } else { 2411 inverse_char(scr, scr->mouse); 2412 if (ISSET(scr->mouse_flags, MOUSE_VISIBLE)) 2413 inverse_char(scr, old_mouse); 2414 else 2415 SET(scr->mouse_flags, MOUSE_VISIBLE); 2416 } 2417 } 2418 } 2419 2420 void 2421 inverse_char(struct wsscreen *scr, u_int pos) 2422 { 2423 struct wsscreen_internal *dconf = scr->scr_dconf; 2424 struct wsdisplay_charcell cell; 2425 int fg, bg, ul; 2426 int flags; 2427 int tmp; 2428 long attr; 2429 2430 GETCHAR(scr, pos, &cell); 2431 2432 (*dconf->emulops->unpack_attr)(dconf->emulcookie, cell.attr, &fg, 2433 &bg, &ul); 2434 2435 /* 2436 * Display the mouse cursor as a color inverted cell whenever 2437 * possible. If this is not possible, ask for the video reverse 2438 * attribute. 2439 */ 2440 flags = 0; 2441 if (dconf->scrdata->capabilities & WSSCREEN_WSCOLORS) { 2442 flags |= WSATTR_WSCOLORS; 2443 tmp = fg; 2444 fg = bg; 2445 bg = tmp; 2446 } else if (dconf->scrdata->capabilities & WSSCREEN_REVERSE) { 2447 flags |= WSATTR_REVERSE; 2448 } 2449 if ((*dconf->emulops->alloc_attr)(dconf->emulcookie, fg, bg, flags | 2450 (ul ? WSATTR_UNDERLINE : 0), &attr) == 0) { 2451 cell.attr = attr; 2452 PUTCHAR(dconf, pos, cell.uc, cell.attr); 2453 } 2454 } 2455 2456 void 2457 inverse_region(struct wsscreen *scr, u_int start, u_int end) 2458 { 2459 struct wsscreen_internal *dconf = scr->scr_dconf; 2460 u_int current_pos; 2461 u_int abs_end; 2462 2463 /* sanity check, useful because 'end' can be (u_int)-1 */ 2464 abs_end = N_COLS(dconf) * N_ROWS(dconf); 2465 if (end > abs_end) 2466 return; 2467 current_pos = start; 2468 while (current_pos <= end) 2469 inverse_char(scr, current_pos++); 2470 } 2471 2472 /* 2473 * Return the number of contiguous blank characters between the right margin 2474 * if border == 1 or between the next non-blank character and the current mouse 2475 * cursor if border == 0 2476 */ 2477 u_int 2478 skip_spc_right(struct wsscreen *scr, int border) 2479 { 2480 struct wsscreen_internal *dconf = scr->scr_dconf; 2481 struct wsdisplay_charcell cell; 2482 u_int current = scr->cpy_end; 2483 u_int mouse_col = scr->cpy_end % N_COLS(dconf); 2484 u_int limit = current + (N_COLS(dconf) - mouse_col - 1); 2485 u_int res = 0; 2486 2487 while (GETCHAR(scr, current, &cell) == 0 && cell.uc == ' ' && 2488 current <= limit) { 2489 current++; 2490 res++; 2491 } 2492 if (border == BORDER) { 2493 if (current > limit) 2494 return (res - 1); 2495 else 2496 return (0); 2497 } else { 2498 if (res != 0) 2499 return (res - 1); 2500 else 2501 return (res); 2502 } 2503 } 2504 2505 /* 2506 * Return the number of contiguous blank characters between the first of the 2507 * contiguous blank characters and the current mouse cursor 2508 */ 2509 u_int 2510 skip_spc_left(struct wsscreen *scr) 2511 { 2512 struct wsscreen_internal *dconf = scr->scr_dconf; 2513 struct wsdisplay_charcell cell; 2514 u_int current = scr->cpy_start; 2515 u_int mouse_col = scr->mouse % N_COLS(dconf); 2516 u_int limit = current - mouse_col; 2517 u_int res = 0; 2518 2519 while (GETCHAR(scr, current, &cell) == 0 && cell.uc == ' ' && 2520 current >= limit) { 2521 current--; 2522 res++; 2523 } 2524 if (res != 0) 2525 res--; 2526 return (res); 2527 } 2528 2529 /* 2530 * Class of characters 2531 * Stolen from xterm sources of the Xfree project (see cvs tag below) 2532 * $TOG: button.c /main/76 1997/07/30 16:56:19 kaleb $ 2533 */ 2534 static const int charClass[256] = { 2535 /* NUL SOH STX ETX EOT ENQ ACK BEL */ 2536 32, 1, 1, 1, 1, 1, 1, 1, 2537 /* BS HT NL VT NP CR SO SI */ 2538 1, 32, 1, 1, 1, 1, 1, 1, 2539 /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2540 1, 1, 1, 1, 1, 1, 1, 1, 2541 /* CAN EM SUB ESC FS GS RS US */ 2542 1, 1, 1, 1, 1, 1, 1, 1, 2543 /* SP ! " # $ % & ' */ 2544 32, 33, 34, 35, 36, 37, 38, 39, 2545 /* ( ) * + , - . / */ 2546 40, 41, 42, 43, 44, 45, 46, 47, 2547 /* 0 1 2 3 4 5 6 7 */ 2548 48, 48, 48, 48, 48, 48, 48, 48, 2549 /* 8 9 : ; < = > ? */ 2550 48, 48, 58, 59, 60, 61, 62, 63, 2551 /* @ A B C D E F G */ 2552 64, 48, 48, 48, 48, 48, 48, 48, 2553 /* H I J K L M N O */ 2554 48, 48, 48, 48, 48, 48, 48, 48, 2555 /* P Q R S T U V W */ 2556 48, 48, 48, 48, 48, 48, 48, 48, 2557 /* X Y Z [ \ ] ^ _ */ 2558 48, 48, 48, 91, 92, 93, 94, 48, 2559 /* ` a b c d e f g */ 2560 96, 48, 48, 48, 48, 48, 48, 48, 2561 /* h i j k l m n o */ 2562 48, 48, 48, 48, 48, 48, 48, 48, 2563 /* p q r s t u v w */ 2564 48, 48, 48, 48, 48, 48, 48, 48, 2565 /* x y z { | } ~ DEL */ 2566 48, 48, 48, 123, 124, 125, 126, 1, 2567 /* x80 x81 x82 x83 IND NEL SSA ESA */ 2568 1, 1, 1, 1, 1, 1, 1, 1, 2569 /* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2570 1, 1, 1, 1, 1, 1, 1, 1, 2571 /* DCS PU1 PU2 STS CCH MW SPA EPA */ 2572 1, 1, 1, 1, 1, 1, 1, 1, 2573 /* x98 x99 x9A CSI ST OSC PM APC */ 2574 1, 1, 1, 1, 1, 1, 1, 1, 2575 /* - i c/ L ox Y- | So */ 2576 160, 161, 162, 163, 164, 165, 166, 167, 2577 /* .. c0 ip << _ R0 - */ 2578 168, 169, 170, 171, 172, 173, 174, 175, 2579 /* o +- 2 3 ' u q| . */ 2580 176, 177, 178, 179, 180, 181, 182, 183, 2581 /* , 1 2 >> 1/4 1/2 3/4 ? */ 2582 184, 185, 186, 187, 188, 189, 190, 191, 2583 /* A` A' A^ A~ A: Ao AE C, */ 2584 48, 48, 48, 48, 48, 48, 48, 48, 2585 /* E` E' E^ E: I` I' I^ I: */ 2586 48, 48, 48, 48, 48, 48, 48, 48, 2587 /* D- N~ O` O' O^ O~ O: X */ 2588 48, 48, 48, 48, 48, 48, 48, 216, 2589 /* O/ U` U' U^ U: Y' P B */ 2590 48, 48, 48, 48, 48, 48, 48, 48, 2591 /* a` a' a^ a~ a: ao ae c, */ 2592 48, 48, 48, 48, 48, 48, 48, 48, 2593 /* e` e' e^ e: i` i' i^ i: */ 2594 48, 48, 48, 48, 48, 48, 48, 48, 2595 /* d n~ o` o' o^ o~ o: -: */ 2596 48, 48, 48, 48, 48, 48, 48, 248, 2597 /* o/ u` u' u^ u: y' P y: */ 2598 48, 48, 48, 48, 48, 48, 48, 48 2599 }; 2600 2601 /* 2602 * Find the first blank beginning after the current cursor position 2603 */ 2604 u_int 2605 skip_char_right(struct wsscreen *scr, u_int offset) 2606 { 2607 struct wsscreen_internal *dconf = scr->scr_dconf; 2608 struct wsdisplay_charcell cell; 2609 u_int current = offset; 2610 u_int limit = current + 2611 (N_COLS(dconf) - (scr->mouse % N_COLS(dconf)) - 1); 2612 u_int class; 2613 u_int res = 0; 2614 2615 GETCHAR(scr, current, &cell); 2616 class = charClass[cell.uc & 0xff]; 2617 while (GETCHAR(scr, current, &cell) == 0 && 2618 charClass[cell.uc & 0xff] == class && current <= limit) { 2619 current++; 2620 res++; 2621 } 2622 if (res != 0) 2623 res--; 2624 return (res); 2625 } 2626 2627 /* 2628 * Find the first non-blank character before the cursor position 2629 */ 2630 u_int 2631 skip_char_left(struct wsscreen *scr, u_int offset) 2632 { 2633 struct wsscreen_internal *dconf = scr->scr_dconf; 2634 struct wsdisplay_charcell cell; 2635 u_int current = offset; 2636 u_int limit = current - (scr->mouse % N_COLS(dconf)); 2637 u_int class; 2638 u_int res = 0; 2639 2640 GETCHAR(scr, current, &cell); 2641 class = charClass[cell.uc & 0xff]; 2642 while (GETCHAR(scr, current, &cell) == 0 && 2643 charClass[cell.uc & 0xff] == class && current >= limit) { 2644 current--; 2645 res++; 2646 } 2647 if (res != 0) 2648 res--; 2649 return (res); 2650 } 2651 2652 /* 2653 * Compare character classes 2654 */ 2655 u_int 2656 class_cmp(struct wsscreen *scr, u_int first, u_int second) 2657 { 2658 struct wsdisplay_charcell cell; 2659 u_int first_class; 2660 u_int second_class; 2661 2662 if (GETCHAR(scr, first, &cell) != 0) 2663 return (1); 2664 first_class = charClass[cell.uc & 0xff]; 2665 if (GETCHAR(scr, second, &cell) != 0) 2666 return (1); 2667 second_class = charClass[cell.uc & 0xff]; 2668 2669 if (first_class != second_class) 2670 return (1); 2671 else 2672 return (0); 2673 } 2674 2675 /* 2676 * Beginning of a copy operation 2677 */ 2678 void 2679 mouse_copy_start(struct wsscreen *scr) 2680 { 2681 u_int right; 2682 2683 /* if no selection, then that's the first one */ 2684 SET(scr->sc->sc_flags, SC_PASTE_AVAIL); 2685 2686 /* remove the previous selection */ 2687 if (ISSET(scr->mouse_flags, SEL_EXISTS)) 2688 remove_selection(scr); 2689 2690 /* initial show of the cursor */ 2691 if (!ISSET(scr->mouse_flags, MOUSE_VISIBLE)) 2692 inverse_char(scr, scr->mouse); 2693 2694 scr->cpy_start = scr->cpy_end = scr->mouse; 2695 scr->orig_start = scr->cpy_start; 2696 scr->orig_end = scr->cpy_end; 2697 scr->cursor = scr->cpy_end + 1; /* init value */ 2698 2699 /* useful later, in mouse_copy_extend */ 2700 right = skip_spc_right(scr, BORDER); 2701 if (right) 2702 SET(scr->mouse_flags, BLANK_TO_EOL); 2703 2704 SET(scr->mouse_flags, SEL_IN_PROGRESS | SEL_EXISTS | SEL_BY_CHAR); 2705 CLR(scr->mouse_flags, SEL_BY_WORD | SEL_BY_LINE); 2706 CLR(scr->mouse_flags, MOUSE_VISIBLE); /* cursor hidden in selection */ 2707 } 2708 2709 /* 2710 * Copy of the word under the cursor 2711 */ 2712 void 2713 mouse_copy_word(struct wsscreen *scr) 2714 { 2715 struct wsdisplay_charcell cell; 2716 u_int right; 2717 u_int left; 2718 2719 if (ISSET(scr->mouse_flags, SEL_EXISTS)) 2720 remove_selection(scr); 2721 2722 if (ISSET(scr->mouse_flags, MOUSE_VISIBLE)) 2723 inverse_char(scr, scr->mouse); 2724 2725 scr->cpy_start = scr->cpy_end = scr->mouse; 2726 2727 if (GETCHAR(scr, scr->mouse, &cell) == 0 && 2728 IS_ALPHANUM(cell.uc)) { 2729 right = skip_char_right(scr, scr->cpy_end); 2730 left = skip_char_left(scr, scr->cpy_start); 2731 } else { 2732 right = skip_spc_right(scr, NO_BORDER); 2733 left = skip_spc_left(scr); 2734 } 2735 2736 scr->cpy_start -= left; 2737 scr->cpy_end += right; 2738 scr->orig_start = scr->cpy_start; 2739 scr->orig_end = scr->cpy_end; 2740 scr->cursor = scr->cpy_end + 1; /* init value, never happen */ 2741 inverse_region(scr, scr->cpy_start, scr->cpy_end); 2742 2743 SET(scr->mouse_flags, SEL_IN_PROGRESS | SEL_EXISTS | SEL_BY_WORD); 2744 CLR(scr->mouse_flags, SEL_BY_CHAR | SEL_BY_LINE); 2745 /* mouse cursor hidden in the selection */ 2746 CLR(scr->mouse_flags, BLANK_TO_EOL | MOUSE_VISIBLE); 2747 } 2748 2749 /* 2750 * Copy of the current line 2751 */ 2752 void 2753 mouse_copy_line(struct wsscreen *scr) 2754 { 2755 struct wsscreen_internal *dconf = scr->scr_dconf; 2756 u_int row = scr->mouse / N_COLS(dconf); 2757 2758 if (ISSET(scr->mouse_flags, SEL_EXISTS)) 2759 remove_selection(scr); 2760 2761 if (ISSET(scr->mouse_flags, MOUSE_VISIBLE)) 2762 inverse_char(scr, scr->mouse); 2763 2764 scr->cpy_start = row * N_COLS(dconf); 2765 scr->cpy_end = scr->cpy_start + (N_COLS(dconf) - 1); 2766 scr->orig_start = scr->cpy_start; 2767 scr->orig_end = scr->cpy_end; 2768 scr->cursor = scr->cpy_end + 1; 2769 inverse_region(scr, scr->cpy_start, scr->cpy_end); 2770 2771 SET(scr->mouse_flags, SEL_IN_PROGRESS | SEL_EXISTS | SEL_BY_LINE); 2772 CLR(scr->mouse_flags, SEL_BY_CHAR | SEL_BY_WORD); 2773 /* mouse cursor hidden in the selection */ 2774 CLR(scr->mouse_flags, BLANK_TO_EOL | MOUSE_VISIBLE); 2775 } 2776 2777 /* 2778 * End of a copy operation 2779 */ 2780 void 2781 mouse_copy_end(struct wsscreen *scr) 2782 { 2783 CLR(scr->mouse_flags, SEL_IN_PROGRESS); 2784 if (ISSET(scr->mouse_flags, SEL_BY_WORD) || 2785 ISSET(scr->mouse_flags, SEL_BY_LINE)) { 2786 if (scr->cursor != scr->cpy_end + 1) 2787 inverse_char(scr, scr->cursor); 2788 scr->cursor = scr->cpy_end + 1; 2789 } 2790 } 2791 2792 2793 /* 2794 * Generic selection extend function 2795 */ 2796 void 2797 mouse_copy_extend(struct wsscreen *scr) 2798 { 2799 if (ISSET(scr->mouse_flags, SEL_BY_CHAR)) 2800 mouse_copy_extend_char(scr); 2801 if (ISSET(scr->mouse_flags, SEL_BY_WORD)) 2802 mouse_copy_extend_word(scr); 2803 if (ISSET(scr->mouse_flags, SEL_BY_LINE)) 2804 mouse_copy_extend_line(scr); 2805 } 2806 2807 /* 2808 * Extend a selected region, character by character 2809 */ 2810 void 2811 mouse_copy_extend_char(struct wsscreen *scr) 2812 { 2813 u_int right; 2814 2815 if (!ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 2816 if (ISSET(scr->mouse_flags, BLANK_TO_EOL)) { 2817 /* 2818 * First extension of selection. We handle special 2819 * cases of blank characters to eol 2820 */ 2821 2822 right = skip_spc_right(scr, BORDER); 2823 if (scr->mouse > scr->orig_start) { 2824 /* the selection goes to the lower part of 2825 the screen */ 2826 2827 /* remove the previous cursor, start of 2828 selection is now next line */ 2829 inverse_char(scr, scr->cpy_start); 2830 scr->cpy_start += (right + 1); 2831 scr->cpy_end = scr->cpy_start; 2832 scr->orig_start = scr->cpy_start; 2833 /* simulate the initial mark */ 2834 inverse_char(scr, scr->cpy_start); 2835 } else { 2836 /* the selection goes to the upper part 2837 of the screen */ 2838 /* remove the previous cursor, start of 2839 selection is now at the eol */ 2840 inverse_char(scr, scr->cpy_start); 2841 scr->orig_start += (right + 1); 2842 scr->cpy_start = scr->orig_start - 1; 2843 scr->cpy_end = scr->orig_start - 1; 2844 /* simulate the initial mark */ 2845 inverse_char(scr, scr->cpy_start); 2846 } 2847 CLR(scr->mouse_flags, BLANK_TO_EOL); 2848 } 2849 2850 if (scr->mouse < scr->orig_start && 2851 scr->cpy_end >= scr->orig_start) { 2852 /* we go to the upper part of the screen */ 2853 2854 /* reverse the old selection region */ 2855 remove_selection(scr); 2856 scr->cpy_end = scr->orig_start - 1; 2857 scr->cpy_start = scr->orig_start; 2858 } 2859 if (scr->cpy_start < scr->orig_start && 2860 scr->mouse >= scr->orig_start) { 2861 /* we go to the lower part of the screen */ 2862 2863 /* reverse the old selection region */ 2864 2865 remove_selection(scr); 2866 scr->cpy_start = scr->orig_start; 2867 scr->cpy_end = scr->orig_start - 1; 2868 } 2869 /* restore flags cleared in remove_selection() */ 2870 SET(scr->mouse_flags, SEL_IN_PROGRESS | SEL_EXISTS); 2871 } 2872 2873 if (scr->mouse >= scr->orig_start) { 2874 /* lower part of the screen */ 2875 if (scr->mouse > scr->cpy_end) { 2876 /* extending selection */ 2877 inverse_region(scr, scr->cpy_end + 1, scr->mouse); 2878 } else { 2879 /* reducing selection */ 2880 inverse_region(scr, scr->mouse + 1, scr->cpy_end); 2881 } 2882 scr->cpy_end = scr->mouse; 2883 } else { 2884 /* upper part of the screen */ 2885 if (scr->mouse < scr->cpy_start) { 2886 /* extending selection */ 2887 inverse_region(scr, scr->mouse, scr->cpy_start - 1); 2888 } else { 2889 /* reducing selection */ 2890 inverse_region(scr, scr->cpy_start, scr->mouse - 1); 2891 } 2892 scr->cpy_start = scr->mouse; 2893 } 2894 } 2895 2896 /* 2897 * Extend a selected region, word by word 2898 */ 2899 void 2900 mouse_copy_extend_word(struct wsscreen *scr) 2901 { 2902 u_int old_cpy_end; 2903 u_int old_cpy_start; 2904 2905 if (!ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 2906 /* remove cursor in selection (black one) */ 2907 if (scr->cursor != scr->cpy_end + 1) 2908 inverse_char(scr, scr->cursor); 2909 2910 /* now, switch between lower and upper part of the screen */ 2911 if (scr->mouse < scr->orig_start && 2912 scr->cpy_end >= scr->orig_start) { 2913 /* going to the upper part of the screen */ 2914 inverse_region(scr, scr->orig_end + 1, scr->cpy_end); 2915 scr->cpy_end = scr->orig_end; 2916 } 2917 2918 if (scr->mouse > scr->orig_end && 2919 scr->cpy_start <= scr->orig_start) { 2920 /* going to the lower part of the screen */ 2921 inverse_region(scr, scr->cpy_start, 2922 scr->orig_start - 1); 2923 scr->cpy_start = scr->orig_start; 2924 } 2925 } 2926 2927 if (scr->mouse >= scr->orig_start) { 2928 /* lower part of the screen */ 2929 if (scr->mouse > scr->cpy_end) { 2930 /* extending selection */ 2931 old_cpy_end = scr->cpy_end; 2932 scr->cpy_end = scr->mouse + 2933 skip_char_right(scr, scr->mouse); 2934 inverse_region(scr, old_cpy_end + 1, scr->cpy_end); 2935 } else { 2936 if (class_cmp(scr, scr->mouse, scr->mouse + 1)) { 2937 /* reducing selection (remove last word) */ 2938 old_cpy_end = scr->cpy_end; 2939 scr->cpy_end = scr->mouse; 2940 inverse_region(scr, scr->cpy_end + 1, 2941 old_cpy_end); 2942 } else { 2943 old_cpy_end = scr->cpy_end; 2944 scr->cpy_end = scr->mouse + 2945 skip_char_right(scr, scr->mouse); 2946 if (scr->cpy_end != old_cpy_end) { 2947 /* reducing selection, from the end of 2948 * next word */ 2949 inverse_region(scr, scr->cpy_end + 1, 2950 old_cpy_end); 2951 } 2952 } 2953 } 2954 } else { 2955 /* upper part of the screen */ 2956 if (scr->mouse < scr->cpy_start) { 2957 /* extending selection */ 2958 old_cpy_start = scr->cpy_start; 2959 scr->cpy_start = scr->mouse - 2960 skip_char_left(scr, scr->mouse); 2961 inverse_region(scr, scr->cpy_start, old_cpy_start - 1); 2962 } else { 2963 if (class_cmp(scr, scr->mouse - 1, scr->mouse)) { 2964 /* reducing selection (remove last word) */ 2965 old_cpy_start = scr->cpy_start; 2966 scr->cpy_start = scr->mouse; 2967 inverse_region(scr, old_cpy_start, 2968 scr->cpy_start - 1); 2969 } else { 2970 old_cpy_start = scr->cpy_start; 2971 scr->cpy_start = scr->mouse - 2972 skip_char_left(scr, scr->mouse); 2973 if (scr->cpy_start != old_cpy_start) { 2974 inverse_region(scr, old_cpy_start, 2975 scr->cpy_start - 1); 2976 } 2977 } 2978 } 2979 } 2980 2981 if (!ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 2982 /* display new cursor */ 2983 scr->cursor = scr->mouse; 2984 inverse_char(scr, scr->cursor); 2985 } 2986 } 2987 2988 /* 2989 * Extend a selected region, line by line 2990 */ 2991 void 2992 mouse_copy_extend_line(struct wsscreen *scr) 2993 { 2994 struct wsscreen_internal *dconf = scr->scr_dconf; 2995 u_int old_row; 2996 u_int new_row; 2997 u_int old_cpy_start; 2998 u_int old_cpy_end; 2999 3000 if (!ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 3001 /* remove cursor in selection (black one) */ 3002 if (scr->cursor != scr->cpy_end + 1) 3003 inverse_char(scr, scr->cursor); 3004 3005 /* now, switch between lower and upper part of the screen */ 3006 if (scr->mouse < scr->orig_start && 3007 scr->cpy_end >= scr->orig_start) { 3008 /* going to the upper part of the screen */ 3009 inverse_region(scr, scr->orig_end + 1, scr->cpy_end); 3010 scr->cpy_end = scr->orig_end; 3011 } 3012 3013 if (scr->mouse > scr->orig_end && 3014 scr->cpy_start <= scr->orig_start) { 3015 /* going to the lower part of the screen */ 3016 inverse_region(scr, scr->cpy_start, 3017 scr->orig_start - 1); 3018 scr->cpy_start = scr->orig_start; 3019 } 3020 } 3021 3022 if (scr->mouse >= scr->orig_start) { 3023 /* lower part of the screen */ 3024 if (scr->cursor == scr->cpy_end + 1) 3025 scr->cursor = scr->cpy_end; 3026 old_row = scr->cursor / N_COLS(dconf); 3027 new_row = scr->mouse / N_COLS(dconf); 3028 old_cpy_end = scr->cpy_end; 3029 scr->cpy_end = new_row * N_COLS(dconf) + MAXCOL(dconf); 3030 if (new_row > old_row) 3031 inverse_region(scr, old_cpy_end + 1, scr->cpy_end); 3032 else if (new_row < old_row) 3033 inverse_region(scr, scr->cpy_end + 1, old_cpy_end); 3034 } else { 3035 /* upper part of the screen */ 3036 old_row = scr->cursor / N_COLS(dconf); 3037 new_row = scr->mouse / N_COLS(dconf); 3038 old_cpy_start = scr->cpy_start; 3039 scr->cpy_start = new_row * N_COLS(dconf); 3040 if (new_row < old_row) 3041 inverse_region(scr, scr->cpy_start, old_cpy_start - 1); 3042 else if (new_row > old_row) 3043 inverse_region(scr, old_cpy_start, scr->cpy_start - 1); 3044 } 3045 3046 if (!ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 3047 /* display new cursor */ 3048 scr->cursor = scr->mouse; 3049 inverse_char(scr, scr->cursor); 3050 } 3051 } 3052 3053 /* 3054 * Add an extension to a selected region, word by word 3055 */ 3056 void 3057 mouse_copy_extend_after(struct wsscreen *scr) 3058 { 3059 u_int start_dist; 3060 u_int end_dist; 3061 3062 if (ISSET(scr->mouse_flags, SEL_EXISTS)) { 3063 SET(scr->mouse_flags, SEL_EXT_AFTER); 3064 mouse_hide(scr); /* hide current cursor */ 3065 3066 if (scr->cpy_start > scr->mouse) 3067 start_dist = scr->cpy_start - scr->mouse; 3068 else 3069 start_dist = scr->mouse - scr->cpy_start; 3070 if (scr->mouse > scr->cpy_end) 3071 end_dist = scr->mouse - scr->cpy_end; 3072 else 3073 end_dist = scr->cpy_end - scr->mouse; 3074 if (start_dist < end_dist) { 3075 /* upper part of the screen*/ 3076 scr->orig_start = scr->mouse + 1; 3077 /* only used in mouse_copy_extend_line() */ 3078 scr->cursor = scr->cpy_start; 3079 } else { 3080 /* lower part of the screen */ 3081 scr->orig_start = scr->mouse; 3082 /* only used in mouse_copy_extend_line() */ 3083 scr->cursor = scr->cpy_end; 3084 } 3085 if (ISSET(scr->mouse_flags, SEL_BY_CHAR)) 3086 mouse_copy_extend_char(scr); 3087 if (ISSET(scr->mouse_flags, SEL_BY_WORD)) 3088 mouse_copy_extend_word(scr); 3089 if (ISSET(scr->mouse_flags, SEL_BY_LINE)) 3090 mouse_copy_extend_line(scr); 3091 mouse_copy_selection(scr); 3092 } 3093 } 3094 3095 void 3096 mouse_hide(struct wsscreen *scr) 3097 { 3098 if (ISSET(scr->mouse_flags, MOUSE_VISIBLE)) { 3099 inverse_char(scr, scr->mouse); 3100 CLR(scr->mouse_flags, MOUSE_VISIBLE); 3101 } 3102 } 3103 3104 /* 3105 * Remove a previously selected region 3106 */ 3107 void 3108 remove_selection(struct wsscreen *scr) 3109 { 3110 if (ISSET(scr->mouse_flags, SEL_EXT_AFTER)) { 3111 /* reset the flag indicating an extension of selection */ 3112 CLR(scr->mouse_flags, SEL_EXT_AFTER); 3113 } 3114 inverse_region(scr, scr->cpy_start, scr->cpy_end); 3115 CLR(scr->mouse_flags, SEL_IN_PROGRESS | SEL_EXISTS); 3116 } 3117 3118 /* 3119 * Put the current visual selection in the selection buffer 3120 */ 3121 void 3122 mouse_copy_selection(struct wsscreen *scr) 3123 { 3124 struct wsscreen_internal *dconf = scr->scr_dconf; 3125 struct wsdisplay_charcell cell; 3126 u_int current = 0; 3127 u_int blank = current; 3128 u_int buf_end = (N_COLS(dconf) + 1) * N_ROWS(dconf); 3129 u_int sel_cur; 3130 u_int sel_end; 3131 3132 sel_cur = scr->cpy_start; 3133 sel_end = scr->cpy_end; 3134 3135 while (sel_cur <= sel_end && current < buf_end - 1) { 3136 if (GETCHAR(scr, sel_cur, &cell) != 0) 3137 break; 3138 scr->sc->sc_copybuffer[current] = cell.uc; 3139 if (!IS_SPACE(cell.uc)) 3140 blank = current + 1; /* first blank after non-blank */ 3141 current++; 3142 if (sel_cur % N_COLS(dconf) == MAXCOL(dconf)) { 3143 /* 3144 * If we are on the last column of the screen, 3145 * insert a carriage return. 3146 */ 3147 scr->sc->sc_copybuffer[blank] = '\r'; 3148 current = ++blank; 3149 } 3150 sel_cur++; 3151 } 3152 3153 scr->sc->sc_copybuffer[current] = '\0'; 3154 } 3155 3156 /* 3157 * Paste the current selection 3158 */ 3159 void 3160 mouse_paste(struct wsscreen *scr) 3161 { 3162 char *current = scr->sc->sc_copybuffer; 3163 struct tty *tp; 3164 u_int len; 3165 3166 if (ISSET(scr->sc->sc_flags, SC_PASTE_AVAIL)) { 3167 if (!WSSCREEN_HAS_TTY(scr)) 3168 return; 3169 3170 tp = scr->scr_tty; 3171 for (len = strlen(scr->sc->sc_copybuffer); len != 0; len--) 3172 (*linesw[tp->t_line].l_rint)(*current++, tp); 3173 } 3174 } 3175 3176 /* 3177 * Handle the z axis. 3178 * The z axis (roller or wheel) is mapped by default to scrollback. 3179 */ 3180 void 3181 mouse_zaxis(struct wsscreen *scr, int z) 3182 { 3183 if (z < 0) 3184 wsscrollback(scr->sc, WSDISPLAY_SCROLL_BACKWARD); 3185 else 3186 wsscrollback(scr->sc, WSDISPLAY_SCROLL_FORWARD); 3187 } 3188 3189 /* 3190 * Allocate the copy buffer. The size is: 3191 * (cols + 1) * (rows) 3192 * (+1 for '\n' at the end of lines), 3193 * where cols and rows are the maximum of column and rows of all screens. 3194 */ 3195 void 3196 allocate_copybuffer(struct wsdisplay_softc *sc) 3197 { 3198 int nscreens = sc->sc_scrdata->nscreens; 3199 int i, s; 3200 const struct wsscreen_descr **screens_list = sc->sc_scrdata->screens; 3201 const struct wsscreen_descr *current; 3202 u_int size = sc->sc_copybuffer_size; 3203 3204 s = spltty(); 3205 for (i = 0; i < nscreens; i++) { 3206 current = *screens_list; 3207 if ((current->ncols + 1) * current->nrows > size) 3208 size = (current->ncols + 1) * current->nrows; 3209 screens_list++; 3210 } 3211 if (size != sc->sc_copybuffer_size && sc->sc_copybuffer_size != 0) { 3212 bzero(sc->sc_copybuffer, sc->sc_copybuffer_size); 3213 free(sc->sc_copybuffer, M_DEVBUF); 3214 } 3215 if ((sc->sc_copybuffer = (char *)malloc(size, M_DEVBUF, M_NOWAIT)) == 3216 NULL) { 3217 printf("%s: couldn't allocate copy buffer\n", 3218 sc->sc_dv.dv_xname); 3219 size = 0; 3220 } 3221 sc->sc_copybuffer_size = size; 3222 splx(s); 3223 } 3224 3225 /* Remove selection and cursor on current screen */ 3226 void 3227 mouse_remove(struct wsscreen *scr) 3228 { 3229 if (ISSET(scr->mouse_flags, SEL_EXISTS)) 3230 remove_selection(scr); 3231 3232 mouse_hide(scr); 3233 } 3234 3235 /* Send a wscons event to notify wsmoused(8) to release the mouse device */ 3236 void 3237 wsmoused_release(struct wsdisplay_softc *sc) 3238 { 3239 #if NWSMOUSE > 0 3240 struct device *wsms_dev = NULL; 3241 struct device **wsms_dev_list; 3242 int is_wsmouse = 0; 3243 #if NWSMUX > 0 3244 int is_wsmux = 0; 3245 #endif /* NWSMUX > 0 */ 3246 3247 if (sc->wsmoused_dev) { 3248 /* wsmoused(8) is running */ 3249 3250 wsms_dev_list = (struct device **) wsmouse_cd.cd_devs; 3251 if (!wsms_dev_list) 3252 /* no wsmouse device exists */ 3253 return ; 3254 3255 /* test whether device opened by wsmoused(8) is a wsmux device 3256 * (/dev/wsmouse) or a wsmouse device (/dev/wsmouse{0..n} */ 3257 3258 #if NWSMUX > 0 3259 /* obtain major of /dev/wsmouse multiplexor device */ 3260 /* XXX first member of wsmux_softc is of type struct device */ 3261 if (cdevsw[major(sc->wsmoused_dev)].d_open == wsmuxopen) 3262 is_wsmux = 1; 3263 3264 if (is_wsmux && (minor(sc->wsmoused_dev) == WSMOUSEDEVCF_MUX)) { 3265 /* /dev/wsmouse case */ 3266 /* XXX at least, wsmouse0 exist */ 3267 wsms_dev = wsms_dev_list[0]; 3268 } 3269 #endif /* NWSMUX > 0 */ 3270 3271 /* obtain major of /dev/wsmouse{0..n} devices */ 3272 if (wsmouse_cd.cd_ndevs > 0) { 3273 if (cdevsw[major(sc->wsmoused_dev)].d_open == 3274 wsmouseopen) 3275 is_wsmouse = 1; 3276 } 3277 3278 if (is_wsmouse && (minor(sc->wsmoused_dev) <= NWSMOUSE)) { 3279 /* /dev/wsmouseX case */ 3280 if (minor(sc->wsmoused_dev) < wsmouse_cd.cd_ndevs) { 3281 wsms_dev = 3282 wsms_dev_list[minor(sc->wsmoused_dev)]; 3283 } 3284 else 3285 /* no corresponding /dev/wsmouseX device */ 3286 return; 3287 } 3288 3289 /* inject event to notify wsmoused(8) to close mouse device */ 3290 if (wsms_dev != NULL) 3291 wsmouse_input(wsms_dev, 0, 0, 0, 0, 0, 3292 WSMOUSE_INPUT_WSMOUSED_CLOSE); 3293 } 3294 #endif /* NWSMOUSE > 0 */ 3295 } 3296 3297 /* Wakeup wsmoused(8), so that the mouse device can be reopened */ 3298 void 3299 wsmoused_wakeup(struct wsdisplay_softc *sc) 3300 { 3301 #if NWSMOUSE > 0 3302 if (sc->wsmoused_dev) { 3303 sc->wsmoused_sleep = 0; 3304 wakeup(&sc->wsmoused_sleep); 3305 } 3306 #endif /* NWSMOUSE > 0 */ 3307 } 3308 #endif /* WSMOUSED_SUPPORT */ 3309