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