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