root/dev/wscons/wskbd.c

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

DEFINITIONS

This source file includes following definitions.
  1. wskbd_update_layout
  2. wskbddevprint
  3. wskbd_match
  4. wskbd_attach
  5. wskbd_cnattach
  6. wskbd_cndetach
  7. wskbd_repeat
  8. wskbd_activate
  9. wskbd_detach
  10. wskbd_input
  11. wskbd_deliver_event
  12. wskbd_rawinput
  13. wskbd_holdscreen
  14. wskbd_enable
  15. wskbd_mux_open
  16. wskbdopen
  17. wskbd_do_open
  18. wskbdclose
  19. wskbd_mux_close
  20. wskbdread
  21. wskbdioctl
  22. wskbd_do_ioctl
  23. wskbd_do_ioctl_sc
  24. wskbd_displayioctl
  25. wskbdpoll
  26. wskbd_pickfree
  27. wskbd_set_console_display
  28. wskbd_set_display
  29. wskbd_add_mux
  30. wskbd_cngetc
  31. wskbd_cnpollc
  32. wskbd_cnbell
  33. update_leds
  34. update_modifier
  35. change_displayparam
  36. internal_command
  37. wskbd_translate

    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 }

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