root/dev/wscons/wsdisplay.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wsscreen_attach
  2. wsscreen_detach
  3. wsdisplay_screentype_pick
  4. wsdisplay_addscreen_print
  5. wsdisplay_addscreen
  6. wsdisplay_getscreen
  7. wsdisplay_closescreen
  8. wsdisplay_delscreen
  9. wsdisplay_emul_match
  10. wsdisplay_emul_attach
  11. wsdisplay_emul_detach
  12. wsdisplay_common_detach
  13. wsemuldisplaydevprint
  14. wsdisplay_common_attach
  15. wsdisplay_cnattach
  16. wsdisplayopen
  17. wsdisplayclose
  18. wsdisplayread
  19. wsdisplaywrite
  20. wsdisplaytty
  21. wsdisplayioctl
  22. wsdisplay_param
  23. wsdisplay_internal_ioctl
  24. wsdisplay_cfg_ioctl
  25. wsdisplaymmap
  26. wsdisplaypoll
  27. wsdisplaykqfilter
  28. wsdisplaystart
  29. wsdisplaystop
  30. wsdisplayparam
  31. wsdisplay_emulbell
  32. wsdisplay_emulinput
  33. wsdisplay_kbdinput
  34. wsdisplay_update_rawkbd
  35. wsdisplay_switch3
  36. wsdisplay_switch2
  37. wsdisplay_switch1
  38. wsdisplay_switch
  39. wsdisplay_reset
  40. wsscreen_attach_sync
  41. wsscreen_detach_sync
  42. wsscreen_lookup_sync
  43. wsdisplay_maxscreenidx
  44. wsdisplay_screenstate
  45. wsdisplay_getactivescreen
  46. wsscreen_switchwait
  47. wsdisplay_kbdholdscreen
  48. wsdisplay_set_console_kbd
  49. wsdisplay_set_kbd
  50. wsdisplay_cnputc
  51. wsdisplay_getc_dummy
  52. wsdisplay_pollc
  53. wsdisplay_set_cons_kbd
  54. wsdisplay_unset_cons_kbd
  55. wsdisplay_switchtoconsole
  56. wsscrollback
  57. wsdisplay_burn
  58. wsdisplay_burner
  59. wsdisplay_shutdownhook
  60. wsmoused
  61. motion_event
  62. button_event
  63. ctrl_event
  64. mouse_moverel
  65. inverse_char
  66. inverse_region
  67. skip_spc_right
  68. skip_spc_left
  69. skip_char_right
  70. skip_char_left
  71. class_cmp
  72. mouse_copy_start
  73. mouse_copy_word
  74. mouse_copy_line
  75. mouse_copy_end
  76. mouse_copy_extend
  77. mouse_copy_extend_char
  78. mouse_copy_extend_word
  79. mouse_copy_extend_line
  80. mouse_hide
  81. mouse_copy_extend_after
  82. remove_selection
  83. mouse_copy_selection
  84. mouse_paste
  85. mouse_zaxis
  86. allocate_copybuffer
  87. mouse_remove
  88. wsmoused_release
  89. wsmoused_wakeup

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

/* [<][>][^][v][top][bottom][index][help] */