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