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

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

1.1       nbrk        1: /* $OpenBSD: wskbd.c,v 1.56 2007/06/02 07:19:28 tedu Exp $ */
                      2: /* $NetBSD: wskbd.c,v 1.80 2005/05/04 01:52:16 augustss Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
                      6:  *
                      7:  * Keysym translator:
                      8:  * Contributed to The NetBSD Foundation by Juergen Hannken-Illjes.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *      This product includes software developed by Christopher G. Demetriou
                     21:  *     for the NetBSD Project.
                     22:  * 4. The name of the author may not be used to endorse or promote products
                     23:  *    derived from this software without specific prior written permission
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     27:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     28:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     29:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     30:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     31:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     32:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     33:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     34:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     35:  */
                     36:
                     37: /*
                     38:  * Copyright (c) 1992, 1993
                     39:  *     The Regents of the University of California.  All rights reserved.
                     40:  *
                     41:  * This software was developed by the Computer Systems Engineering group
                     42:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     43:  * contributed to Berkeley.
                     44:  *
                     45:  * All advertising materials mentioning features or use of this software
                     46:  * must display the following acknowledgement:
                     47:  *     This product includes software developed by the University of
                     48:  *     California, Lawrence Berkeley Laboratory.
                     49:  *
                     50:  * Redistribution and use in source and binary forms, with or without
                     51:  * modification, are permitted provided that the following conditions
                     52:  * are met:
                     53:  * 1. Redistributions of source code must retain the above copyright
                     54:  *    notice, this list of conditions and the following disclaimer.
                     55:  * 2. Redistributions in binary form must reproduce the above copyright
                     56:  *    notice, this list of conditions and the following disclaimer in the
                     57:  *    documentation and/or other materials provided with the distribution.
                     58:  * 3. Neither the name of the University nor the names of its contributors
                     59:  *    may be used to endorse or promote products derived from this software
                     60:  *    without specific prior written permission.
                     61:  *
                     62:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     63:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     64:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     65:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     66:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     67:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     68:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     69:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     70:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     71:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     72:  * SUCH DAMAGE.
                     73:  *
                     74:  *     @(#)kbd.c       8.2 (Berkeley) 10/30/93
                     75:  */
                     76:
                     77: /*
                     78:  * Keyboard driver (/dev/wskbd*).  Translates incoming bytes to ASCII or
                     79:  * to `wscons_events' and passes them up to the appropriate reader.
                     80:  */
                     81:
                     82: #include <sys/param.h>
                     83: #include <sys/conf.h>
                     84: #include <sys/device.h>
                     85: #include <sys/ioctl.h>
                     86: #include <sys/kernel.h>
                     87: #include <sys/proc.h>
                     88: #include <sys/syslog.h>
                     89: #include <sys/systm.h>
                     90: #include <sys/timeout.h>
                     91: #include <sys/malloc.h>
                     92: #include <sys/tty.h>
                     93: #include <sys/signalvar.h>
                     94: #include <sys/errno.h>
                     95: #include <sys/fcntl.h>
                     96: #include <sys/vnode.h>
                     97: #include <sys/poll.h>
                     98: #include <sys/workq.h>
                     99:
                    100: #include <ddb/db_var.h>
                    101:
                    102: #include <dev/wscons/wsconsio.h>
                    103: #include <dev/wscons/wskbdvar.h>
                    104: #include <dev/wscons/wsksymdef.h>
                    105: #include <dev/wscons/wsksymvar.h>
                    106: #include <dev/wscons/wsdisplayvar.h>
                    107: #include <dev/wscons/wseventvar.h>
                    108: #include <dev/wscons/wscons_callbacks.h>
                    109:
                    110: #include "audio.h"             /* NAUDIO (mixer tuning) */
                    111: #include "wsdisplay.h"
                    112: #include "wskbd.h"
                    113: #include "wsmux.h"
                    114:
                    115: #ifndef        SMALL_KERNEL
                    116: #define        BURNER_SUPPORT
                    117: #define        SCROLLBACK_SUPPORT
                    118: #endif
                    119:
                    120: #ifdef WSKBD_DEBUG
                    121: #define DPRINTF(x)     if (wskbddebug) printf x
                    122: int    wskbddebug = 0;
                    123: #else
                    124: #define DPRINTF(x)
                    125: #endif
                    126:
                    127: #include <dev/wscons/wsmuxvar.h>
                    128:
                    129: struct wskbd_internal {
                    130:        const struct wskbd_mapdata *t_keymap;
                    131:
                    132:        const struct wskbd_consops *t_consops;
                    133:        void    *t_consaccesscookie;
                    134:
                    135:        int     t_modifiers;
                    136:        int     t_composelen;           /* remaining entries in t_composebuf */
                    137:        keysym_t t_composebuf[2];
                    138:
                    139:        int     t_flags;
                    140: #define WSKFL_METAESC 1
                    141:
                    142: #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */
                    143:        keysym_t t_symbols[MAXKEYSYMSPERKEY];
                    144:
                    145:        struct wskbd_softc *t_sc;       /* back pointer */
                    146: };
                    147:
                    148: struct wskbd_softc {
                    149:        struct wsevsrc  sc_base;
                    150:
                    151:        struct wskbd_internal *id;
                    152:
                    153:        const struct wskbd_accessops *sc_accessops;
                    154:        void *sc_accesscookie;
                    155:
                    156:        int     sc_ledstate;
                    157:
                    158:        int     sc_isconsole;
                    159:
                    160:        struct wskbd_bell_data sc_bell_data;
                    161:        struct wskbd_keyrepeat_data sc_keyrepeat_data;
                    162:
                    163:        int     sc_repeating;           /* we've called timeout() */
                    164:        int     sc_repkey;
                    165:        struct timeout sc_repeat_ch;
                    166:        u_int   sc_repeat_type;
                    167:        int     sc_repeat_value;
                    168:
                    169:        int     sc_translating;         /* xlate to chars for emulation */
                    170:
                    171:        int     sc_maplen;              /* number of entries in sc_map */
                    172:        struct wscons_keymap *sc_map;   /* current translation map */
                    173:        kbd_t   sc_layout; /* current layout */
                    174:
                    175:        int     sc_refcnt;
                    176:        u_char  sc_dying;               /* device is being detached */
                    177: };
                    178:
                    179: #define MOD_SHIFT_L            (1 << 0)
                    180: #define MOD_SHIFT_R            (1 << 1)
                    181: #define MOD_SHIFTLOCK          (1 << 2)
                    182: #define MOD_CAPSLOCK           (1 << 3)
                    183: #define MOD_CONTROL_L          (1 << 4)
                    184: #define MOD_CONTROL_R          (1 << 5)
                    185: #define MOD_META_L             (1 << 6)
                    186: #define MOD_META_R             (1 << 7)
                    187: #define MOD_MODESHIFT          (1 << 8)
                    188: #define MOD_NUMLOCK            (1 << 9)
                    189: #define MOD_COMPOSE            (1 << 10)
                    190: #define MOD_HOLDSCREEN         (1 << 11)
                    191: #define MOD_COMMAND            (1 << 12)
                    192: #define MOD_COMMAND1           (1 << 13)
                    193: #define MOD_COMMAND2           (1 << 14)
                    194: #define MOD_MODELOCK           (1 << 15)
                    195:
                    196: #define MOD_ANYSHIFT           (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
                    197: #define MOD_ANYCONTROL         (MOD_CONTROL_L | MOD_CONTROL_R)
                    198: #define MOD_ANYMETA            (MOD_META_L | MOD_META_R)
                    199:
                    200: #define MOD_ONESET(id, mask)   (((id)->t_modifiers & (mask)) != 0)
                    201: #define MOD_ALLSET(id, mask)   (((id)->t_modifiers & (mask)) == (mask))
                    202:
                    203: keysym_t ksym_upcase(keysym_t);
                    204:
                    205: int    wskbd_match(struct device *, void *, void *);
                    206: void   wskbd_attach(struct device *, struct device *, void *);
                    207: int    wskbd_detach(struct device *, int);
                    208: int    wskbd_activate(struct device *, enum devact);
                    209:
                    210: int    wskbd_displayioctl(struct device *, u_long, caddr_t, int, struct proc *);
                    211:
                    212: void   update_leds(struct wskbd_internal *);
                    213: void   update_modifier(struct wskbd_internal *, u_int, int, int);
                    214: int    internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t);
                    215: int    wskbd_translate(struct wskbd_internal *, u_int, int);
                    216: int    wskbd_enable(struct wskbd_softc *, int);
                    217: #if NWSDISPLAY > 0
                    218: void   change_displayparam(struct wskbd_softc *, int, int, int);
                    219: void   wskbd_holdscreen(struct wskbd_softc *, int);
                    220: #endif
                    221:
                    222: int    wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, caddr_t, int,
                    223:            struct proc *);
                    224: void   wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value);
                    225:
                    226: #if NWSMUX > 0
                    227: int    wskbd_mux_open(struct wsevsrc *, struct wseventvar *);
                    228: int    wskbd_mux_close(struct wsevsrc *);
                    229: #else
                    230: #define        wskbd_mux_open NULL
                    231: #define        wskbd_mux_close NULL
                    232: #endif
                    233:
                    234: int    wskbd_do_open(struct wskbd_softc *, struct wseventvar *);
                    235: int    wskbd_do_ioctl(struct device *, u_long, caddr_t, int, struct proc *);
                    236:
                    237: struct cfdriver wskbd_cd = {
                    238:        NULL, "wskbd", DV_TTY
                    239: };
                    240:
                    241: struct cfattach wskbd_ca = {
                    242:        sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
                    243:        wskbd_detach, wskbd_activate
                    244: };
                    245:
                    246: extern int kbd_reset;
                    247:
                    248: #ifndef WSKBD_DEFAULT_BELL_PITCH
                    249: #define        WSKBD_DEFAULT_BELL_PITCH        400     /* 400Hz */
                    250: #endif
                    251: #ifndef WSKBD_DEFAULT_BELL_PERIOD
                    252: #define        WSKBD_DEFAULT_BELL_PERIOD       100     /* 100ms */
                    253: #endif
                    254: #ifndef WSKBD_DEFAULT_BELL_VOLUME
                    255: #define        WSKBD_DEFAULT_BELL_VOLUME       50      /* 50% volume */
                    256: #endif
                    257:
                    258: struct wskbd_bell_data wskbd_default_bell_data = {
                    259:        WSKBD_BELL_DOALL,
                    260:        WSKBD_DEFAULT_BELL_PITCH,
                    261:        WSKBD_DEFAULT_BELL_PERIOD,
                    262:        WSKBD_DEFAULT_BELL_VOLUME,
                    263: };
                    264:
                    265: #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
                    266: #define        WSKBD_DEFAULT_KEYREPEAT_DEL1    400     /* 400ms to start repeating */
                    267: #endif
                    268: #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
                    269: #define        WSKBD_DEFAULT_KEYREPEAT_DELN    100     /* 100ms to between repeats */
                    270: #endif
                    271:
                    272: struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
                    273:        WSKBD_KEYREPEAT_DOALL,
                    274:        WSKBD_DEFAULT_KEYREPEAT_DEL1,
                    275:        WSKBD_DEFAULT_KEYREPEAT_DELN,
                    276: };
                    277:
                    278: #if NWSMUX > 0 || NWSDISPLAY > 0
                    279: struct wssrcops wskbd_srcops = {
                    280:        WSMUX_KBD,
                    281:        wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl,
                    282:        wskbd_displayioctl,
                    283: #if NWSDISPLAY > 0
                    284:        wskbd_set_display
                    285: #else
                    286:        NULL
                    287: #endif
                    288: };
                    289: #endif
                    290:
                    291: #if NWSDISPLAY > 0
                    292: void wskbd_repeat(void *v);
                    293: #endif
                    294:
                    295: static int wskbd_console_initted;
                    296: static struct wskbd_softc *wskbd_console_device;
                    297: static struct wskbd_internal wskbd_console_data;
                    298:
                    299: void   wskbd_update_layout(struct wskbd_internal *, kbd_t);
                    300:
                    301: #if NAUDIO > 0
                    302: extern int wskbd_set_mixervolume(long dir);
                    303: #endif
                    304:
                    305: void
                    306: wskbd_update_layout(struct wskbd_internal *id, kbd_t enc)
                    307: {
                    308:        if (enc & KB_METAESC)
                    309:                id->t_flags |= WSKFL_METAESC;
                    310:        else
                    311:                id->t_flags &= ~WSKFL_METAESC;
                    312: }
                    313:
                    314: /*
                    315:  * Print function (for parent devices).
                    316:  */
                    317: int
                    318: wskbddevprint(void *aux, const char *pnp)
                    319: {
                    320: #if 0
                    321:        struct wskbddev_attach_args *ap = aux;
                    322: #endif
                    323:
                    324:        if (pnp)
                    325:                printf("wskbd at %s", pnp);
                    326: #if 0
                    327:        printf(" console %d", ap->console);
                    328: #endif
                    329:
                    330:        return (UNCONF);
                    331: }
                    332:
                    333: int
                    334: wskbd_match(struct device *parent, void *match, void *aux)
                    335: {
                    336:        struct cfdata *cf = match;
                    337:        struct wskbddev_attach_args *ap = aux;
                    338:
                    339:        if (cf->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
                    340:                /*
                    341:                 * If console-ness of device specified, either match
                    342:                 * exactly (at high priority), or fail.
                    343:                 */
                    344:                if (cf->wskbddevcf_console != 0 && ap->console != 0)
                    345:                        return (10);
                    346:                else
                    347:                        return (0);
                    348:        }
                    349:
                    350:        /* If console-ness unspecified, it wins. */
                    351:        return (1);
                    352: }
                    353:
                    354: void
                    355: wskbd_attach(struct device *parent, struct device *self, void *aux)
                    356: {
                    357:        struct wskbd_softc *sc = (struct wskbd_softc *)self;
                    358:        struct wskbddev_attach_args *ap = aux;
                    359: #if NWSMUX > 0
                    360:        int mux, error;
                    361: #endif
                    362:
                    363:        sc->sc_isconsole = ap->console;
                    364:
                    365: #if NWSMUX > 0 || NWSDISPLAY > 0
                    366:        sc->sc_base.me_ops = &wskbd_srcops;
                    367: #endif
                    368: #if NWSMUX > 0
                    369:        mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux;
                    370:        if (ap->console) {
                    371:                /* Ignore mux for console; it always goes to the console mux. */
                    372:                /* printf(" (mux %d ignored for console)", mux); */
                    373:                mux = -1;
                    374:        }
                    375:        if (mux >= 0)
                    376:                printf(" mux %d", mux);
                    377: #else
                    378: #if 0  /* not worth keeping, especially since the default value is not -1... */
                    379:        if (sc->sc_base.me_dv.dv_cfdata->wskbddevcf_mux >= 0)
                    380:                printf(" (mux ignored)");
                    381: #endif
                    382: #endif /* NWSMUX > 0 */
                    383:
                    384:        if (ap->console) {
                    385:                sc->id = &wskbd_console_data;
                    386:        } else {
                    387:                sc->id = malloc(sizeof(struct wskbd_internal),
                    388:                    M_DEVBUF, M_WAITOK);
                    389:                bzero(sc->id, sizeof(struct wskbd_internal));
                    390:                sc->id->t_keymap = ap->keymap;
                    391:                wskbd_update_layout(sc->id, ap->keymap->layout);
                    392:        }
                    393:
                    394: #if NWSDISPLAY > 0
                    395:        timeout_set(&sc->sc_repeat_ch, wskbd_repeat, sc);
                    396: #endif
                    397:
                    398:        sc->id->t_sc = sc;
                    399:
                    400:        sc->sc_accessops = ap->accessops;
                    401:        sc->sc_accesscookie = ap->accesscookie;
                    402:        sc->sc_repeating = 0;
                    403:        sc->sc_translating = 1;
                    404:        sc->sc_ledstate = -1; /* force update */
                    405:
                    406:        if (wskbd_load_keymap(sc->id->t_keymap,
                    407:            &sc->sc_map, &sc->sc_maplen) != 0)
                    408:                panic("cannot load keymap");
                    409:
                    410:        sc->sc_layout = sc->id->t_keymap->layout;
                    411:
                    412:        /* set default bell and key repeat data */
                    413:        sc->sc_bell_data = wskbd_default_bell_data;
                    414:        sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
                    415:
                    416:        if (ap->console) {
                    417:                KASSERT(wskbd_console_initted);
                    418:                KASSERT(wskbd_console_device == NULL);
                    419:
                    420:                wskbd_console_device = sc;
                    421:
                    422:                printf(": console keyboard");
                    423:
                    424: #if NWSDISPLAY > 0
                    425:                wsdisplay_set_console_kbd(&sc->sc_base); /* sets me_dispdv */
                    426:                if (sc->sc_displaydv != NULL)
                    427:                        printf(", using %s", sc->sc_displaydv->dv_xname);
                    428: #endif
                    429:        }
                    430:        printf("\n");
                    431:
                    432: #if NWSMUX > 0
                    433:        if (mux >= 0) {
                    434:                error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
                    435:                if (error)
                    436:                        printf("%s: attach error=%d\n",
                    437:                            sc->sc_base.me_dv.dv_xname, error);
                    438:        }
                    439: #endif
                    440:
                    441: #if WSDISPLAY > 0 && NWSMUX == 0
                    442:        if (ap->console == 0) {
                    443:                /*
                    444:                 * In the non-wsmux world, always connect wskbd0 and wsdisplay0
                    445:                 * together.
                    446:                 */
                    447:                extern struct cfdriver wsdisplay_cd;
                    448:
                    449:                if (wsdisplay_cd.cd_ndevs != 0 && self->dv_unit == 0) {
                    450:                        if (wskbd_set_display(self,
                    451:                            wsdisplay_cd.cd_devs[0]) == 0)
                    452:                                wsdisplay_set_kbd(wsdisplay_cd.cd_devs[0],
                    453:                                    (struct wsevsrc *)sc);
                    454:                }
                    455:        }
                    456: #endif
                    457:
                    458: }
                    459:
                    460: void
                    461: wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie,
                    462:     const struct wskbd_mapdata *mapdata)
                    463: {
                    464:
                    465:        KASSERT(!wskbd_console_initted);
                    466:
                    467:        wskbd_console_data.t_keymap = mapdata;
                    468:        wskbd_update_layout(&wskbd_console_data, mapdata->layout);
                    469:
                    470:        wskbd_console_data.t_consops = consops;
                    471:        wskbd_console_data.t_consaccesscookie = conscookie;
                    472:
                    473: #if NWSDISPLAY > 0
                    474:        wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell);
                    475: #endif
                    476:
                    477:        wskbd_console_initted = 1;
                    478: }
                    479:
                    480: void
                    481: wskbd_cndetach()
                    482: {
                    483:        KASSERT(wskbd_console_initted);
                    484:
                    485:        wskbd_console_data.t_keymap = 0;
                    486:
                    487:        wskbd_console_data.t_consops = 0;
                    488:        wskbd_console_data.t_consaccesscookie = 0;
                    489:
                    490: #if NWSDISPLAY > 0
                    491:        wsdisplay_unset_cons_kbd();
                    492: #endif
                    493:
                    494:        wskbd_console_initted = 0;
                    495: }
                    496:
                    497: #if NWSDISPLAY > 0
                    498: void
                    499: wskbd_repeat(void *v)
                    500: {
                    501:        struct wskbd_softc *sc = (struct wskbd_softc *)v;
                    502:        int s = spltty();
                    503:
                    504:        if (!sc->sc_repeating) {
                    505:                /*
                    506:                 * race condition: a "key up" event came in when wskbd_repeat()
                    507:                 * was already called but not yet spltty()'d
                    508:                 */
                    509:                splx(s);
                    510:                return;
                    511:        }
                    512:        if (sc->sc_translating) {
                    513:                /* deliver keys */
                    514:                if (sc->sc_base.me_dispdv != NULL) {
                    515:                        int i;
                    516:                        for (i = 0; i < sc->sc_repeating; i++)
                    517:                                wsdisplay_kbdinput(sc->sc_base.me_dispdv,
                    518:                                    sc->id->t_symbols[i]);
                    519:                }
                    520:        } else {
                    521:                /* queue event */
                    522:                wskbd_deliver_event(sc, sc->sc_repeat_type,
                    523:                    sc->sc_repeat_value);
                    524:        }
                    525:        if (sc->sc_keyrepeat_data.delN != 0)
                    526:                timeout_add(&sc->sc_repeat_ch,
                    527:                    (hz * sc->sc_keyrepeat_data.delN) / 1000);
                    528:        splx(s);
                    529: }
                    530: #endif
                    531:
                    532: int
                    533: wskbd_activate(struct device *self, enum devact act)
                    534: {
                    535:        struct wskbd_softc *sc = (struct wskbd_softc *)self;
                    536:
                    537:        if (act == DVACT_DEACTIVATE)
                    538:                sc->sc_dying = 1;
                    539:        return (0);
                    540: }
                    541:
                    542: /*
                    543:  * Detach a keyboard.  To keep track of users of the softc we keep
                    544:  * a reference count that's incremented while inside, e.g., read.
                    545:  * If the keyboard is active and the reference count is > 0 (0 is the
                    546:  * normal state) we post an event and then wait for the process
                    547:  * that had the reference to wake us up again.  Then we blow away the
                    548:  * vnode and return (which will deallocate the softc).
                    549:  */
                    550: int
                    551: wskbd_detach(struct device  *self, int flags)
                    552: {
                    553:        struct wskbd_softc *sc = (struct wskbd_softc *)self;
                    554:        struct wseventvar *evar;
                    555:        int maj, mn;
                    556:        int s;
                    557:
                    558: #if NWSMUX > 0
                    559:        /* Tell parent mux we're leaving. */
                    560:        if (sc->sc_base.me_parent != NULL)
                    561:                wsmux_detach_sc(&sc->sc_base);
                    562: #endif
                    563:
                    564: #if NWSDISPLAY > 0
                    565:        if (sc->sc_repeating) {
                    566:                sc->sc_repeating = 0;
                    567:                timeout_del(&sc->sc_repeat_ch);
                    568:        }
                    569: #endif
                    570:
                    571:        if (sc->sc_isconsole) {
                    572:                KASSERT(wskbd_console_device == sc);
                    573:                wskbd_console_device = NULL;
                    574:        }
                    575:
                    576:        evar = sc->sc_base.me_evp;
                    577:        if (evar != NULL && evar->io != NULL) {
                    578:                s = spltty();
                    579:                if (--sc->sc_refcnt >= 0) {
                    580:                        /* Wake everyone by generating a dummy event. */
                    581:                        if (++evar->put >= WSEVENT_QSIZE)
                    582:                                evar->put = 0;
                    583:                        WSEVENT_WAKEUP(evar);
                    584:                        /* Wait for processes to go away. */
                    585:                        if (tsleep(sc, PZERO, "wskdet", hz * 60))
                    586:                                printf("wskbd_detach: %s didn't detach\n",
                    587:                                       sc->sc_base.me_dv.dv_xname);
                    588:                }
                    589:                splx(s);
                    590:        }
                    591:
                    592:        /* locate the major number */
                    593:        for (maj = 0; maj < nchrdev; maj++)
                    594:                if (cdevsw[maj].d_open == wskbdopen)
                    595:                        break;
                    596:
                    597:        /* Nuke the vnodes for any open instances. */
                    598:        mn = self->dv_unit;
                    599:        vdevgone(maj, mn, mn, VCHR);
                    600:
                    601:        return (0);
                    602: }
                    603:
                    604: void
                    605: wskbd_input(struct device *dev, u_int type, int value)
                    606: {
                    607:        struct wskbd_softc *sc = (struct wskbd_softc *)dev;
                    608: #if NWSDISPLAY > 0
                    609:        int num, i;
                    610: #endif
                    611:
                    612: #if NWSDISPLAY > 0
                    613:        if (sc->sc_repeating) {
                    614:                sc->sc_repeating = 0;
                    615:                timeout_del(&sc->sc_repeat_ch);
                    616:        }
                    617:
                    618:        /*
                    619:         * If /dev/wskbdN is not connected in event mode translate and
                    620:         * send upstream.
                    621:         */
                    622:        if (sc->sc_translating) {
                    623: #ifdef BURNER_SUPPORT
                    624:                if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_displaydv != NULL)
                    625:                        wsdisplay_burn(sc->sc_displaydv, WSDISPLAY_BURN_KBD);
                    626: #endif
                    627:                num = wskbd_translate(sc->id, type, value);
                    628:                if (num > 0) {
                    629:                        if (sc->sc_base.me_dispdv != NULL) {
                    630: #ifdef SCROLLBACK_SUPPORT
                    631:                                /* XXX - Shift_R+PGUP(release) emits PrtSc */
                    632:                                if (sc->id->t_symbols[0] != KS_Print_Screen) {
                    633:                                        wsscrollback(sc->sc_base.me_dispdv,
                    634:                                            WSDISPLAY_SCROLL_RESET);
                    635:                                }
                    636: #endif
                    637:                                for (i = 0; i < num; i++) {
                    638:                                        wsdisplay_kbdinput(sc->sc_base.me_dispdv,
                    639:                                            sc->id->t_symbols[i]);
                    640:                                }
                    641:                        }
                    642:
                    643:                        if (sc->sc_keyrepeat_data.del1 != 0) {
                    644:                                sc->sc_repeating = num;
                    645:                                timeout_add(&sc->sc_repeat_ch,
                    646:                                    (hz * sc->sc_keyrepeat_data.del1) / 1000);
                    647:                        }
                    648:                }
                    649:                return;
                    650:        }
                    651: #endif
                    652:
                    653:        wskbd_deliver_event(sc, type, value);
                    654:
                    655: #if NWSDISPLAY > 0
                    656:        /* Repeat key presses if enabled. */
                    657:        if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) {
                    658:                sc->sc_repeat_type = type;
                    659:                sc->sc_repeat_value = value;
                    660:                sc->sc_repeating = 1;
                    661:                timeout_add(&sc->sc_repeat_ch,
                    662:                    (hz * sc->sc_keyrepeat_data.del1) / 1000);
                    663:        }
                    664: #endif
                    665: }
                    666:
                    667: /*
                    668:  * Keyboard is generating events.  Turn this keystroke into an
                    669:  * event and put it in the queue.  If the queue is full, the
                    670:  * keystroke is lost (sorry!).
                    671:  */
                    672: void
                    673: wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value)
                    674: {
                    675:        struct wseventvar *evar;
                    676:        struct wscons_event *ev;
                    677:        int put;
                    678:
                    679:        evar = sc->sc_base.me_evp;
                    680:
                    681:        if (evar == NULL) {
                    682:                DPRINTF(("wskbd_input: not open\n"));
                    683:                return;
                    684:        }
                    685:
                    686: #ifdef DIAGNOSTIC
                    687:        if (evar->q == NULL) {
                    688:                printf("wskbd_input: evar->q=NULL\n");
                    689:                return;
                    690:        }
                    691: #endif
                    692:
                    693:        put = evar->put;
                    694:        ev = &evar->q[put];
                    695:        put = (put + 1) % WSEVENT_QSIZE;
                    696:        if (put == evar->get) {
                    697:                log(LOG_WARNING, "%s: event queue overflow\n",
                    698:                    sc->sc_base.me_dv.dv_xname);
                    699:                return;
                    700:        }
                    701:        ev->type = type;
                    702:        ev->value = value;
                    703:        nanotime(&ev->time);
                    704:        evar->put = put;
                    705:        WSEVENT_WAKEUP(evar);
                    706: }
                    707:
                    708: #ifdef WSDISPLAY_COMPAT_RAWKBD
                    709: void
                    710: wskbd_rawinput(struct device *dev, u_char *buf, int len)
                    711: {
                    712: #if NWSDISPLAY > 0
                    713:        struct wskbd_softc *sc = (struct wskbd_softc *)dev;
                    714:        int i;
                    715:
                    716:        if (sc->sc_base.me_dispdv != NULL)
                    717:                for (i = 0; i < len; i++)
                    718:                        wsdisplay_kbdinput(sc->sc_base.me_dispdv, buf[i]);
                    719:        /* this is KS_GROUP_Ascii */
                    720: #endif
                    721: }
                    722: #endif /* WSDISPLAY_COMPAT_RAWKBD */
                    723:
                    724: #if NWSDISPLAY > 0
                    725: void
                    726: wskbd_holdscreen(struct wskbd_softc *sc, int hold)
                    727: {
                    728:        int new_state;
                    729:
                    730:        if (sc->sc_base.me_dispdv != NULL) {
                    731:                wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold);
                    732:                new_state = sc->sc_ledstate;
                    733:                if (hold)
                    734:                        new_state |= WSKBD_LED_SCROLL;
                    735:                else
                    736:                        new_state &= ~WSKBD_LED_SCROLL;
                    737:                if (new_state != sc->sc_ledstate) {
                    738:                        (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
                    739:                                                      new_state);
                    740:                        sc->sc_ledstate = new_state;
                    741:                }
                    742:        }
                    743: }
                    744: #endif
                    745:
                    746: int
                    747: wskbd_enable(struct wskbd_softc *sc, int on)
                    748: {
                    749:        int error;
                    750:
                    751: #if NWSDISPLAY > 0
                    752:        if (sc->sc_base.me_dispdv != NULL)
                    753:                return (0);
                    754:
                    755:        /* Always cancel auto repeat when fiddling with the kbd. */
                    756:        if (sc->sc_repeating) {
                    757:                sc->sc_repeating = 0;
                    758:                timeout_del(&sc->sc_repeat_ch);
                    759:        }
                    760: #endif
                    761:
                    762:        error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
                    763:        DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error));
                    764:        return (error);
                    765: }
                    766:
                    767: #if NWSMUX > 0
                    768: int
                    769: wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp)
                    770: {
                    771:        struct wskbd_softc *sc = (struct wskbd_softc *)me;
                    772:
                    773:        if (sc->sc_dying)
                    774:                return (EIO);
                    775:
                    776:        if (sc->sc_base.me_evp != NULL)
                    777:                return (EBUSY);
                    778:
                    779:        return (wskbd_do_open(sc, evp));
                    780: }
                    781: #endif
                    782:
                    783: int
                    784: wskbdopen(dev_t dev, int flags, int mode, struct proc *p)
                    785: {
                    786:        struct wskbd_softc *sc;
                    787:        struct wseventvar *evar;
                    788:        int unit, error;
                    789:
                    790:        unit = minor(dev);
                    791:        if (unit >= wskbd_cd.cd_ndevs ||        /* make sure it was attached */
                    792:            (sc = wskbd_cd.cd_devs[unit]) == NULL)
                    793:                return (ENXIO);
                    794:
                    795: #if NWSMUX > 0
                    796:        DPRINTF(("wskbdopen: %s mux=%p p=%p\n", sc->sc_base.me_dv.dv_xname,
                    797:                 sc->sc_base.me_parent, p));
                    798: #endif
                    799:
                    800:        if (sc->sc_dying)
                    801:                return (EIO);
                    802:
                    803:        if ((flags & (FREAD | FWRITE)) == FWRITE) {
                    804:                /* Not opening for read, only ioctl is available. */
                    805:                return (0);
                    806:        }
                    807:
                    808: #if NWSMUX > 0
                    809:        if (sc->sc_base.me_parent != NULL) {
                    810:                /* Grab the keyboard out of the greedy hands of the mux. */
                    811:                DPRINTF(("wskbdopen: detach\n"));
                    812:                wsmux_detach_sc(&sc->sc_base);
                    813:        }
                    814: #endif
                    815:
                    816:        if (sc->sc_base.me_evp != NULL)
                    817:                return (EBUSY);
                    818:
                    819:        evar = &sc->sc_base.me_evar;
                    820:        wsevent_init(evar);
                    821:        evar->io = p;
                    822:
                    823:        error = wskbd_do_open(sc, evar);
                    824:        if (error) {
                    825:                DPRINTF(("wskbdopen: %s open failed\n",
                    826:                         sc->sc_base.me_dv.dv_xname));
                    827:                sc->sc_base.me_evp = NULL;
                    828:                wsevent_fini(evar);
                    829:        }
                    830:        return (error);
                    831: }
                    832:
                    833: int
                    834: wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp)
                    835: {
                    836:        sc->sc_base.me_evp = evp;
                    837:        sc->sc_translating = 0;
                    838:
                    839:        return (wskbd_enable(sc, 1));
                    840: }
                    841:
                    842: int
                    843: wskbdclose(dev_t dev, int flags, int mode, struct proc *p)
                    844: {
                    845:        struct wskbd_softc *sc =
                    846:            (struct wskbd_softc *)wskbd_cd.cd_devs[minor(dev)];
                    847:        struct wseventvar *evar = sc->sc_base.me_evp;
                    848:
                    849:        if (evar == NULL)
                    850:                /* not open for read */
                    851:                return (0);
                    852:
                    853:        sc->sc_base.me_evp = NULL;
                    854:        sc->sc_translating = 1;
                    855:        (void)wskbd_enable(sc, 0);
                    856:        wsevent_fini(evar);
                    857:
                    858:        return (0);
                    859: }
                    860:
                    861: #if NWSMUX > 0
                    862: int
                    863: wskbd_mux_close(struct wsevsrc *me)
                    864: {
                    865:        struct wskbd_softc *sc = (struct wskbd_softc *)me;
                    866:
                    867:        sc->sc_base.me_evp = NULL;
                    868:        sc->sc_translating = 1;
                    869:        (void)wskbd_enable(sc, 0);
                    870:
                    871:        return (0);
                    872: }
                    873: #endif
                    874:
                    875: int
                    876: wskbdread(dev_t dev, struct uio *uio, int flags)
                    877: {
                    878:        struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
                    879:        int error;
                    880:
                    881:        if (sc->sc_dying)
                    882:                return (EIO);
                    883:
                    884: #ifdef DIAGNOSTIC
                    885:        if (sc->sc_base.me_evp == NULL) {
                    886:                printf("wskbdread: evp == NULL\n");
                    887:                return (EINVAL);
                    888:        }
                    889: #endif
                    890:
                    891:        sc->sc_refcnt++;
                    892:        error = wsevent_read(&sc->sc_base.me_evar, uio, flags);
                    893:        if (--sc->sc_refcnt < 0) {
                    894:                wakeup(sc);
                    895:                error = EIO;
                    896:        }
                    897:        return (error);
                    898: }
                    899:
                    900: int
                    901: wskbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
                    902: {
                    903:        return (wskbd_do_ioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p));
                    904: }
                    905:
                    906: /* A wrapper around the ioctl() workhorse to make reference counting easy. */
                    907: int
                    908: wskbd_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
                    909:     struct proc *p)
                    910: {
                    911:        struct wskbd_softc *sc = (struct wskbd_softc *)dv;
                    912:        int error;
                    913:
                    914:        sc->sc_refcnt++;
                    915:        error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p);
                    916:        if (--sc->sc_refcnt < 0)
                    917:                wakeup(sc);
                    918:        return (error);
                    919: }
                    920:
                    921: int
                    922: wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, int flag,
                    923:      struct proc *p)
                    924: {
                    925:        int error;
                    926:
                    927:        /*
                    928:         * Try the generic ioctls that the wskbd interface supports.
                    929:         */
                    930:        switch (cmd) {
                    931:        case FIONBIO:           /* we will remove this someday (soon???) */
                    932:                return (0);
                    933:
                    934:        case FIOASYNC:
                    935:                if (sc->sc_base.me_evp == NULL)
                    936:                        return (EINVAL);
                    937:                sc->sc_base.me_evp->async = *(int *)data != 0;
                    938:                return (0);
                    939:
                    940:        case FIOSETOWN:
                    941:                if (sc->sc_base.me_evp == NULL)
                    942:                        return (EINVAL);
                    943:                if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid &&
                    944:                    *(int *)data != sc->sc_base.me_evp->io->p_pid)
                    945:                        return (EPERM);
                    946:                return (0);
                    947:
                    948:        case TIOCSPGRP:
                    949:                if (sc->sc_base.me_evp == NULL)
                    950:                        return (EINVAL);
                    951:                if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
                    952:                        return (EPERM);
                    953:                return (0);
                    954:        }
                    955:
                    956:        /*
                    957:         * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
                    958:         * if it didn't recognize the request.
                    959:         */
                    960:        error = wskbd_displayioctl(&sc->sc_base.me_dv, cmd, data, flag, p);
                    961:        return (error != -1 ? error : ENOTTY);
                    962: }
                    963:
                    964: /*
                    965:  * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
                    966:  * Some of these have no real effect in raw mode, however.
                    967:  */
                    968: int
                    969: wskbd_displayioctl(struct device *dev, u_long cmd, caddr_t data, int flag,
                    970:     struct proc *p)
                    971: {
                    972:        struct wskbd_softc *sc = (struct wskbd_softc *)dev;
                    973:        struct wskbd_bell_data *ubdp, *kbdp;
                    974:        struct wskbd_keyrepeat_data *ukdp, *kkdp;
                    975:        struct wskbd_map_data *umdp;
                    976:        struct wskbd_mapdata md;
                    977:        kbd_t enc;
                    978:        void *buf;
                    979:        int len, error;
                    980:
                    981:        switch (cmd) {
                    982:        case WSKBDIO_BELL:
                    983:        case WSKBDIO_COMPLEXBELL:
                    984:        case WSKBDIO_SETBELL:
                    985:        case WSKBDIO_SETKEYREPEAT:
                    986:        case WSKBDIO_SETDEFAULTKEYREPEAT:
                    987:        case WSKBDIO_SETMAP:
                    988:        case WSKBDIO_SETENCODING:
                    989:                if ((flag & FWRITE) == 0)
                    990:                        return (EACCES);
                    991:        }
                    992:
                    993:        switch (cmd) {
                    994: #define        SETBELL(dstp, srcp, dfltp)                                      \
                    995:     do {                                                               \
                    996:        (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ?          \
                    997:            (srcp)->pitch : (dfltp)->pitch;                             \
                    998:        (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ?        \
                    999:            (srcp)->period : (dfltp)->period;                           \
                   1000:        (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ?        \
                   1001:            (srcp)->volume : (dfltp)->volume;                           \
                   1002:        (dstp)->which = WSKBD_BELL_DOALL;                               \
                   1003:     } while (0)
                   1004:
                   1005:        case WSKBDIO_BELL:
                   1006:                return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
                   1007:                    WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
                   1008:
                   1009:        case WSKBDIO_COMPLEXBELL:
                   1010:                ubdp = (struct wskbd_bell_data *)data;
                   1011:                SETBELL(ubdp, ubdp, &sc->sc_bell_data);
                   1012:                return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
                   1013:                    WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
                   1014:
                   1015:        case WSKBDIO_SETBELL:
                   1016:                kbdp = &sc->sc_bell_data;
                   1017: setbell:
                   1018:                ubdp = (struct wskbd_bell_data *)data;
                   1019:                SETBELL(kbdp, ubdp, kbdp);
                   1020:                return (0);
                   1021:
                   1022:        case WSKBDIO_GETBELL:
                   1023:                kbdp = &sc->sc_bell_data;
                   1024: getbell:
                   1025:                ubdp = (struct wskbd_bell_data *)data;
                   1026:                SETBELL(ubdp, kbdp, kbdp);
                   1027:                return (0);
                   1028:
                   1029:        case WSKBDIO_SETDEFAULTBELL:
                   1030:                if ((error = suser(p, 0)) != 0)
                   1031:                        return (error);
                   1032:                kbdp = &wskbd_default_bell_data;
                   1033:                goto setbell;
                   1034:
                   1035:
                   1036:        case WSKBDIO_GETDEFAULTBELL:
                   1037:                kbdp = &wskbd_default_bell_data;
                   1038:                goto getbell;
                   1039:
                   1040: #undef SETBELL
                   1041:
                   1042: #define        SETKEYREPEAT(dstp, srcp, dfltp)                                 \
                   1043:     do {                                                               \
                   1044:        (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ?       \
                   1045:            (srcp)->del1 : (dfltp)->del1;                               \
                   1046:        (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ?       \
                   1047:            (srcp)->delN : (dfltp)->delN;                               \
                   1048:        (dstp)->which = WSKBD_KEYREPEAT_DOALL;                          \
                   1049:     } while (0)
                   1050:
                   1051:        case WSKBDIO_SETKEYREPEAT:
                   1052:                kkdp = &sc->sc_keyrepeat_data;
                   1053: setkeyrepeat:
                   1054:                ukdp = (struct wskbd_keyrepeat_data *)data;
                   1055:                SETKEYREPEAT(kkdp, ukdp, kkdp);
                   1056:                return (0);
                   1057:
                   1058:        case WSKBDIO_GETKEYREPEAT:
                   1059:                kkdp = &sc->sc_keyrepeat_data;
                   1060: getkeyrepeat:
                   1061:                ukdp = (struct wskbd_keyrepeat_data *)data;
                   1062:                SETKEYREPEAT(ukdp, kkdp, kkdp);
                   1063:                return (0);
                   1064:
                   1065:        case WSKBDIO_SETDEFAULTKEYREPEAT:
                   1066:                if ((error = suser(p, 0)) != 0)
                   1067:                        return (error);
                   1068:                kkdp = &wskbd_default_keyrepeat_data;
                   1069:                goto setkeyrepeat;
                   1070:
                   1071:
                   1072:        case WSKBDIO_GETDEFAULTKEYREPEAT:
                   1073:                kkdp = &wskbd_default_keyrepeat_data;
                   1074:                goto getkeyrepeat;
                   1075:
                   1076: #undef SETKEYREPEAT
                   1077:
                   1078:        case WSKBDIO_SETMAP:
                   1079:                umdp = (struct wskbd_map_data *)data;
                   1080:                if (umdp->maplen > WSKBDIO_MAXMAPLEN)
                   1081:                        return (EINVAL);
                   1082:
                   1083:                len = umdp->maplen * sizeof(struct wscons_keymap);
                   1084:                buf = malloc(len, M_TEMP, M_WAITOK);
                   1085:                error = copyin(umdp->map, buf, len);
                   1086:                if (error == 0) {
                   1087:                        wskbd_init_keymap(umdp->maplen,
                   1088:                                          &sc->sc_map, &sc->sc_maplen);
                   1089:                        memcpy(sc->sc_map, buf, len);
                   1090:                        /* drop the variant bits handled by the map */
                   1091:                        sc->sc_layout = KB_USER |
                   1092:                              (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD);
                   1093:                        wskbd_update_layout(sc->id, sc->sc_layout);
                   1094:                }
                   1095:                free(buf, M_TEMP);
                   1096:                return(error);
                   1097:
                   1098:        case WSKBDIO_GETMAP:
                   1099:                umdp = (struct wskbd_map_data *)data;
                   1100:                if (umdp->maplen > sc->sc_maplen)
                   1101:                        umdp->maplen = sc->sc_maplen;
                   1102:                error = copyout(sc->sc_map, umdp->map,
                   1103:                                umdp->maplen*sizeof(struct wscons_keymap));
                   1104:                return(error);
                   1105:
                   1106:        case WSKBDIO_GETENCODING:
                   1107:                *((kbd_t *) data) = sc->sc_layout;
                   1108:                return(0);
                   1109:
                   1110:        case WSKBDIO_SETENCODING:
                   1111:                enc = *((kbd_t *)data);
                   1112:                if (KB_ENCODING(enc) == KB_USER) {
                   1113:                        /* user map must already be loaded */
                   1114:                        if (KB_ENCODING(sc->sc_layout) != KB_USER)
                   1115:                                return (EINVAL);
                   1116:                        /* map variants make no sense */
                   1117:                        if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD)
                   1118:                                return (EINVAL);
                   1119:                } else {
                   1120:                        md = *(sc->id->t_keymap); /* structure assignment */
                   1121:                        md.layout = enc;
                   1122:                        error = wskbd_load_keymap(&md, &sc->sc_map,
                   1123:                                                  &sc->sc_maplen);
                   1124:                        if (error)
                   1125:                                return(error);
                   1126:                }
                   1127:                sc->sc_layout = enc;
                   1128:                wskbd_update_layout(sc->id, enc);
                   1129:                return (0);
                   1130:        }
                   1131:
                   1132:        /*
                   1133:         * Try the keyboard driver for WSKBDIO ioctls.  It returns -1
                   1134:         * if it didn't recognize the request, and in turn we return
                   1135:         * -1 if we didn't recognize the request.
                   1136:         */
                   1137: /* printf("kbdaccess\n"); */
                   1138:        error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
                   1139:                                           flag, p);
                   1140: #ifdef WSDISPLAY_COMPAT_RAWKBD
                   1141:        if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
                   1142:                int s = spltty();
                   1143:                sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
                   1144:                                         | MOD_CONTROL_L | MOD_CONTROL_R
                   1145:                                         | MOD_META_L | MOD_META_R
                   1146:                                         | MOD_COMMAND
                   1147:                                         | MOD_COMMAND1 | MOD_COMMAND2);
                   1148: #if NWSDISPLAY > 0
                   1149:                if (sc->sc_repeating) {
                   1150:                        sc->sc_repeating = 0;
                   1151:                        timeout_del(&sc->sc_repeat_ch);
                   1152:                }
                   1153: #endif
                   1154:                splx(s);
                   1155:        }
                   1156: #endif
                   1157:        return (error);
                   1158: }
                   1159:
                   1160: int
                   1161: wskbdpoll(dev_t dev, int events, struct proc *p)
                   1162: {
                   1163:        struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
                   1164:
                   1165:        if (sc->sc_base.me_evp == NULL)
                   1166:                return (POLLERR);
                   1167:        return (wsevent_poll(sc->sc_base.me_evp, events, p));
                   1168: }
                   1169:
                   1170: #if NWSDISPLAY > 0
                   1171:
                   1172: int
                   1173: wskbd_pickfree()
                   1174: {
                   1175:        int i;
                   1176:        struct wskbd_softc *sc;
                   1177:
                   1178:        for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
                   1179:                if ((sc = wskbd_cd.cd_devs[i]) == NULL)
                   1180:                        continue;
                   1181:                if (sc->sc_displaydv == NULL)
                   1182:                        return (i);
                   1183:        }
                   1184:        return (-1);
                   1185: }
                   1186:
                   1187: struct wsevsrc *
                   1188: wskbd_set_console_display(struct device *displaydv, struct wsevsrc *me)
                   1189: {
                   1190:        struct wskbd_softc *sc = wskbd_console_device;
                   1191:
                   1192:        if (sc == NULL)
                   1193:                return (NULL);
                   1194:        sc->sc_base.me_dispdv = displaydv;
                   1195: #if NWSMUX > 0
                   1196:        (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base);
                   1197: #endif
                   1198:        return (&sc->sc_base);
                   1199: }
                   1200:
                   1201: int
                   1202: wskbd_set_display(struct device *dv, struct device *displaydv)
                   1203: {
                   1204:        struct wskbd_softc *sc = (struct wskbd_softc *)dv;
                   1205:        struct device *odisplaydv;
                   1206:        int error;
                   1207:
                   1208:        DPRINTF(("wskbd_set_display: %s odisp=%p disp=%p cons=%d\n",
                   1209:                 dv->dv_xname, sc->sc_base.me_dispdv, displaydv,
                   1210:                 sc->sc_isconsole));
                   1211:
                   1212:        if (sc->sc_isconsole)
                   1213:                return (EBUSY);
                   1214:
                   1215:        if (displaydv != NULL) {
                   1216:                if (sc->sc_base.me_dispdv != NULL)
                   1217:                        return (EBUSY);
                   1218:        } else {
                   1219:                if (sc->sc_base.me_dispdv == NULL)
                   1220:                        return (ENXIO);
                   1221:        }
                   1222:
                   1223:        odisplaydv = sc->sc_base.me_dispdv;
                   1224:        sc->sc_base.me_dispdv = NULL;
                   1225:        error = wskbd_enable(sc, displaydv != NULL);
                   1226:        sc->sc_base.me_dispdv = displaydv;
                   1227:        if (error) {
                   1228:                sc->sc_base.me_dispdv = odisplaydv;
                   1229:                return (error);
                   1230:        }
                   1231:
                   1232:        if (displaydv)
                   1233:                printf("%s: connecting to %s\n",
                   1234:                       sc->sc_base.me_dv.dv_xname, displaydv->dv_xname);
                   1235:        else
                   1236:                printf("%s: disconnecting from %s\n",
                   1237:                       sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname);
                   1238:
                   1239:        return (0);
                   1240: }
                   1241:
                   1242: #endif /* NWSDISPLAY > 0 */
                   1243:
                   1244: #if NWSMUX > 0
                   1245: int
                   1246: wskbd_add_mux(int unit, struct wsmux_softc *muxsc)
                   1247: {
                   1248:        struct wskbd_softc *sc;
                   1249:
                   1250:        if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
                   1251:            (sc = wskbd_cd.cd_devs[unit]) == NULL)
                   1252:                return (ENXIO);
                   1253:
                   1254:        if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
                   1255:                return (EBUSY);
                   1256:
                   1257:        return (wsmux_attach_sc(muxsc, &sc->sc_base));
                   1258: }
                   1259: #endif
                   1260:
                   1261: /*
                   1262:  * Console interface.
                   1263:  */
                   1264: int
                   1265: wskbd_cngetc(dev_t dev)
                   1266: {
                   1267:        static int num = 0;
                   1268:        static int pos;
                   1269:        u_int type;
                   1270:        int data;
                   1271:        keysym_t ks;
                   1272:
                   1273:        if (!wskbd_console_initted)
                   1274:                return 0;
                   1275:
                   1276:        if (wskbd_console_device != NULL &&
                   1277:            !wskbd_console_device->sc_translating)
                   1278:                return 0;
                   1279:
                   1280:        for(;;) {
                   1281:                if (num-- > 0) {
                   1282:                        ks = wskbd_console_data.t_symbols[pos++];
                   1283:                        if (KS_GROUP(ks) == KS_GROUP_Ascii)
                   1284:                                return (KS_VALUE(ks));
                   1285:                } else {
                   1286:                        (*wskbd_console_data.t_consops->getc)
                   1287:                                (wskbd_console_data.t_consaccesscookie,
                   1288:                                 &type, &data);
                   1289:                        num = wskbd_translate(&wskbd_console_data, type, data);
                   1290:                        pos = 0;
                   1291:                }
                   1292:        }
                   1293: }
                   1294:
                   1295: void
                   1296: wskbd_cnpollc(dev_t dev, int poll)
                   1297: {
                   1298:
                   1299:        if (!wskbd_console_initted)
                   1300:                return;
                   1301:
                   1302:        if (wskbd_console_device != NULL &&
                   1303:            !wskbd_console_device->sc_translating)
                   1304:                return;
                   1305:
                   1306:        (*wskbd_console_data.t_consops->pollc)
                   1307:            (wskbd_console_data.t_consaccesscookie, poll);
                   1308: }
                   1309:
                   1310: void
                   1311: wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume)
                   1312: {
                   1313:        if (!wskbd_console_initted)
                   1314:                return;
                   1315:
                   1316:        if (wskbd_console_data.t_consops->bell != NULL)
                   1317:                (*wskbd_console_data.t_consops->bell)
                   1318:                    (wskbd_console_data.t_consaccesscookie, pitch, period,
                   1319:                        volume);
                   1320: }
                   1321:
                   1322: void
                   1323: update_leds(struct wskbd_internal *id)
                   1324: {
                   1325:        int new_state;
                   1326:
                   1327:        new_state = 0;
                   1328:        if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
                   1329:                new_state |= WSKBD_LED_CAPS;
                   1330:        if (id->t_modifiers & MOD_NUMLOCK)
                   1331:                new_state |= WSKBD_LED_NUM;
                   1332:        if (id->t_modifiers & MOD_COMPOSE)
                   1333:                new_state |= WSKBD_LED_COMPOSE;
                   1334:        if (id->t_modifiers & MOD_HOLDSCREEN)
                   1335:                new_state |= WSKBD_LED_SCROLL;
                   1336:
                   1337:        if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
                   1338:                (*id->t_sc->sc_accessops->set_leds)
                   1339:                    (id->t_sc->sc_accesscookie, new_state);
                   1340:                id->t_sc->sc_ledstate = new_state;
                   1341:        }
                   1342: }
                   1343:
                   1344: void
                   1345: update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask)
                   1346: {
                   1347:        if (toggle) {
                   1348:                if (type == WSCONS_EVENT_KEY_DOWN)
                   1349:                        id->t_modifiers ^= mask;
                   1350:        } else {
                   1351:                if (type == WSCONS_EVENT_KEY_DOWN)
                   1352:                        id->t_modifiers |= mask;
                   1353:                else
                   1354:                        id->t_modifiers &= ~mask;
                   1355:        }
                   1356: }
                   1357:
                   1358: #if NWSDISPLAY > 0
                   1359: void
                   1360: change_displayparam(struct wskbd_softc *sc, int param, int updown,
                   1361:     int wraparound)
                   1362: {
                   1363:        int res;
                   1364:        struct wsdisplay_param dp;
                   1365:
                   1366:        dp.param = param;
                   1367:        res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp);
                   1368:
                   1369:        if (res == EINVAL)
                   1370:                return; /* no such parameter */
                   1371:
                   1372:        dp.curval += updown;
                   1373:        if (dp.max < dp.curval)
                   1374:                dp.curval = wraparound ? dp.min : dp.max;
                   1375:        else
                   1376:        if (dp.curval < dp.min)
                   1377:                dp.curval = wraparound ? dp.max : dp.min;
                   1378:        wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp);
                   1379: }
                   1380: #endif
                   1381:
                   1382: int
                   1383: internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym,
                   1384:     keysym_t ksym2)
                   1385: {
                   1386:        switch (ksym) {
                   1387:        case KS_Cmd:
                   1388:                update_modifier(sc->id, *type, 0, MOD_COMMAND);
                   1389:                ksym = ksym2;
                   1390:                break;
                   1391:
                   1392:        case KS_Cmd1:
                   1393:                update_modifier(sc->id, *type, 0, MOD_COMMAND1);
                   1394:                break;
                   1395:
                   1396:        case KS_Cmd2:
                   1397:                update_modifier(sc->id, *type, 0, MOD_COMMAND2);
                   1398:                break;
                   1399:        }
                   1400:
                   1401:        if (*type != WSCONS_EVENT_KEY_DOWN)
                   1402:                return (0);
                   1403:
                   1404: #ifdef SCROLLBACK_SUPPORT
                   1405: #if NWSDISPLAY > 0
                   1406:        switch (ksym) {
                   1407:        case KS_Cmd_ScrollBack:
                   1408:                if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
                   1409:                        if (sc->sc_displaydv != NULL)
                   1410:                                wsscrollback(sc->sc_displaydv,
                   1411:                                    WSDISPLAY_SCROLL_BACKWARD);
                   1412:                        return (1);
                   1413:                }
                   1414:                break;
                   1415:
                   1416:        case KS_Cmd_ScrollFwd:
                   1417:                if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
                   1418:                        if (sc->sc_displaydv != NULL)
                   1419:                                wsscrollback(sc->sc_displaydv,
                   1420:                                    WSDISPLAY_SCROLL_FORWARD);
                   1421:                        return (1);
                   1422:                }
                   1423:                break;
                   1424:        }
                   1425: #endif
                   1426: #endif
                   1427:
                   1428:        if (!MOD_ONESET(sc->id, MOD_COMMAND) &&
                   1429:            !MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2))
                   1430:                return (0);
                   1431:
                   1432: #ifdef DDB
                   1433:        if (ksym == KS_Cmd_Debugger) {
                   1434:                if (sc->sc_isconsole && db_console)
                   1435:                        Debugger();
                   1436:                /* discard this key (ddb discarded command modifiers) */
                   1437:                *type = WSCONS_EVENT_KEY_UP;
                   1438:                return (1);
                   1439:        }
                   1440: #endif
                   1441:
                   1442: #if NWSDISPLAY > 0
                   1443:        if (sc->sc_base.me_dispdv == NULL)
                   1444:                return (0);
                   1445:
                   1446:        switch (ksym) {
                   1447:        case KS_Cmd_Screen0:
                   1448:        case KS_Cmd_Screen1:
                   1449:        case KS_Cmd_Screen2:
                   1450:        case KS_Cmd_Screen3:
                   1451:        case KS_Cmd_Screen4:
                   1452:        case KS_Cmd_Screen5:
                   1453:        case KS_Cmd_Screen6:
                   1454:        case KS_Cmd_Screen7:
                   1455:        case KS_Cmd_Screen8:
                   1456:        case KS_Cmd_Screen9:
                   1457:        case KS_Cmd_Screen10:
                   1458:        case KS_Cmd_Screen11:
                   1459:                wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
                   1460:                return (1);
                   1461:        case KS_Cmd_ResetEmul:
                   1462:                wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
                   1463:                return (1);
                   1464:        case KS_Cmd_ResetClose:
                   1465:                wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
                   1466:                return (1);
                   1467: #if defined(__i386__) || defined(__amd64__)
                   1468:        case KS_Cmd_KbdReset:
                   1469:                if (kbd_reset == 1) {
                   1470:                        kbd_reset = 0;
                   1471:                        psignal(initproc, SIGUSR1);
                   1472:                }
                   1473:                return (1);
                   1474: #endif
                   1475:        case KS_Cmd_BacklightOn:
                   1476:        case KS_Cmd_BacklightOff:
                   1477:        case KS_Cmd_BacklightToggle:
                   1478:                change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT,
                   1479:                    ksym == KS_Cmd_BacklightOff ? -1 : 1,
                   1480:                    ksym == KS_Cmd_BacklightToggle ? 1 : 0);
                   1481:                return (1);
                   1482:        case KS_Cmd_BrightnessUp:
                   1483:        case KS_Cmd_BrightnessDown:
                   1484:        case KS_Cmd_BrightnessRotate:
                   1485:                change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS,
                   1486:                    ksym == KS_Cmd_BrightnessDown ? -1 : 1,
                   1487:                    ksym == KS_Cmd_BrightnessRotate ? 1 : 0);
                   1488:                return (1);
                   1489:        case KS_Cmd_ContrastUp:
                   1490:        case KS_Cmd_ContrastDown:
                   1491:        case KS_Cmd_ContrastRotate:
                   1492:                change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST,
                   1493:                    ksym == KS_Cmd_ContrastDown ? -1 : 1,
                   1494:                    ksym == KS_Cmd_ContrastRotate ? 1 : 0);
                   1495:                return (1);
                   1496:        }
                   1497: #endif
                   1498:        return (0);
                   1499: }
                   1500:
                   1501: int
                   1502: wskbd_translate(struct wskbd_internal *id, u_int type, int value)
                   1503: {
                   1504:        struct wskbd_softc *sc = id->t_sc;
                   1505:        keysym_t ksym, res, *group;
                   1506:        struct wscons_keymap kpbuf, *kp;
                   1507:        int gindex, iscommand = 0;
                   1508:
                   1509:        if (type == WSCONS_EVENT_ALL_KEYS_UP) {
                   1510: #if NWSDISPLAY > 0
                   1511:                if (sc != NULL && sc->sc_repeating) {
                   1512:                        sc->sc_repeating = 0;
                   1513:                        timeout_del(&sc->sc_repeat_ch);
                   1514:                }
                   1515: #endif
                   1516:                id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R |
                   1517:                    MOD_CONTROL_L | MOD_CONTROL_R |
                   1518:                    MOD_META_L | MOD_META_R |
                   1519:                    MOD_MODESHIFT | MOD_MODELOCK |
                   1520:                    MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
                   1521:                update_leds(id);
                   1522:                return (0);
                   1523:        }
                   1524:
                   1525:        if (sc != NULL) {
                   1526:                if (value < 0 || value >= sc->sc_maplen) {
                   1527: #ifdef DEBUG
                   1528:                        printf("wskbd_translate: keycode %d out of range\n",
                   1529:                               value);
                   1530: #endif
                   1531:                        return (0);
                   1532:                }
                   1533:                kp = sc->sc_map + value;
                   1534:        } else {
                   1535:                kp = &kpbuf;
                   1536:                wskbd_get_mapentry(id->t_keymap, value, kp);
                   1537:        }
                   1538:
                   1539:        /* if this key has a command, process it first */
                   1540:        if (sc != NULL && kp->command != KS_voidSymbol)
                   1541:                iscommand = internal_command(sc, &type, kp->command,
                   1542:                    kp->group1[0]);
                   1543:
                   1544:        /* Now update modifiers */
                   1545:        switch (kp->group1[0]) {
                   1546:        case KS_Shift_L:
                   1547:                update_modifier(id, type, 0, MOD_SHIFT_L);
                   1548:                break;
                   1549:
                   1550:        case KS_Shift_R:
                   1551:                update_modifier(id, type, 0, MOD_SHIFT_R);
                   1552:                break;
                   1553:
                   1554:        case KS_Shift_Lock:
                   1555:                update_modifier(id, type, 1, MOD_SHIFTLOCK);
                   1556:                break;
                   1557:
                   1558:        case KS_Caps_Lock:
                   1559:                update_modifier(id, type, 1, MOD_CAPSLOCK);
                   1560:                break;
                   1561:
                   1562:        case KS_Control_L:
                   1563:                update_modifier(id, type, 0, MOD_CONTROL_L);
                   1564:                break;
                   1565:
                   1566:        case KS_Control_R:
                   1567:                update_modifier(id, type, 0, MOD_CONTROL_R);
                   1568:                break;
                   1569:
                   1570:        case KS_Alt_L:
                   1571:                update_modifier(id, type, 0, MOD_META_L);
                   1572:                break;
                   1573:
                   1574:        case KS_Alt_R:
                   1575:                update_modifier(id, type, 0, MOD_META_R);
                   1576:                break;
                   1577:
                   1578:        case KS_Mode_switch:
                   1579:                update_modifier(id, type, 0, MOD_MODESHIFT);
                   1580:                break;
                   1581:
                   1582:        case KS_Mode_Lock:
                   1583:                update_modifier(id, type, 1, MOD_MODELOCK);
                   1584:                break;
                   1585:
                   1586:        case KS_Num_Lock:
                   1587:                update_modifier(id, type, 1, MOD_NUMLOCK);
                   1588:                break;
                   1589:
                   1590: #if NWSDISPLAY > 0
                   1591:        case KS_Hold_Screen:
                   1592:                if (sc != NULL) {
                   1593:                        update_modifier(id, type, 1, MOD_HOLDSCREEN);
                   1594:                        wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
                   1595:                }
                   1596:                break;
                   1597:
                   1598:        default:
                   1599:                if (sc != NULL && sc->sc_repeating &&
                   1600:                    ((type == WSCONS_EVENT_KEY_UP && value != sc->sc_repkey) ||
                   1601:                     (type == WSCONS_EVENT_KEY_DOWN && value == sc->sc_repkey)))
                   1602:                        return (0);
                   1603:                break;
                   1604: #endif
                   1605:        }
                   1606:
                   1607: #if NWSDISPLAY > 0
                   1608:        if (sc != NULL) {
                   1609:                if (sc->sc_repeating) {
                   1610:                        sc->sc_repeating = 0;
                   1611:                        timeout_del(&sc->sc_repeat_ch);
                   1612:                }
                   1613:                sc->sc_repkey = value;
                   1614:        }
                   1615: #endif
                   1616:
                   1617:        /* If this is a key release or we are in command mode, we are done */
                   1618:        if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
                   1619:                update_leds(id);
                   1620:                return (0);
                   1621:        }
                   1622:
                   1623:        /* Get the keysym */
                   1624:        if (id->t_modifiers & (MOD_MODESHIFT|MOD_MODELOCK) &&
                   1625:            !MOD_ONESET(id, MOD_ANYCONTROL))
                   1626:                group = & kp->group2[0];
                   1627:        else
                   1628:                group = & kp->group1[0];
                   1629:
                   1630:        if ((id->t_modifiers & MOD_NUMLOCK) &&
                   1631:            KS_GROUP(group[1]) == KS_GROUP_Keypad) {
                   1632:                gindex = !MOD_ONESET(id, MOD_ANYSHIFT);
                   1633:                ksym = group[gindex];
                   1634:        } else {
                   1635:                /* CAPS alone should only affect letter keys */
                   1636:                if ((id->t_modifiers & (MOD_CAPSLOCK | MOD_ANYSHIFT)) ==
                   1637:                    MOD_CAPSLOCK) {
                   1638:                        gindex = 0;
                   1639:                        ksym = ksym_upcase(group[0]);
                   1640:                } else {
                   1641:                        gindex = MOD_ONESET(id, MOD_ANYSHIFT);
                   1642:                        ksym = group[gindex];
                   1643:                }
                   1644:        }
                   1645:
                   1646:        /* Submit Audio keys for hotkey processing */
                   1647:        if (KS_GROUP(ksym) == KS_GROUP_Function) {
                   1648:                switch (ksym) {
                   1649: #if NAUDIO > 0
                   1650:                case KS_AudioMute:
                   1651:                        workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume,
                   1652:                            (void *)(long)0, NULL);
                   1653:                        break;
                   1654:                case KS_AudioLower:
                   1655:                        workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume,
                   1656:                            (void *)(long)-1, NULL);
                   1657:                        break;
                   1658:                case KS_AudioRaise:
                   1659:                        workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume,
                   1660:                            (void *)(long)1, NULL);
                   1661:                        return (0);
                   1662: #endif
                   1663:                default:
                   1664:                        break;
                   1665:                }
                   1666:        }
                   1667:
                   1668:        /* Process compose sequence and dead accents */
                   1669:        res = KS_voidSymbol;
                   1670:
                   1671:        switch (KS_GROUP(ksym)) {
                   1672:        case KS_GROUP_Ascii:
                   1673:        case KS_GROUP_Keypad:
                   1674:        case KS_GROUP_Function:
                   1675:                res = ksym;
                   1676:                break;
                   1677:
                   1678:        case KS_GROUP_Mod:
                   1679:                if (ksym == KS_Multi_key) {
                   1680:                        update_modifier(id, 1, 0, MOD_COMPOSE);
                   1681:                        id->t_composelen = 2;
                   1682:                }
                   1683:                break;
                   1684:
                   1685:        case KS_GROUP_Dead:
                   1686:                if (id->t_composelen == 0) {
                   1687:                        update_modifier(id, 1, 0, MOD_COMPOSE);
                   1688:                        id->t_composelen = 1;
                   1689:                        id->t_composebuf[0] = ksym;
                   1690:                } else
                   1691:                        res = ksym;
                   1692:                break;
                   1693:        }
                   1694:
                   1695:        if (res == KS_voidSymbol) {
                   1696:                update_leds(id);
                   1697:                return (0);
                   1698:        }
                   1699:
                   1700:        if (id->t_composelen > 0) {
                   1701:                /*
                   1702:                 * If the compose key also serves as AltGr (i.e. set to both
                   1703:                 * KS_Multi_key and KS_Mode_switch), and would provide a valid,
                   1704:                 * distinct combination as AltGr, leave compose mode.
                   1705:                 */
                   1706:                if (id->t_composelen == 2 && group == &kp->group2[0]) {
                   1707:                        if (kp->group1[gindex] != kp->group2[gindex])
                   1708:                                id->t_composelen = 0;
                   1709:                }
                   1710:
                   1711:                if (id->t_composelen != 0) {
                   1712:                        id->t_composebuf[2 - id->t_composelen] = res;
                   1713:                        if (--id->t_composelen == 0) {
                   1714:                                res = wskbd_compose_value(id->t_composebuf);
                   1715:                                update_modifier(id, 0, 0, MOD_COMPOSE);
                   1716:                        } else {
                   1717:                                return (0);
                   1718:                        }
                   1719:                }
                   1720:        }
                   1721:
                   1722:        update_leds(id);
                   1723:
                   1724:        /* We are done, return the symbol */
                   1725:        if (KS_GROUP(res) == KS_GROUP_Ascii) {
                   1726:                if (MOD_ONESET(id, MOD_ANYCONTROL)) {
                   1727:                        if ((res >= KS_at && res <= KS_z) || res == KS_space)
                   1728:                                res = res & 0x1f;
                   1729:                        else if (res == KS_2)
                   1730:                                res = 0x00;
                   1731:                        else if (res >= KS_3 && res <= KS_7)
                   1732:                                res = KS_Escape + (res - KS_3);
                   1733:                        else if (res == KS_8)
                   1734:                                res = KS_Delete;
                   1735:                }
                   1736:                if (MOD_ONESET(id, MOD_ANYMETA)) {
                   1737:                        if (id->t_flags & WSKFL_METAESC) {
                   1738:                                id->t_symbols[0] = KS_Escape;
                   1739:                                id->t_symbols[1] = res;
                   1740:                                return (2);
                   1741:                        } else
                   1742:                                res |= 0x80;
                   1743:                }
                   1744:        }
                   1745:
                   1746:        id->t_symbols[0] = res;
                   1747:        return (1);
                   1748: }

CVSweb