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