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