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