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