LCOV - code coverage report
Current view: top level - dev/wscons - wsdisplay.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1538 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 95 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13