[BACK]Return to wsdisplay.c CVS log [TXT][DIR] Up to [local] / sys / dev / wscons

Annotation of sys/dev/wscons/wsdisplay.c, Revision 1.1.1.1

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

CVSweb