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