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