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