1 /* $OpenBSD: wsdisplay.c,v 1.36 2001/11/26 16:02:30 mickey 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 case WSDISPLAYIO_GETSCREEN: 1137 return (wsdisplay_getscreen(sc, 1138 (struct wsdisplay_addscreendata *)data)); 1139 1140 case WSDISPLAYIO_SETSCREEN: 1141 return (wsdisplay_switch((void *)sc, *(int *)data, 1)); 1142 } 1143 1144 /* check ioctls for display */ 1145 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1146 flag, p)); 1147 } 1148 1149 int 1150 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p) 1151 struct wsdisplay_softc *sc; 1152 u_long cmd; 1153 caddr_t data; 1154 int flag; 1155 struct proc *p; 1156 { 1157 int error; 1158 void *buf; 1159 size_t fontsz; 1160 #if defined(COMPAT_14) && NWSKBD > 0 1161 struct wsmux_device wsmuxdata; 1162 #endif 1163 1164 switch (cmd) { 1165 case WSDISPLAYIO_WSMOUSED: 1166 error = wsmoused(sc, cmd, data, flag, p); 1167 return (error); 1168 case WSDISPLAYIO_ADDSCREEN: 1169 #define d ((struct wsdisplay_addscreendata *)data) 1170 if ((error = wsdisplay_addscreen(sc, d->idx, 1171 d->screentype, d->emul)) == 0) 1172 wsdisplay_addscreen_print(sc, d->idx, 0); 1173 return (error); 1174 #undef d 1175 case WSDISPLAYIO_DELSCREEN: 1176 #define d ((struct wsdisplay_delscreendata *)data) 1177 return (wsdisplay_delscreen(sc, d->idx, d->flags)); 1178 #undef d 1179 case WSDISPLAYIO_GETSCREEN: 1180 return (wsdisplay_getscreen(sc, 1181 (struct wsdisplay_addscreendata *)data)); 1182 case WSDISPLAYIO_SETSCREEN: 1183 return (wsdisplay_switch((void *)sc, *(int *)data, 1)); 1184 case WSDISPLAYIO_LDFONT: 1185 #define d ((struct wsdisplay_font *)data) 1186 if (!sc->sc_accessops->load_font) 1187 return (EINVAL); 1188 if (d->index >= WSDISPLAY_MAXFONT) 1189 return (EINVAL); 1190 fontsz = d->fontheight * d->stride * d->numchars; 1191 if (fontsz > WSDISPLAY_MAXFONTSZ) 1192 return (EINVAL); 1193 1194 buf = malloc(fontsz, M_DEVBUF, M_WAITOK); 1195 error = copyin(d->data, buf, fontsz); 1196 if (error) { 1197 free(buf, M_DEVBUF); 1198 return (error); 1199 } 1200 d->data = buf; 1201 error = 1202 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d); 1203 if (error) 1204 free(buf, M_DEVBUF); 1205 else if (d->index >= 0 || d->index < WSDISPLAY_MAXFONT) 1206 sc->sc_fonts[d->index] = *d; 1207 return (error); 1208 1209 case WSDISPLAYIO_LSFONT: 1210 if (d->index < 0 || d->index >= WSDISPLAY_MAXFONT) 1211 return (EINVAL); 1212 *d = sc->sc_fonts[d->index]; 1213 return (0); 1214 1215 case WSDISPLAYIO_DELFONT: 1216 return (EINVAL); 1217 #undef d 1218 1219 #if NWSKBD > 0 1220 #ifdef COMPAT_14 1221 case _O_WSDISPLAYIO_SETKEYBOARD: 1222 #define d ((struct wsdisplay_kbddata *)data) 1223 switch (d->op) { 1224 case _O_WSDISPLAY_KBD_ADD: 1225 if (d->idx == -1) { 1226 d->idx = wskbd_pickfree(); 1227 if (d->idx == -1) 1228 return (ENXIO); 1229 } 1230 wsmuxdata.type = WSMUX_KBD; 1231 wsmuxdata.idx = d->idx; 1232 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, 1233 WSMUX_ADD_DEVICE, 1234 (caddr_t)&wsmuxdata, flag, p)); 1235 case _O_WSDISPLAY_KBD_DEL: 1236 wsmuxdata.type = WSMUX_KBD; 1237 wsmuxdata.idx = d->idx; 1238 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, 1239 WSMUX_REMOVE_DEVICE, 1240 (caddr_t)&wsmuxdata, flag, p)); 1241 default: 1242 return (EINVAL); 1243 } 1244 #undef d 1245 #endif 1246 1247 case WSMUX_ADD_DEVICE: 1248 #define d ((struct wsmux_device *)data) 1249 if (d->idx == -1 && d->type == WSMUX_KBD) 1250 d->idx = wskbd_pickfree(); 1251 #undef d 1252 /* fall into */ 1253 case WSMUX_INJECTEVENT: 1254 case WSMUX_REMOVE_DEVICE: 1255 case WSMUX_LIST_DEVICES: 1256 return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, cmd, data, flag,p)); 1257 #endif /* NWSKBD > 0 */ 1258 1259 } 1260 return (EINVAL); 1261 } 1262 1263 paddr_t 1264 wsdisplaymmap(dev, offset, prot) 1265 dev_t dev; 1266 off_t offset; 1267 int prot; 1268 { 1269 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1270 struct wsscreen *scr; 1271 1272 if (ISWSDISPLAYCTL(dev)) 1273 return (-1); 1274 1275 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1276 1277 if (!(scr->scr_flags & SCR_GRAPHICS)) 1278 return (-1); 1279 1280 /* pass mmap to display */ 1281 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot)); 1282 } 1283 1284 int 1285 wsdisplayselect(dev, events, p) 1286 dev_t dev; 1287 int events; 1288 struct proc *p; 1289 { 1290 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1291 struct wsscreen *scr; 1292 1293 if (ISWSDISPLAYCTL(dev)) 1294 return (0); 1295 1296 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1297 1298 if (WSSCREEN_HAS_TTY(scr)) 1299 return (ttselect(dev, events, p)); 1300 else 1301 return (0); 1302 } 1303 1304 int 1305 wsdisplaykqfilter(dev, kn) 1306 dev_t dev; 1307 struct knote *kn; 1308 { 1309 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)]; 1310 struct wsscreen *scr; 1311 1312 if (ISWSDISPLAYCTL(dev)) 1313 return (1); 1314 1315 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]; 1316 1317 if (WSSCREEN_HAS_TTY(scr)) 1318 return (ttkqfilter(dev, kn)); 1319 else 1320 return (1); 1321 } 1322 1323 void 1324 wsdisplaystart(tp) 1325 struct tty *tp; 1326 { 1327 struct wsdisplay_softc *sc; 1328 struct wsscreen *scr; 1329 int s, n, unit; 1330 u_char *buf; 1331 1332 unit = WSDISPLAYUNIT(tp->t_dev); 1333 if (unit >= wsdisplay_cd.cd_ndevs || 1334 (sc = wsdisplay_cd.cd_devs[unit]) == NULL) 1335 return; 1336 1337 s = spltty(); 1338 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { 1339 splx(s); 1340 return; 1341 } 1342 if (tp->t_outq.c_cc == 0 && tp->t_wsel.si_selpid == 0) 1343 goto low; 1344 1345 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]; 1346 if (scr->scr_hold_screen) { 1347 tp->t_state |= TS_TIMEOUT; 1348 splx(s); 1349 return; 1350 } 1351 tp->t_state |= TS_BUSY; 1352 splx(s); 1353 1354 /* 1355 * Drain output from ring buffer. 1356 * The output will normally be in one contiguous chunk, but when the 1357 * ring wraps, it will be in two pieces.. one at the end of the ring, 1358 * the other at the start. For performance, rather than loop here, 1359 * we output one chunk, see if there's another one, and if so, output 1360 * it too. 1361 */ 1362 1363 n = ndqb(&tp->t_outq, 0); 1364 buf = tp->t_outq.c_cf; 1365 1366 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1367 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1368 wsdisplay_burn(sc, WSDISPLAY_BURN_OUTPUT); 1369 if (scr == sc->sc_focus) { 1370 if (IS_SEL_EXISTS(sc->sc_focus)) 1371 /* hide a potential selection */ 1372 remove_selection(sc); 1373 /* hide a potential mouse cursor */ 1374 mouse_hide(sc); 1375 } 1376 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie, 1377 buf, n, 0); 1378 } 1379 ndflush(&tp->t_outq, n); 1380 1381 if ((n = ndqb(&tp->t_outq, 0)) > 0) { 1382 buf = tp->t_outq.c_cf; 1383 1384 if (!(scr->scr_flags & SCR_GRAPHICS)) { 1385 KASSERT(WSSCREEN_HAS_EMULATOR(scr)); 1386 wsdisplay_burn(sc, WSDISPLAY_BURN_OUTPUT); 1387 (*scr->scr_dconf->wsemul->output) 1388 (scr->scr_dconf->wsemulcookie, buf, n, 0); 1389 } 1390 ndflush(&tp->t_outq, n); 1391 } 1392 1393 s = spltty(); 1394 tp->t_state &= ~TS_BUSY; 1395 1396 tp->t_state |= TS_TIMEOUT; 1397 timeout_add(&tp->t_rstrt_to, (hz > 128) ? (hz / 128) : 1); 1398 1399 if (tp->t_outq.c_cc <= tp->t_lowat) { 1400 low: 1401 if (tp->t_state&TS_ASLEEP) { 1402 tp->t_state &= ~TS_ASLEEP; 1403 wakeup((caddr_t)&tp->t_outq); 1404 } 1405 selwakeup(&tp->t_wsel); 1406 } 1407 splx(s); 1408 } 1409 1410 int 1411 wsdisplaystop(tp, flag) 1412 struct tty *tp; 1413 int flag; 1414 { 1415 int s; 1416 1417 s = spltty(); 1418 if (ISSET(tp->t_state, TS_BUSY)) 1419 if (!ISSET(tp->t_state, TS_TTSTOP)) 1420 SET(tp->t_state, TS_FLUSH); 1421 splx(s); 1422 1423 return (0); 1424 } 1425 1426 /* Set line parameters. */ 1427 int 1428 wsdisplayparam(tp, t) 1429 struct tty *tp; 1430 struct termios *t; 1431 { 1432 1433 tp->t_ispeed = t->c_ispeed; 1434 tp->t_ospeed = t->c_ospeed; 1435 tp->t_cflag = t->c_cflag; 1436 return (0); 1437 } 1438 1439 /* 1440 * Callbacks for the emulation code. 1441 */ 1442 void 1443 wsdisplay_emulbell(v) 1444 void *v; 1445 { 1446 struct wsscreen *scr = v; 1447 1448 if (scr == NULL) /* console, before real attach */ 1449 return; 1450 1451 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */ 1452 return; 1453 1454 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL, 1455 FWRITE, NULL); 1456 } 1457 1458 void 1459 wsdisplay_emulinput(v, data, count) 1460 void *v; 1461 const u_char *data; 1462 u_int count; 1463 { 1464 struct wsscreen *scr = v; 1465 struct tty *tp; 1466 1467 if (v == NULL) /* console, before real attach */ 1468 return; 1469 1470 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */ 1471 return; 1472 if (!WSSCREEN_HAS_TTY(scr)) 1473 return; 1474 1475 tp = scr->scr_tty; 1476 while (count-- > 0) 1477 (*linesw[tp->t_line].l_rint)(*data++, tp); 1478 } 1479 1480 /* 1481 * Calls from the keyboard interface. 1482 */ 1483 void 1484 wsdisplay_kbdinput(dev, ks) 1485 struct device *dev; 1486 keysym_t ks; 1487 { 1488 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1489 struct wsscreen *scr; 1490 char *dp; 1491 int count; 1492 struct tty *tp; 1493 1494 KASSERT(sc != NULL); 1495 1496 scr = sc->sc_focus; 1497 1498 if (!scr || !WSSCREEN_HAS_TTY(scr)) 1499 return; 1500 1501 tp = scr->scr_tty; 1502 1503 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1504 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp); 1505 else if (WSSCREEN_HAS_EMULATOR(scr)) { 1506 count = (*scr->scr_dconf->wsemul->translate) 1507 (scr->scr_dconf->wsemulcookie, ks, &dp); 1508 while (count-- > 0) 1509 (*linesw[tp->t_line].l_rint)(*dp++, tp); 1510 } 1511 } 1512 1513 #ifdef WSDISPLAY_COMPAT_RAWKBD 1514 int 1515 wsdisplay_update_rawkbd(sc, scr) 1516 struct wsdisplay_softc *sc; 1517 struct wsscreen *scr; 1518 { 1519 int s, raw, data, error; 1520 s = spltty(); 1521 1522 raw = (scr ? scr->scr_rawkbd : 0); 1523 1524 if (scr != sc->sc_focus || 1525 sc->sc_rawkbd == raw) { 1526 splx(s); 1527 return (0); 1528 } 1529 1530 data = raw ? WSKBD_RAW : WSKBD_TRANSLATED; 1531 error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, WSKBDIO_SETMODE, 1532 (caddr_t)&data, 0, 0); 1533 if (!error) 1534 sc->sc_rawkbd = raw; 1535 splx(s); 1536 return (error); 1537 } 1538 #endif 1539 1540 int 1541 wsdisplay_switch3(arg, error, waitok) 1542 void *arg; 1543 int error, waitok; 1544 { 1545 struct wsdisplay_softc *sc = arg; 1546 int no; 1547 struct wsscreen *scr; 1548 1549 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1550 printf("wsdisplay_switch3: not switching\n"); 1551 return (EINVAL); 1552 } 1553 1554 no = sc->sc_screenwanted; 1555 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1556 panic("wsdisplay_switch3: invalid screen %d", no); 1557 scr = sc->sc_scr[no]; 1558 if (!scr) { 1559 printf("wsdisplay_switch3: screen %d disappeared\n", no); 1560 error = ENXIO; 1561 } 1562 1563 if (error) { 1564 /* try to recover, avoid recursion */ 1565 1566 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1567 printf("wsdisplay_switch3: giving up\n"); 1568 sc->sc_focus = 0; 1569 #ifdef WSDISPLAY_COMPAT_RAWKBD 1570 wsdisplay_update_rawkbd(sc, 0); 1571 #endif 1572 sc->sc_flags &= ~SC_SWITCHPENDING; 1573 return (error); 1574 } 1575 1576 sc->sc_screenwanted = sc->sc_oldscreen; 1577 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1578 return (wsdisplay_switch1(arg, 0, waitok)); 1579 } 1580 1581 sc->sc_flags &= ~SC_SWITCHPENDING; 1582 1583 if (!error && (scr->scr_flags & SCR_WAITACTIVE)) 1584 wakeup(scr); 1585 return (error); 1586 } 1587 1588 int 1589 wsdisplay_switch2(arg, error, waitok) 1590 void *arg; 1591 int error, waitok; 1592 { 1593 struct wsdisplay_softc *sc = arg; 1594 int no; 1595 struct wsscreen *scr; 1596 1597 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1598 printf("wsdisplay_switch2: not switching\n"); 1599 return (EINVAL); 1600 } 1601 1602 no = sc->sc_screenwanted; 1603 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1604 panic("wsdisplay_switch2: invalid screen %d", no); 1605 scr = sc->sc_scr[no]; 1606 if (!scr) { 1607 printf("wsdisplay_switch2: screen %d disappeared\n", no); 1608 error = ENXIO; 1609 } 1610 1611 if (error) { 1612 /* try to recover, avoid recursion */ 1613 1614 if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) { 1615 printf("wsdisplay_switch2: giving up\n"); 1616 sc->sc_focus = 0; 1617 sc->sc_flags &= ~SC_SWITCHPENDING; 1618 return (error); 1619 } 1620 1621 sc->sc_screenwanted = sc->sc_oldscreen; 1622 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1623 return (wsdisplay_switch1(arg, 0, waitok)); 1624 } 1625 1626 sc->sc_focusidx = no; 1627 sc->sc_focus = scr; 1628 1629 #ifdef WSDISPLAY_COMPAT_RAWKBD 1630 (void) wsdisplay_update_rawkbd(sc, scr); 1631 #endif 1632 /* keyboard map??? */ 1633 1634 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3) 1635 if (scr->scr_syncops) { 1636 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok, 1637 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc); 1638 if (error == EAGAIN) { 1639 /* switch will be done asynchronously */ 1640 return (0); 1641 } 1642 } 1643 1644 return (wsdisplay_switch3(sc, error, waitok)); 1645 } 1646 1647 int 1648 wsdisplay_switch1(arg, error, waitok) 1649 void *arg; 1650 int error, waitok; 1651 { 1652 struct wsdisplay_softc *sc = arg; 1653 int no; 1654 struct wsscreen *scr; 1655 1656 if (!(sc->sc_flags & SC_SWITCHPENDING)) { 1657 printf("wsdisplay_switch1: not switching\n"); 1658 return (EINVAL); 1659 } 1660 1661 no = sc->sc_screenwanted; 1662 if (no == WSDISPLAY_NULLSCREEN) { 1663 sc->sc_flags &= ~SC_SWITCHPENDING; 1664 if (!error) { 1665 sc->sc_focus = 0; 1666 } 1667 wakeup(sc); 1668 return (error); 1669 } 1670 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1671 panic("wsdisplay_switch1: invalid screen %d", no); 1672 scr = sc->sc_scr[no]; 1673 if (!scr) { 1674 printf("wsdisplay_switch1: screen %d disappeared\n", no); 1675 error = ENXIO; 1676 } 1677 1678 if (error) { 1679 sc->sc_flags &= ~SC_SWITCHPENDING; 1680 return (error); 1681 } 1682 1683 #define wsswitch_cb2 ((void (*) __P((void *, int, int)))wsdisplay_switch2) 1684 error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 1685 scr->scr_dconf->emulcookie, 1686 waitok, 1687 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc); 1688 if (error == EAGAIN) { 1689 /* switch will be done asynchronously */ 1690 return (0); 1691 } 1692 1693 return (wsdisplay_switch2(sc, error, waitok)); 1694 } 1695 1696 int 1697 wsdisplay_switch(dev, no, waitok) 1698 struct device *dev; 1699 int no, waitok; 1700 { 1701 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1702 int s, res = 0; 1703 struct wsscreen *scr; 1704 1705 if (no != WSDISPLAY_NULLSCREEN && 1706 (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])) 1707 return (ENXIO); 1708 1709 s = spltty(); 1710 1711 if ((sc->sc_focus && no == sc->sc_focusidx) || 1712 (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) { 1713 splx(s); 1714 return (0); 1715 } 1716 1717 if (sc->sc_flags & SC_SWITCHPENDING) { 1718 splx(s); 1719 return (EBUSY); 1720 } 1721 1722 sc->sc_flags |= SC_SWITCHPENDING; 1723 sc->sc_screenwanted = no; 1724 1725 splx(s); 1726 1727 scr = sc->sc_focus; 1728 if (!scr) { 1729 sc->sc_oldscreen = WSDISPLAY_NULLSCREEN; 1730 return (wsdisplay_switch1(sc, 0, waitok)); 1731 } else 1732 sc->sc_oldscreen = sc->sc_focusidx; 1733 1734 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1) 1735 if (scr->scr_syncops) { 1736 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok, 1737 sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc); 1738 if (res == EAGAIN) { 1739 /* switch will be done asynchronously */ 1740 return (0); 1741 } 1742 } else if (scr->scr_flags & SCR_GRAPHICS) { 1743 /* no way to save state */ 1744 res = EBUSY; 1745 } 1746 1747 if (IS_SEL_EXISTS(sc->sc_focus)) 1748 /* hide a potential selection */ 1749 remove_selection(sc); 1750 1751 mouse_hide(sc); /* hide a potential mouse cursor */ 1752 1753 return (wsdisplay_switch1(sc, res, waitok)); 1754 } 1755 1756 void 1757 wsdisplay_reset(dev, op) 1758 struct device *dev; 1759 enum wsdisplay_resetops op; 1760 { 1761 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1762 struct wsscreen *scr; 1763 1764 KASSERT(sc != NULL); 1765 scr = sc->sc_focus; 1766 1767 if (!scr) 1768 return; 1769 1770 switch (op) { 1771 case WSDISPLAY_RESETEMUL: 1772 if (!WSSCREEN_HAS_EMULATOR(scr)) 1773 break; 1774 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie, 1775 WSEMUL_RESET); 1776 break; 1777 case WSDISPLAY_RESETCLOSE: 1778 wsdisplay_closescreen(sc, scr); 1779 break; 1780 } 1781 } 1782 1783 /* 1784 * Interface for (external) VT switch / process synchronization code 1785 */ 1786 int 1787 wsscreen_attach_sync(scr, ops, cookie) 1788 struct wsscreen *scr; 1789 const struct wscons_syncops *ops; 1790 void *cookie; 1791 { 1792 if (scr->scr_syncops) { 1793 /* 1794 * The screen is already claimed. 1795 * Check if the owner is still alive. 1796 */ 1797 if ((*scr->scr_syncops->check)(scr->scr_synccookie)) 1798 return (EBUSY); 1799 } 1800 scr->scr_syncops = ops; 1801 scr->scr_synccookie = cookie; 1802 return (0); 1803 } 1804 1805 int 1806 wsscreen_detach_sync(scr) 1807 struct wsscreen *scr; 1808 { 1809 if (!scr->scr_syncops) 1810 return (EINVAL); 1811 scr->scr_syncops = 0; 1812 return (0); 1813 } 1814 1815 int 1816 wsscreen_lookup_sync(scr, ops, cookiep) 1817 struct wsscreen *scr; 1818 const struct wscons_syncops *ops; /* used as ID */ 1819 void **cookiep; 1820 { 1821 if (!scr->scr_syncops || ops != scr->scr_syncops) 1822 return (EINVAL); 1823 *cookiep = scr->scr_synccookie; 1824 return (0); 1825 } 1826 1827 /* 1828 * Interface to virtual screen stuff 1829 */ 1830 int 1831 wsdisplay_maxscreenidx(sc) 1832 struct wsdisplay_softc *sc; 1833 { 1834 return (WSDISPLAY_MAXSCREEN - 1); 1835 } 1836 1837 int 1838 wsdisplay_screenstate(sc, idx) 1839 struct wsdisplay_softc *sc; 1840 int idx; 1841 { 1842 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN) 1843 return (EINVAL); 1844 if (!sc->sc_scr[idx]) 1845 return (ENXIO); 1846 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0); 1847 } 1848 1849 int 1850 wsdisplay_getactivescreen(sc) 1851 struct wsdisplay_softc *sc; 1852 { 1853 return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN); 1854 } 1855 1856 int 1857 wsscreen_switchwait(sc, no) 1858 struct wsdisplay_softc *sc; 1859 int no; 1860 { 1861 struct wsscreen *scr; 1862 int s, res = 0; 1863 1864 if (no == WSDISPLAY_NULLSCREEN) { 1865 s = spltty(); 1866 while (sc->sc_focus && res == 0) { 1867 res = tsleep(sc, PCATCH, "wswait", 0); 1868 } 1869 splx(s); 1870 return (res); 1871 } 1872 1873 if (no < 0 || no >= WSDISPLAY_MAXSCREEN) 1874 return (ENXIO); 1875 scr = sc->sc_scr[no]; 1876 if (!scr) 1877 return (ENXIO); 1878 1879 s = spltty(); 1880 if (scr != sc->sc_focus) { 1881 scr->scr_flags |= SCR_WAITACTIVE; 1882 res = tsleep(scr, PCATCH, "wswait", 0); 1883 if (scr != sc->sc_scr[no]) 1884 res = ENXIO; /* disappeared in the meantime */ 1885 else 1886 scr->scr_flags &= ~SCR_WAITACTIVE; 1887 } 1888 splx(s); 1889 return (res); 1890 } 1891 1892 void 1893 wsdisplay_kbdholdscreen(dev, hold) 1894 struct device *dev; 1895 int hold; 1896 { 1897 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev; 1898 struct wsscreen *scr; 1899 1900 scr = sc->sc_focus; 1901 1902 if (hold) 1903 scr->scr_hold_screen = 1; 1904 else { 1905 scr->scr_hold_screen = 0; 1906 timeout_add(&scr->scr_tty->t_rstrt_to, 0); /* "immediate" */ 1907 } 1908 } 1909 1910 #if NWSKBD > 0 1911 struct device * 1912 wsdisplay_set_console_kbd(kbddv) 1913 struct device *kbddv; 1914 { 1915 if (!wsdisplay_console_device) 1916 return (0); 1917 if (wskbd_add_mux(kbddv->dv_unit, wsdisplay_console_device->sc_muxdv)) 1918 return (0); 1919 return (&wsdisplay_console_device->sc_dv); 1920 } 1921 #endif /* NWSKBD > 0 */ 1922 1923 /* 1924 * Console interface. 1925 */ 1926 void 1927 wsdisplay_cnputc(dev, i) 1928 dev_t dev; 1929 int i; 1930 { 1931 struct wsscreen_internal *dc; 1932 char c = i; 1933 1934 if (!wsdisplay_console_initted) 1935 return; 1936 1937 if (wsdisplay_console_device != NULL && 1938 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS)) 1939 return; 1940 1941 dc = &wsdisplay_console_conf; 1942 /*wsdisplay_burn(wsdisplay_console_device, WSDISPLAY_BURN_OUTPUT);*/ 1943 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1); 1944 } 1945 1946 int 1947 wsdisplay_getc_dummy(dev) 1948 dev_t dev; 1949 { 1950 /* panic? */ 1951 return (0); 1952 } 1953 1954 void 1955 wsdisplay_pollc(dev, on) 1956 dev_t dev; 1957 int on; 1958 { 1959 struct wsdisplay_softc *sc = NULL; 1960 int unit = WSDISPLAYUNIT(dev); 1961 1962 if (unit < wsdisplay_cd.cd_ndevs) 1963 sc = wsdisplay_cd.cd_devs[unit]; 1964 1965 wsdisplay_cons_pollmode = on; 1966 1967 /* notify to fb drivers */ 1968 if (sc != NULL && sc->sc_accessops->pollc != NULL) 1969 (*sc->sc_accessops->pollc)(sc->sc_accesscookie, on); 1970 1971 /* notify to kbd drivers */ 1972 if (wsdisplay_cons_kbd_pollc) 1973 (*wsdisplay_cons_kbd_pollc)(dev, on); 1974 } 1975 1976 void 1977 wsdisplay_set_cons_kbd(get, poll, bell) 1978 int (*get) __P((dev_t)); 1979 void (*poll) __P((dev_t, int)); 1980 void (*bell) __P((dev_t, u_int, u_int, u_int)); 1981 { 1982 wsdisplay_cons.cn_getc = get; 1983 wsdisplay_cons.cn_bell = bell; 1984 wsdisplay_cons_kbd_pollc = poll; 1985 } 1986 1987 void 1988 wsdisplay_unset_cons_kbd() 1989 { 1990 wsdisplay_cons.cn_getc = wsdisplay_getc_dummy; 1991 wsdisplay_cons.cn_bell = NULL; 1992 wsdisplay_cons_kbd_pollc = 0; 1993 } 1994 1995 /* 1996 * Switch the console display to it's first screen. 1997 */ 1998 void 1999 wsdisplay_switchtoconsole() 2000 { 2001 struct wsdisplay_softc *sc; 2002 struct wsscreen *scr; 2003 2004 if (wsdisplay_console_device != NULL) { 2005 sc = wsdisplay_console_device; 2006 scr = sc->sc_scr[0]; 2007 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie, 2008 scr->scr_dconf->emulcookie, 0, NULL, NULL); 2009 } 2010 } 2011 2012 void 2013 wsscrollback(arg, op) 2014 void *arg; 2015 int op; 2016 { 2017 struct wsdisplay_softc *sc = arg; 2018 int lines; 2019 2020 if (op == WSDISPLAY_SCROLL_RESET) 2021 lines = 0; 2022 else { 2023 lines = sc->sc_focus->scr_dconf->scrdata->nrows - 1; 2024 if (op == WSDISPLAY_SCROLL_BACKWARD) 2025 lines = -lines; 2026 } 2027 2028 if (sc->sc_accessops->scrollback) { 2029 (*sc->sc_accessops->scrollback)(sc->sc_accesscookie, 2030 sc->sc_focus->scr_dconf->emulcookie, lines); 2031 } 2032 } 2033 2034 void 2035 wsdisplay_burn(v, flags) 2036 void *v; 2037 u_int flags; 2038 { 2039 struct wsdisplay_softc *sc = v; 2040 2041 if ((flags & sc->sc_burnflags & (WSDISPLAY_BURN_OUTPUT | 2042 WSDISPLAY_BURN_KBD | WSDISPLAY_BURN_MOUSE)) && 2043 sc->sc_accessops->burn_screen) { 2044 if (sc->sc_burnout) 2045 timeout_add(&sc->sc_burner, sc->sc_burnout); 2046 if (sc->sc_burnman) 2047 sc->sc_burnout = 0; 2048 } 2049 } 2050 2051 void 2052 wsdisplay_burner(v) 2053 void *v; 2054 { 2055 struct wsdisplay_softc *sc = v; 2056 int s; 2057 2058 if (sc->sc_accessops->burn_screen) { 2059 (*sc->sc_accessops->burn_screen)(sc->sc_accesscookie, 2060 sc->sc_burnman, sc->sc_burnflags); 2061 s = spltty(); 2062 if (sc->sc_burnman) { 2063 sc->sc_burnout = sc->sc_burnoutintvl; 2064 timeout_add(&sc->sc_burner, sc->sc_burnout); 2065 } else 2066 sc->sc_burnout = sc->sc_burninintvl; 2067 sc->sc_burnman = !sc->sc_burnman; 2068 splx(s); 2069 } 2070 } 2071 2072 /* 2073 * Switch the console at shutdown. 2074 */ 2075 void 2076 wsdisplay_shutdownhook(arg) 2077 void *arg; 2078 { 2079 wsdisplay_switchtoconsole(); 2080 } 2081 2082 /* 2083 * mouse console support functions 2084 */ 2085 2086 /* pointer to the current screen wsdisplay_softc structure */ 2087 static struct wsdisplay_softc *sc = NULL; 2088 2089 /* 2090 * Main function, called from wsdisplay_cfg_ioctl. 2091 */ 2092 int 2093 wsmoused(struct wsdisplay_softc *ws_sc, u_long cmd, caddr_t data, 2094 int flag, struct proc *p) 2095 { 2096 int error = -1; 2097 struct wscons_event mouse_event = *(struct wscons_event *)data; 2098 2099 if (cmd == WSDISPLAYIO_WSMOUSED) { 2100 if (IS_MOTION_EVENT(mouse_event.type)) { 2101 motion_event(mouse_event.type, mouse_event.value); 2102 return (0); 2103 } 2104 if (IS_BUTTON_EVENT(mouse_event.type)) { 2105 /* XXX tv_sec contains the number of clicks */ 2106 if (mouse_event.type == WSCONS_EVENT_MOUSE_DOWN) { 2107 button_event(mouse_event.value, 2108 mouse_event.time.tv_sec); 2109 } else 2110 button_event(mouse_event.value, 0); 2111 return (0); 2112 } 2113 if (IS_CTRL_EVENT(mouse_event.type)) { 2114 return (ctrl_event(mouse_event.type, mouse_event.value, 2115 ws_sc, p)); 2116 } 2117 } 2118 return (error); 2119 } 2120 2121 /* 2122 * Mouse motion events 2123 */ 2124 void 2125 motion_event(u_int type, int value) 2126 { 2127 switch (type) { 2128 case WSCONS_EVENT_MOUSE_DELTA_X: 2129 mouse_moverel(value, 0); 2130 break; 2131 case WSCONS_EVENT_MOUSE_DELTA_Y: 2132 mouse_moverel(0, 0 - value); 2133 break; 2134 case WSCONS_EVENT_MOUSE_DELTA_Z: 2135 mouse_zaxis(value); 2136 break; 2137 default: 2138 break; 2139 } 2140 } 2141 2142 /* 2143 * Button clicks events 2144 */ 2145 void 2146 button_event(int button, int clicks) 2147 { 2148 switch (button) { 2149 case MOUSE_COPY_BUTTON: 2150 switch (clicks % 4) { 2151 case 0: /* button is up */ 2152 mouse_copy_end(); 2153 mouse_copy_selection(); 2154 break; 2155 case 1: /* single click */ 2156 mouse_copy_start(); 2157 mouse_copy_selection(); 2158 break; 2159 case 2: /* double click */ 2160 mouse_copy_word(); 2161 mouse_copy_selection(); 2162 break; 2163 case 3: /* triple click */ 2164 mouse_copy_line(); 2165 mouse_copy_selection(); 2166 break; 2167 default: 2168 break; 2169 } 2170 break; 2171 2172 case MOUSE_PASTE_BUTTON: 2173 switch (clicks) { 2174 case 0: /* button is up */ 2175 break; 2176 default: /* paste */ 2177 mouse_paste(); 2178 break; 2179 } 2180 break; 2181 2182 case MOUSE_EXTEND_BUTTON: 2183 switch (clicks) { 2184 case 0: /* button is up */ 2185 break; 2186 default: /* extend the selection */ 2187 mouse_copy_extend_after(); 2188 break; 2189 } 2190 break; 2191 2192 default: 2193 break; 2194 } 2195 } 2196 2197 /* 2198 * Control events 2199 */ 2200 int 2201 ctrl_event(u_int type, int value, struct wsdisplay_softc *ws_sc, struct proc *p) 2202 { 2203 int i; 2204 2205 if (type == WSCONS_EVENT_WSMOUSED_ON) { 2206 if (!ws_sc->sc_accessops->getchar) 2207 /* no wsmoused support in the display driver */ 2208 return (1); 2209 /* initialization of globals */ 2210 sc = ws_sc; 2211 allocate_copybuffer(sc); 2212 Paste_avail = 0; 2213 } 2214 if (type == WSCONS_EVENT_WSMOUSED_OFF) { 2215 Paste_avail = 0; 2216 return (0); 2217 } 2218 for (i = 0 ; i < WSDISPLAY_DEFAULTSCREENS ; i++) { 2219 sc->sc_scr[i]->mouse = 2220 ((WS_NCOLS(sc->sc_scr[i]) * 2221 WS_NROWS(sc->sc_scr[i])) / 2); 2222 sc->sc_scr[i]->cursor = sc->sc_scr[i]->mouse; 2223 sc->sc_scr[i]->cpy_start = 0; 2224 sc->sc_scr[i]->cpy_end = 0; 2225 sc->sc_scr[i]->orig_start = 0; 2226 sc->sc_scr[i]->orig_end = 0; 2227 sc->sc_scr[i]->mouse_flags = 0; 2228 } 2229 return (0); 2230 } 2231 2232 void 2233 mouse_moverel(char dx, char dy) 2234 { 2235 unsigned short old_mouse = MOUSE; 2236 unsigned char mouse_col = (MOUSE % N_COLS); 2237 unsigned char mouse_row = (MOUSE / N_COLS); 2238 2239 /* wscons has support for screen saver via the WSDISPLAYIO_{G,S}VIDEO 2240 with WSDISPLAY_VIDEO_OFF and WSDISPLAY_VIDEO_ON values. 2241 However, none of the pc display driver (pcdisplay.c or vga.c) 2242 support this ioctl. Only the alpha display driver (tga.c) support it. 2243 2244 When screen saver support is available, /usr/sbin/screenblank can be 2245 used with the -m option, so that mice movements stop the screen 2246 saver. 2247 */ 2248 2249 /* update position */ 2250 2251 if (mouse_col + dx >= MAXCOL) 2252 mouse_col = MAXCOL; 2253 else { 2254 if (mouse_col + dx <= 0) 2255 mouse_col = 0; 2256 else 2257 mouse_col += dx; 2258 } 2259 if (mouse_row + dy >= MAXROW) 2260 mouse_row = MAXROW; 2261 else { 2262 if (mouse_row + dy <= 0) 2263 mouse_row = 0; 2264 else 2265 mouse_row += dy; 2266 } 2267 MOUSE = XY_TO_POS(mouse_col, mouse_row); 2268 /* if we have moved */ 2269 if (old_mouse != MOUSE) { 2270 if (IS_SEL_IN_PROGRESS(sc->sc_focus)) { 2271 /* selection in progress */ 2272 mouse_copy_extend(); 2273 } else { 2274 inverse_char(MOUSE); 2275 if (IS_MOUSE_VISIBLE(sc->sc_focus)) 2276 inverse_char(old_mouse); 2277 else 2278 MOUSE_FLAGS |= MOUSE_VISIBLE; 2279 } 2280 } 2281 } 2282 2283 void 2284 inverse_char(unsigned short pos) 2285 { 2286 u_int16_t uc; 2287 u_int16_t attr; 2288 2289 uc = GET_FULLCHAR(pos); 2290 attr = uc; 2291 2292 if ((attr >> 8) == 0) 2293 attr = (FG_LIGHTGREY << 8); 2294 2295 attr = (((attr >> 8) & 0x88) | ((((attr >> 8) >> 4) | 2296 ((attr >> 8) << 4)) & 0x77)) ; 2297 PUTCHAR(pos, (u_int) (uc & 0x00FF), (long) attr); 2298 } 2299 2300 void 2301 inverse_region(unsigned short start, unsigned short end) 2302 { 2303 unsigned short current_pos; 2304 unsigned short abs_end; 2305 2306 /* sanity check, useful because 'end' can be (0 - 1) = 65535 */ 2307 abs_end = N_COLS * N_ROWS; 2308 if (end > abs_end) 2309 return; 2310 current_pos = start; 2311 while (current_pos <= end) 2312 inverse_char(current_pos++); 2313 } 2314 2315 /* 2316 * Return the number of contiguous blank characters between the right margin 2317 * if border == 1 or between the next non-blank character and the current mouse 2318 * cursor if border == 0 2319 */ 2320 unsigned char 2321 skip_spc_right(char border) 2322 { 2323 unsigned short current = CPY_END; 2324 unsigned short mouse_col = (CPY_END % N_COLS); 2325 unsigned short limit = current + (N_COLS - mouse_col - 1); 2326 unsigned char res = 0; 2327 2328 while ((GETCHAR(current) == ' ') && (current <= limit)) { 2329 current++; 2330 res++; 2331 } 2332 if (border == BORDER) { 2333 if (current > limit) 2334 return (res - 1); 2335 else 2336 return (0); 2337 } else { 2338 if (res) 2339 return (res - 1); 2340 else 2341 return (res); 2342 } 2343 } 2344 2345 /* 2346 * Return the number of contiguous blank characters between the first of the 2347 * contiguous blank characters and the current mouse cursor 2348 */ 2349 unsigned char 2350 skip_spc_left(void) 2351 { 2352 short current = CPY_START; 2353 unsigned short mouse_col = (MOUSE % N_COLS); 2354 unsigned short limit = current - mouse_col; 2355 unsigned char res = 0; 2356 2357 while ((GETCHAR(current) == ' ') && (current >= limit)) { 2358 current--; 2359 res++; 2360 } 2361 if (res) 2362 res--; 2363 return (res); 2364 } 2365 2366 /* 2367 * Class of characters 2368 * Stolen from xterm sources of the Xfree project (see cvs tag below) 2369 * $TOG: button.c /main/76 1997/07/30 16:56:19 kaleb $ 2370 */ 2371 static int charClass[256] = { 2372 /* NUL SOH STX ETX EOT ENQ ACK BEL */ 2373 32, 1, 1, 1, 1, 1, 1, 1, 2374 /* BS HT NL VT NP CR SO SI */ 2375 1, 32, 1, 1, 1, 1, 1, 1, 2376 /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2377 1, 1, 1, 1, 1, 1, 1, 1, 2378 /* CAN EM SUB ESC FS GS RS US */ 2379 1, 1, 1, 1, 1, 1, 1, 1, 2380 /* SP ! " # $ % & ' */ 2381 32, 33, 34, 35, 36, 37, 38, 39, 2382 /* ( ) * + , - . / */ 2383 40, 41, 42, 43, 44, 45, 46, 47, 2384 /* 0 1 2 3 4 5 6 7 */ 2385 48, 48, 48, 48, 48, 48, 48, 48, 2386 /* 8 9 : ; < = > ? */ 2387 48, 48, 58, 59, 60, 61, 62, 63, 2388 /* @ A B C D E F G */ 2389 64, 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 [ \ ] ^ _ */ 2395 48, 48, 48, 91, 92, 93, 94, 48, 2396 /* ` a b c d e f g */ 2397 96, 48, 48, 48, 48, 48, 48, 48, 2398 /* h i j k l m n o */ 2399 48, 48, 48, 48, 48, 48, 48, 48, 2400 /* p q r s t u v w */ 2401 48, 48, 48, 48, 48, 48, 48, 48, 2402 /* x y z { | } ~ DEL */ 2403 48, 48, 48, 123, 124, 125, 126, 1, 2404 /* x80 x81 x82 x83 IND NEL SSA ESA */ 2405 1, 1, 1, 1, 1, 1, 1, 1, 2406 /* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2407 1, 1, 1, 1, 1, 1, 1, 1, 2408 /* DCS PU1 PU2 STS CCH MW SPA EPA */ 2409 1, 1, 1, 1, 1, 1, 1, 1, 2410 /* x98 x99 x9A CSI ST OSC PM APC */ 2411 1, 1, 1, 1, 1, 1, 1, 1, 2412 /* - i c/ L ox Y- | So */ 2413 160, 161, 162, 163, 164, 165, 166, 167, 2414 /* .. c0 ip << _ R0 - */ 2415 168, 169, 170, 171, 172, 173, 174, 175, 2416 /* o +- 2 3 ' u q| . */ 2417 176, 177, 178, 179, 180, 181, 182, 183, 2418 /* , 1 2 >> 1/4 1/2 3/4 ? */ 2419 184, 185, 186, 187, 188, 189, 190, 191, 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: X */ 2425 48, 48, 48, 48, 48, 48, 48, 216, 2426 /* O/ U` U' U^ U: Y' P B */ 2427 48, 48, 48, 48, 48, 48, 48, 48, 2428 /* a` a' a^ a~ a: ao ae c, */ 2429 48, 48, 48, 48, 48, 48, 48, 48, 2430 /* e` e' e^ e: i` i' i^ i: */ 2431 48, 48, 48, 48, 48, 48, 48, 48, 2432 /* d n~ o` o' o^ o~ o: -: */ 2433 48, 48, 48, 48, 48, 48, 48, 248, 2434 /* o/ u` u' u^ u: y' P y: */ 2435 48, 48, 48, 48, 48, 48, 48, 48}; 2436 2437 /* 2438 * Find the first blank beginning after the current cursor position 2439 */ 2440 unsigned char 2441 skip_char_right(unsigned short offset) 2442 { 2443 unsigned short current = offset; 2444 unsigned short limit = current + (N_COLS - (MOUSE % N_COLS) - 1); 2445 unsigned char class = charClass[GETCHAR(current)]; 2446 unsigned char res = 0; 2447 2448 while ((charClass[GETCHAR(current)] == class) 2449 && (current <= limit)) { 2450 current++; 2451 res++; 2452 } 2453 if (res) 2454 res--; 2455 return (res); 2456 } 2457 2458 /* 2459 * Find the first non-blank character before the cursor position 2460 */ 2461 unsigned char 2462 skip_char_left(unsigned short offset) 2463 { 2464 short current = offset; 2465 unsigned short limit = current - (MOUSE % N_COLS); 2466 unsigned char class = charClass[GETCHAR(current)]; 2467 unsigned char res = 0; 2468 2469 while ((charClass[GETCHAR(current)] == class) && (current >= limit)) { 2470 current--; 2471 res++; 2472 } 2473 if (res) 2474 res--; 2475 return (res); 2476 } 2477 2478 /* 2479 * Compare character classes 2480 */ 2481 unsigned char 2482 class_cmp(unsigned short first, unsigned short second) 2483 { 2484 unsigned char first_class; 2485 unsigned char second_class; 2486 2487 first_class = charClass[GETCHAR(first)]; 2488 second_class = charClass[GETCHAR(second)]; 2489 2490 if (first_class != second_class) 2491 return (1); 2492 else 2493 return (0); 2494 } 2495 2496 /* 2497 * Beginning of a copy operation 2498 */ 2499 void 2500 mouse_copy_start(void) 2501 { 2502 unsigned char right; 2503 /* if no selection, then that's the first one */ 2504 2505 if (!Paste_avail) 2506 Paste_avail = 1; 2507 2508 /* remove the previous selection */ 2509 2510 if (IS_SEL_EXISTS(sc->sc_focus)) 2511 remove_selection(sc); 2512 2513 /* initial show of the cursor */ 2514 if (!IS_MOUSE_VISIBLE(sc->sc_focus)) 2515 inverse_char(MOUSE); 2516 2517 CPY_START = MOUSE; 2518 CPY_END = MOUSE; 2519 ORIG_START = CPY_START; 2520 ORIG_END = CPY_END; 2521 CURSOR = CPY_END + 1; /* init value */ 2522 2523 right = skip_spc_right(BORDER); /* useful later, in mouse_copy_extend */ 2524 if (right) 2525 MOUSE_FLAGS |= BLANK_TO_EOL; 2526 2527 MOUSE_FLAGS |= SEL_IN_PROGRESS; 2528 MOUSE_FLAGS |= SEL_EXISTS; 2529 MOUSE_FLAGS |= SEL_BY_CHAR; /* select by char */ 2530 MOUSE_FLAGS &= ~SEL_BY_WORD; 2531 MOUSE_FLAGS &= ~SEL_BY_LINE; 2532 MOUSE_FLAGS &= ~MOUSE_VISIBLE; /* cursor hidden in selection */ 2533 } 2534 2535 /* 2536 * Copy of the word under the cursor 2537 */ 2538 void 2539 mouse_copy_word() 2540 { 2541 unsigned char right; 2542 unsigned char left; 2543 2544 if (IS_SEL_EXISTS(sc->sc_focus)) 2545 remove_selection(sc); 2546 2547 if (IS_MOUSE_VISIBLE(sc->sc_focus)) 2548 inverse_char(MOUSE); 2549 2550 CPY_START = MOUSE; 2551 CPY_END = MOUSE; 2552 2553 if (IS_ALPHANUM(MOUSE)) { 2554 right = skip_char_right(CPY_END); 2555 left = skip_char_left(CPY_START); 2556 } else { 2557 right = skip_spc_right(NO_BORDER); 2558 left = skip_spc_left(); 2559 } 2560 2561 CPY_START -= left; 2562 CPY_END += right; 2563 ORIG_START = CPY_START; 2564 ORIG_END = CPY_END; 2565 CURSOR = CPY_END + 1; /* init value, never happen */ 2566 inverse_region(CPY_START, CPY_END); 2567 2568 MOUSE_FLAGS |= SEL_IN_PROGRESS; 2569 MOUSE_FLAGS |= SEL_EXISTS; 2570 MOUSE_FLAGS &= ~SEL_BY_CHAR; 2571 MOUSE_FLAGS |= SEL_BY_WORD; 2572 MOUSE_FLAGS &= ~SEL_BY_LINE; 2573 2574 /* mouse cursor hidden in the selection */ 2575 MOUSE_FLAGS &= ~BLANK_TO_EOL; 2576 MOUSE_FLAGS &= ~MOUSE_VISIBLE; 2577 } 2578 2579 /* 2580 * Copy of the current line 2581 */ 2582 void 2583 mouse_copy_line(void) 2584 { 2585 unsigned char row = MOUSE / N_COLS; 2586 2587 if (IS_SEL_EXISTS(sc->sc_focus)) 2588 remove_selection(sc); 2589 2590 if (IS_MOUSE_VISIBLE(sc->sc_focus)) 2591 inverse_char(MOUSE); 2592 2593 CPY_START = row * N_COLS; 2594 CPY_END = CPY_START + (N_COLS - 1); 2595 ORIG_START = CPY_START; 2596 ORIG_END = CPY_END; 2597 CURSOR = CPY_END + 1; 2598 inverse_region(CPY_START, CPY_END); 2599 2600 MOUSE_FLAGS |= SEL_IN_PROGRESS; 2601 MOUSE_FLAGS |= SEL_EXISTS; 2602 MOUSE_FLAGS &= ~SEL_BY_CHAR; 2603 MOUSE_FLAGS &= ~SEL_BY_WORD; 2604 MOUSE_FLAGS |= SEL_BY_LINE; 2605 2606 /* mouse cursor hidden in the selection */ 2607 MOUSE_FLAGS &= ~BLANK_TO_EOL; 2608 MOUSE_FLAGS &= ~MOUSE_VISIBLE; 2609 } 2610 2611 /* 2612 * End of a copy operation 2613 */ 2614 void 2615 mouse_copy_end(void) 2616 { 2617 MOUSE_FLAGS &= ~(SEL_IN_PROGRESS); 2618 if (IS_SEL_BY_WORD(sc->sc_focus) || IS_SEL_BY_LINE(sc->sc_focus)) { 2619 if (CURSOR != (CPY_END + 1)) 2620 inverse_char(CURSOR); 2621 CURSOR = CPY_END + 1; 2622 } 2623 } 2624 2625 2626 /* 2627 * Generic selection extend function 2628 */ 2629 void 2630 mouse_copy_extend(void) 2631 { 2632 if (IS_SEL_BY_CHAR(sc->sc_focus)) 2633 mouse_copy_extend_char(); 2634 if (IS_SEL_BY_WORD(sc->sc_focus)) 2635 mouse_copy_extend_word(); 2636 if (IS_SEL_BY_LINE(sc->sc_focus)) 2637 mouse_copy_extend_line(); 2638 } 2639 2640 /* 2641 * Extend a selected region, character by character 2642 */ 2643 void 2644 mouse_copy_extend_char() 2645 { 2646 unsigned char right; 2647 2648 if (!IS_SEL_EXT_AFTER(sc->sc_focus)) { 2649 2650 if (IS_BLANK_TO_EOL(sc->sc_focus)) { 2651 /* 2652 * First extension of selection. We handle special 2653 * cases of blank characters to eol 2654 */ 2655 2656 right = skip_spc_right(BORDER); 2657 if (MOUSE > ORIG_START) { 2658 /* the selection goes to the lower part of 2659 the screen */ 2660 2661 /* remove the previous cursor, start of 2662 selection is now next line */ 2663 inverse_char(CPY_START); 2664 CPY_START += (right + 1); 2665 CPY_END = CPY_START; 2666 ORIG_START = CPY_START; 2667 /* simulate the initial mark */ 2668 inverse_char(CPY_START); 2669 } else { 2670 /* the selection goes to the upper part 2671 of the screen */ 2672 /* remove the previous cursor, start of 2673 selection is now at the eol */ 2674 inverse_char(CPY_START); 2675 ORIG_START += (right + 1); 2676 CPY_START = ORIG_START - 1; 2677 CPY_END = ORIG_START - 1; 2678 /* simulate the initial mark */ 2679 inverse_char(CPY_START); 2680 } 2681 MOUSE_FLAGS &= ~ BLANK_TO_EOL; 2682 } 2683 2684 if (MOUSE < ORIG_START && CPY_END >= ORIG_START) { 2685 /* we go to the upper part of the screen */ 2686 2687 /* reverse the old selection region */ 2688 remove_selection(sc); 2689 CPY_END = ORIG_START - 1; 2690 CPY_START = ORIG_START; 2691 } 2692 if (CPY_START < ORIG_START && MOUSE >= ORIG_START) { 2693 /* we go to the lower part of the screen */ 2694 2695 /* reverse the old selection region */ 2696 2697 remove_selection(sc); 2698 CPY_START = ORIG_START; 2699 CPY_END = ORIG_START - 1; 2700 } 2701 /* restore flags cleared in remove_selection() */ 2702 MOUSE_FLAGS |= SEL_IN_PROGRESS; 2703 MOUSE_FLAGS |= SEL_EXISTS; 2704 } 2705 /* beginning of common part */ 2706 2707 if (MOUSE >= ORIG_START) { 2708 2709 /* lower part of the screen */ 2710 if (MOUSE > CPY_END) { 2711 /* extending selection */ 2712 inverse_region(CPY_END + 1, MOUSE); 2713 } else { 2714 /* reducing selection */ 2715 inverse_region(MOUSE + 1, CPY_END); 2716 } 2717 CPY_END = MOUSE; 2718 } else { 2719 /* upper part of the screen */ 2720 if (MOUSE < CPY_START) { 2721 /* extending selection */ 2722 inverse_region(MOUSE,CPY_START - 1); 2723 } else { 2724 /* reducing selection */ 2725 inverse_region(CPY_START,MOUSE - 1); 2726 } 2727 CPY_START = MOUSE; 2728 } 2729 /* end of common part */ 2730 } 2731 2732 /* 2733 * Extend a selected region, word by word 2734 */ 2735 void 2736 mouse_copy_extend_word(void) 2737 { 2738 unsigned short old_cpy_end; 2739 unsigned short old_cpy_start; 2740 2741 if (!IS_SEL_EXT_AFTER(sc->sc_focus)) { 2742 2743 /* remove cursor in selection (black one) */ 2744 2745 if (CURSOR != (CPY_END + 1)) 2746 inverse_char(CURSOR); 2747 2748 /* now, switch between lower and upper part of the screen */ 2749 2750 if (MOUSE < ORIG_START && CPY_END >= ORIG_START) { 2751 /* going to the upper part of the screen */ 2752 inverse_region(ORIG_END + 1, CPY_END); 2753 CPY_END = ORIG_END; 2754 } 2755 2756 if (MOUSE > ORIG_END && CPY_START <= ORIG_START) { 2757 /* going to the lower part of the screen */ 2758 inverse_region(CPY_START, ORIG_START - 1); 2759 CPY_START = ORIG_START; 2760 } 2761 } 2762 2763 if (MOUSE >= ORIG_START) { 2764 /* lower part of the screen */ 2765 2766 if (MOUSE > CPY_END) { 2767 /* extending selection */ 2768 2769 old_cpy_end = CPY_END; 2770 CPY_END = MOUSE + skip_char_right(MOUSE); 2771 inverse_region(old_cpy_end + 1, CPY_END); 2772 } else { 2773 if (class_cmp(MOUSE, MOUSE + 1)) { 2774 /* reducing selection (remove last word) */ 2775 old_cpy_end = CPY_END; 2776 CPY_END = MOUSE; 2777 inverse_region(CPY_END + 1, old_cpy_end); 2778 } else { 2779 old_cpy_end = CPY_END; 2780 CPY_END = MOUSE + skip_char_right(MOUSE); 2781 if (CPY_END != old_cpy_end) { 2782 /* reducing selection, from the end of 2783 * next word */ 2784 inverse_region(CPY_END + 1, 2785 old_cpy_end); 2786 } 2787 } 2788 } 2789 } else { 2790 /* upper part of the screen */ 2791 if (MOUSE < CPY_START) { 2792 /* extending selection */ 2793 old_cpy_start = CPY_START; 2794 CPY_START = MOUSE - skip_char_left(MOUSE); 2795 inverse_region(CPY_START, old_cpy_start - 1); 2796 } else { 2797 if (class_cmp(MOUSE - 1, MOUSE)) { 2798 /* reducing selection (remove last word) */ 2799 old_cpy_start = CPY_START; 2800 CPY_START = MOUSE; 2801 inverse_region(old_cpy_start, 2802 CPY_START - 1); 2803 } else { 2804 old_cpy_start = CPY_START; 2805 CPY_START = MOUSE - skip_char_left(MOUSE); 2806 if (CPY_START != old_cpy_start) { 2807 inverse_region(old_cpy_start, 2808 CPY_START - 1); 2809 } 2810 } 2811 } 2812 } 2813 2814 if (!IS_SEL_EXT_AFTER(sc->sc_focus)) { 2815 /* display new cursor */ 2816 CURSOR = MOUSE; 2817 inverse_char(CURSOR); 2818 } 2819 } 2820 2821 /* 2822 * Extend a selected region, line by line 2823 */ 2824 void 2825 mouse_copy_extend_line(void) 2826 { 2827 unsigned short old_row; 2828 unsigned short new_row; 2829 unsigned short old_cpy_start; 2830 unsigned short old_cpy_end; 2831 2832 if (!IS_SEL_EXT_AFTER(sc->sc_focus)) { 2833 /* remove cursor in selection (black one) */ 2834 2835 if (CURSOR != (CPY_END + 1)) 2836 inverse_char(CURSOR); 2837 2838 /* now, switch between lower and upper part of the screen */ 2839 2840 if (MOUSE < ORIG_START && CPY_END >= ORIG_START) { 2841 /* going to the upper part of the screen */ 2842 inverse_region(ORIG_END + 1, CPY_END); 2843 CPY_END = ORIG_END; 2844 } 2845 2846 if (MOUSE > ORIG_END && CPY_START <= ORIG_START) { 2847 /* going to the lower part of the screen */ 2848 inverse_region(CPY_START, ORIG_START - 1); 2849 CPY_START = ORIG_START; 2850 } 2851 } 2852 2853 if (MOUSE >= ORIG_START) { 2854 /* lower part of the screen */ 2855 if (CURSOR == (CPY_END + 1)) 2856 CURSOR = CPY_END; 2857 old_row = CURSOR / N_COLS; 2858 new_row = MOUSE / N_COLS; 2859 old_cpy_end = CPY_END; 2860 CPY_END = (new_row * N_COLS) + MAXCOL; 2861 if (new_row > old_row) 2862 inverse_region(old_cpy_end + 1, CPY_END); 2863 else if (new_row < old_row) 2864 inverse_region(CPY_END + 1, old_cpy_end); 2865 } else { 2866 /* upper part of the screen */ 2867 old_row = CURSOR / N_COLS; 2868 new_row = MOUSE / N_COLS; 2869 old_cpy_start = CPY_START; 2870 CPY_START = new_row * N_COLS; 2871 if (new_row < old_row) 2872 inverse_region(CPY_START, old_cpy_start - 1); 2873 else if (new_row > old_row) 2874 inverse_region(old_cpy_start, CPY_START - 1); 2875 } 2876 2877 if (!IS_SEL_EXT_AFTER(sc->sc_focus)) { 2878 /* display new cursor */ 2879 CURSOR = MOUSE; 2880 inverse_char(CURSOR); 2881 } 2882 } 2883 2884 void 2885 mouse_hide(struct wsdisplay_softc *sc) 2886 { 2887 if (IS_MOUSE_VISIBLE(sc->sc_focus)) { 2888 inverse_char(MOUSE); 2889 MOUSE_FLAGS &= ~MOUSE_VISIBLE; 2890 } 2891 } 2892 2893 /* 2894 * Add an extension to a selected region, word by word 2895 */ 2896 void 2897 mouse_copy_extend_after(void) 2898 { 2899 unsigned short start_dist; 2900 unsigned short end_dist; 2901 2902 if (IS_SEL_EXISTS(sc->sc_focus)) { 2903 MOUSE_FLAGS |= SEL_EXT_AFTER; 2904 mouse_hide(sc); /* hide current cursor */ 2905 2906 if (CPY_START > MOUSE) 2907 start_dist = CPY_START - MOUSE; 2908 else 2909 start_dist = MOUSE - CPY_START; 2910 if (MOUSE > CPY_END) 2911 end_dist = MOUSE - CPY_END; 2912 else 2913 end_dist = CPY_END - MOUSE; 2914 if (start_dist < end_dist) { 2915 /* upper part of the screen*/ 2916 ORIG_START = MOUSE + 1; 2917 /* only used in mouse_copy_extend_line() */ 2918 CURSOR = CPY_START; 2919 } else { 2920 /* lower part of the screen */ 2921 ORIG_START = MOUSE; 2922 /* only used in mouse_copy_extend_line() */ 2923 CURSOR = CPY_END; 2924 } 2925 if (IS_SEL_BY_CHAR(sc->sc_focus)) 2926 mouse_copy_extend_char(); 2927 if (IS_SEL_BY_WORD(sc->sc_focus)) 2928 mouse_copy_extend_word(); 2929 if (IS_SEL_BY_LINE(sc->sc_focus)) 2930 mouse_copy_extend_line(); 2931 mouse_copy_selection(); 2932 } 2933 } 2934 2935 /* 2936 * Remove a previously selected region 2937 */ 2938 void 2939 remove_selection(struct wsdisplay_softc *sc) 2940 { 2941 if (IS_SEL_EXT_AFTER(sc->sc_focus)) { 2942 /* reset the flag indicating an extension of selection */ 2943 MOUSE_FLAGS &= ~SEL_EXT_AFTER; 2944 } 2945 inverse_region(CPY_START, CPY_END); 2946 MOUSE_FLAGS &= ~SEL_IN_PROGRESS; 2947 MOUSE_FLAGS &= ~SEL_EXISTS; 2948 } 2949 2950 /* 2951 * Put the current visual selection in the selection buffer 2952 */ 2953 void 2954 mouse_copy_selection(void) 2955 { 2956 unsigned short current = 0; 2957 unsigned short blank = current; 2958 unsigned short buf_end = ((N_COLS + 1) * N_ROWS); 2959 unsigned short sel_cur; 2960 unsigned short sel_end; 2961 2962 sel_cur = CPY_START; 2963 sel_end = CPY_END; 2964 2965 while (sel_cur <= sel_end && current < buf_end - 1) { 2966 Copybuffer[current] = (GETCHAR(sel_cur)); 2967 if (!IS_SPACE(Copybuffer[current])) 2968 blank = current + 1; /* first blank after non-blank */ 2969 current++; 2970 if (POS_TO_X(sel_cur) == MAXCOL) { 2971 /* we are on the last col of the screen */ 2972 Copybuffer[blank] = '\r'; /* carriage return */ 2973 current = blank + 1; /* restart just after the carriage 2974 return in the buffer */ 2975 blank = current; 2976 } 2977 sel_cur++; 2978 } 2979 2980 Copybuffer[current] = '\0'; 2981 } 2982 2983 /* 2984 * Paste the current selection 2985 */ 2986 void 2987 mouse_paste(void) 2988 { 2989 unsigned short len; 2990 unsigned char *current = Copybuffer; 2991 2992 if (Paste_avail) { 2993 for (len = strlen(Copybuffer) ; len > 0; len--) { 2994 (*linesw[sc->sc_focus->scr_tty->t_line].l_rint) 2995 (*current++, sc->sc_focus->scr_tty); 2996 } 2997 } 2998 } 2999 3000 /* 3001 * Handle the z axis. 3002 * The z axis (roller or wheel) is mapped by default to scrollback. 3003 */ 3004 void 3005 mouse_zaxis(int z) 3006 { 3007 if (z < 0) 3008 wsscrollback(sc, WSDISPLAY_SCROLL_BACKWARD); 3009 else 3010 wsscrollback(sc, WSDISPLAY_SCROLL_FORWARD); 3011 } 3012 3013 /* 3014 * Allocate the copy buffer. The size is: 3015 * (cols + 1) * (rows) 3016 * (+1 for '\n' at the end of lines), 3017 * where cols and rows are the maximum of column and rows of all screens. 3018 */ 3019 void 3020 allocate_copybuffer(struct wsdisplay_softc *sc) 3021 { 3022 int nscreens = sc->sc_scrdata->nscreens; 3023 int i,s; 3024 const struct wsscreen_descr **screens_list = sc->sc_scrdata->screens; 3025 const struct wsscreen_descr *current; 3026 unsigned short size = Copybuffer_size; 3027 3028 s = spltty(); 3029 for (i = 0; i < nscreens; i++) { 3030 current = *screens_list; 3031 if (( (current->ncols + 1) * current->nrows) > size) 3032 size = ((current->ncols + 1) * current->nrows); 3033 screens_list++; 3034 } 3035 if ((size != Copybuffer_size) && (Copybuffer_size != 0)) { 3036 bzero(Copybuffer, Copybuffer_size); 3037 free(Copybuffer, M_DEVBUF); 3038 } 3039 if ((Copybuffer = (char *)malloc(size, M_DEVBUF, M_NOWAIT)) == NULL) { 3040 printf("wscons: copybuffer memory malloc failed\n"); 3041 Copybuffer_size = 0; 3042 } 3043 Copybuffer_size = size; 3044 splx(s); 3045 } 3046