The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/wscons/wskbd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c5327ec8527d55bf9859f280e0220947


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.