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