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