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/kbdmux/kbdmux.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 /*
    2  * kbdmux.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
    7  * All rights reserved.
    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  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  *
   30  * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
   31  * $FreeBSD$
   32  */
   33 
   34 #include "opt_compat.h"
   35 #include "opt_kbd.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/bus.h>
   39 #include <sys/conf.h>
   40 #include <sys/consio.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/kbio.h>
   43 #include <sys/kernel.h>
   44 #include <sys/limits.h>
   45 #include <sys/lock.h>
   46 #include <sys/malloc.h>
   47 #include <sys/module.h>
   48 #include <sys/mutex.h>
   49 #include <sys/poll.h>
   50 #include <sys/proc.h>
   51 #include <sys/queue.h>
   52 #include <sys/selinfo.h>
   53 #include <sys/systm.h>
   54 #include <sys/taskqueue.h>
   55 #include <sys/tty.h>
   56 #include <sys/uio.h>
   57 #include <dev/kbd/kbdreg.h>
   58 #include <dev/kbd/kbdtables.h>
   59 
   60 #define KEYBOARD_NAME   "kbdmux"
   61 
   62 MALLOC_DECLARE(M_KBDMUX);
   63 MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
   64 
   65 /*****************************************************************************
   66  *****************************************************************************
   67  **                             Keyboard state
   68  *****************************************************************************
   69  *****************************************************************************/
   70 
   71 #define KBDMUX_Q_SIZE   512     /* input queue size */
   72 
   73 /*
   74  * XXX
   75  * For now rely on Giant mutex to protect our data structures.
   76  * Just like the rest of keyboard drivers and syscons(4) do.
   77  * Note that callout is initialized as not MP-safe to make sure
   78  * Giant is held.
   79  */
   80 
   81 #if 0 /* not yet */
   82 #define KBDMUX_LOCK_DECL_GLOBAL \
   83         struct mtx ks_lock
   84 #define KBDMUX_LOCK_INIT(s) \
   85         mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
   86 #define KBDMUX_LOCK_DESTROY(s) \
   87         mtx_destroy(&(s)->ks_lock)
   88 #define KBDMUX_LOCK(s) \
   89         mtx_lock(&(s)->ks_lock)
   90 #define KBDMUX_UNLOCK(s) \
   91         mtx_unlock(&(s)->ks_lock)
   92 #define KBDMUX_LOCK_ASSERT(s, w) \
   93         mtx_assert(&(s)->ks_lock, (w))
   94 #define KBDMUX_SLEEP(s, f, d, t) \
   95         msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
   96 #define KBDMUX_CALLOUT_INIT(s) \
   97         callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
   98 #define KBDMUX_QUEUE_INTR(s) \
   99         taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
  100 #else
  101 #define KBDMUX_LOCK_DECL_GLOBAL
  102 
  103 #define KBDMUX_LOCK_INIT(s)
  104 
  105 #define KBDMUX_LOCK_DESTROY(s)
  106 
  107 #define KBDMUX_LOCK(s)
  108 
  109 #define KBDMUX_UNLOCK(s)
  110 
  111 #define KBDMUX_LOCK_ASSERT(s, w)
  112 
  113 #define KBDMUX_SLEEP(s, f, d, t) \
  114         tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
  115 #define KBDMUX_CALLOUT_INIT(s) \
  116         callout_init(&(s)->ks_timo, 0)
  117 #define KBDMUX_QUEUE_INTR(s) \
  118         taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
  119 #endif /* not yet */
  120 
  121 #define KBDMUX_INTR(kbd, arg) \
  122         (*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg))
  123 
  124 #define KBDMUX_IOCTL(kbd, cmd, arg) \
  125         (*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (caddr_t) (arg))
  126 
  127 #define KBDMUX_CHECK_CHAR(kbd) \
  128         (*kbdsw[(kbd)->kb_index]->check_char)((kbd))
  129 
  130 #define KBDMUX_READ_CHAR(kbd, wait) \
  131         (*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait))
  132 
  133 #define KBDMUX_ENABLE(kbd) \
  134         (*kbdsw[(kbd)->kb_index]->enable)((kbd))
  135 
  136 #define KBDMUX_POLL(kbd, on) \
  137         (*kbdsw[(kbd)->kb_index]->poll)((kbd), (on))
  138 
  139 #define KBDMUX_CLEAR_STATE(kbd) \
  140         (*kbdsw[(kbd)->kb_index]->clear_state)((kbd))
  141 
  142 /*
  143  * kbdmux keyboard
  144  */
  145 struct kbdmux_kbd
  146 {
  147         keyboard_t              *kbd;   /* keyboard */
  148         SLIST_ENTRY(kbdmux_kbd)  next;  /* link to next */
  149 };
  150 
  151 typedef struct kbdmux_kbd       kbdmux_kbd_t;
  152 
  153 /*
  154  * kbdmux state
  155  */
  156 struct kbdmux_state
  157 {
  158         struct clist             ks_inq;        /* input chars queue */
  159         struct task              ks_task;       /* interrupt task */
  160         struct callout           ks_timo;       /* timeout handler */
  161 #define TICKS                   (hz)            /* rate */
  162 
  163         int                      ks_flags;      /* flags */
  164 #define COMPOSE                 (1 << 0)        /* compose char flag */ 
  165 #define POLLING                 (1 << 1)        /* polling */
  166 #define TASK                    (1 << 2)        /* interrupt task queued */
  167 
  168         int                      ks_mode;       /* K_XLATE, K_RAW, K_CODE */
  169         int                      ks_state;      /* state */
  170         int                      ks_accents;    /* accent key index (> 0) */
  171         u_int                    ks_composed_char; /* composed char code */
  172         u_char                   ks_prefix;     /* AT scan code prefix */
  173 
  174         SLIST_HEAD(, kbdmux_kbd) ks_kbds;       /* keyboards */
  175 
  176         KBDMUX_LOCK_DECL_GLOBAL;
  177 };
  178 
  179 typedef struct kbdmux_state     kbdmux_state_t;
  180 
  181 /*****************************************************************************
  182  *****************************************************************************
  183  **                             Helper functions
  184  *****************************************************************************
  185  *****************************************************************************/
  186 
  187 static task_fn_t                kbdmux_kbd_intr;
  188 static timeout_t                kbdmux_kbd_intr_timo;
  189 static kbd_callback_func_t      kbdmux_kbd_event;
  190 
  191 /*
  192  * Interrupt handler task
  193  */
  194 void
  195 kbdmux_kbd_intr(void *xkbd, int pending)
  196 {
  197         keyboard_t      *kbd = (keyboard_t *) xkbd;
  198         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  199 
  200         KBDMUX_INTR(kbd, NULL);
  201 
  202         KBDMUX_LOCK(state);
  203 
  204         state->ks_flags &= ~TASK;
  205         wakeup(&state->ks_task);
  206 
  207         KBDMUX_UNLOCK(state);
  208 }
  209 
  210 /*
  211  * Schedule interrupt handler on timeout. Called with locked state.
  212  */
  213 void
  214 kbdmux_kbd_intr_timo(void *xstate)
  215 {
  216         kbdmux_state_t  *state = (kbdmux_state_t *) xstate;
  217 
  218         KBDMUX_LOCK_ASSERT(state, MA_OWNED);
  219 
  220         if (callout_pending(&state->ks_timo))
  221                 return; /* callout was reset */
  222 
  223         if (!callout_active(&state->ks_timo))
  224                 return; /* callout was stopped */
  225 
  226         callout_deactivate(&state->ks_timo);
  227 
  228         /* queue interrupt task if needed */
  229         if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
  230             KBDMUX_QUEUE_INTR(state) == 0)
  231                 state->ks_flags |= TASK;
  232 
  233         /* re-schedule timeout */
  234         callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
  235 }
  236 
  237 /*
  238  * Process event from one of our keyboards
  239  */
  240 static int
  241 kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
  242 {
  243         kbdmux_state_t  *state = (kbdmux_state_t *) arg;
  244 
  245         switch (event) {
  246         case KBDIO_KEYINPUT: {
  247                 int     c;
  248 
  249                 KBDMUX_LOCK(state);
  250 
  251                 /*
  252                  * Read all chars from the keyboard
  253                  *
  254                  * Turns out that atkbd(4) check_char() method may return
  255                  * "true" while read_char() method returns NOKEY. If this
  256                  * happens we could stuck in the loop below. Avoid this
  257                  * by breaking out of the loop if read_char() method returns
  258                  * NOKEY.
  259                  */
  260 
  261                 while (KBDMUX_CHECK_CHAR(kbd)) {
  262                         c = KBDMUX_READ_CHAR(kbd, 0);
  263                         if (c == NOKEY)
  264                                 break;
  265                         if (c == ERRKEY)
  266                                 continue; /* XXX ring bell */
  267                         if (!KBD_IS_BUSY(kbd))
  268                                 continue; /* not open - discard the input */
  269 
  270                         putc(c, &state->ks_inq);
  271                 }
  272 
  273                 /* queue interrupt task if needed */
  274                 if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) &&
  275                     KBDMUX_QUEUE_INTR(state) == 0)
  276                         state->ks_flags |= TASK;
  277 
  278                 KBDMUX_UNLOCK(state);
  279                 } break;
  280 
  281         case KBDIO_UNLOADING: {
  282                 kbdmux_kbd_t    *k;
  283 
  284                 KBDMUX_LOCK(state);
  285 
  286                 SLIST_FOREACH(k, &state->ks_kbds, next)
  287                         if (k->kbd == kbd)
  288                                 break;
  289 
  290                 if (k != NULL) {
  291                         kbd_release(k->kbd, &k->kbd);
  292                         SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
  293 
  294                         k->kbd = NULL;
  295 
  296                         free(k, M_KBDMUX);
  297                 }
  298 
  299                 KBDMUX_UNLOCK(state);
  300                 } break;
  301 
  302         default:
  303                 return (EINVAL);
  304                 /* NOT REACHED */
  305         }
  306 
  307         return (0);
  308 }
  309 
  310 /****************************************************************************
  311  ****************************************************************************
  312  **                              Keyboard driver
  313  ****************************************************************************
  314  ****************************************************************************/
  315 
  316 static int              kbdmux_configure(int flags);
  317 static kbd_probe_t      kbdmux_probe;
  318 static kbd_init_t       kbdmux_init;
  319 static kbd_term_t       kbdmux_term;
  320 static kbd_intr_t       kbdmux_intr;
  321 static kbd_test_if_t    kbdmux_test_if;
  322 static kbd_enable_t     kbdmux_enable;
  323 static kbd_disable_t    kbdmux_disable;
  324 static kbd_read_t       kbdmux_read;
  325 static kbd_check_t      kbdmux_check;
  326 static kbd_read_char_t  kbdmux_read_char;
  327 static kbd_check_char_t kbdmux_check_char;
  328 static kbd_ioctl_t      kbdmux_ioctl;
  329 static kbd_lock_t       kbdmux_lock;
  330 static void             kbdmux_clear_state_locked(kbdmux_state_t *state);
  331 static kbd_clear_state_t kbdmux_clear_state;
  332 static kbd_get_state_t  kbdmux_get_state;
  333 static kbd_set_state_t  kbdmux_set_state;
  334 static kbd_poll_mode_t  kbdmux_poll;
  335 
  336 static keyboard_switch_t kbdmuxsw = {
  337         .probe =        kbdmux_probe,
  338         .init =         kbdmux_init,
  339         .term =         kbdmux_term,
  340         .intr =         kbdmux_intr,
  341         .test_if =      kbdmux_test_if,
  342         .enable =       kbdmux_enable,
  343         .disable =      kbdmux_disable,
  344         .read =         kbdmux_read,
  345         .check =        kbdmux_check,
  346         .read_char =    kbdmux_read_char,
  347         .check_char =   kbdmux_check_char,
  348         .ioctl =        kbdmux_ioctl,
  349         .lock =         kbdmux_lock,
  350         .clear_state =  kbdmux_clear_state,
  351         .get_state =    kbdmux_get_state,
  352         .set_state =    kbdmux_set_state,
  353         .get_fkeystr =  genkbd_get_fkeystr,
  354         .poll =         kbdmux_poll,
  355         .diag =         genkbd_diag,
  356 };
  357 
  358 /*
  359  * Return the number of found keyboards
  360  */
  361 static int
  362 kbdmux_configure(int flags)
  363 {
  364         return (1);
  365 }
  366 
  367 /*
  368  * Detect a keyboard
  369  */
  370 static int
  371 kbdmux_probe(int unit, void *arg, int flags)
  372 {
  373         if (resource_disabled(KEYBOARD_NAME, unit))
  374                 return (ENXIO);
  375 
  376         return (0);
  377 }
  378 
  379 /*
  380  * Reset and initialize the keyboard (stolen from atkbd.c)
  381  */
  382 static int
  383 kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
  384 {
  385         keyboard_t      *kbd = NULL;
  386         kbdmux_state_t  *state = NULL;
  387         keymap_t        *keymap = NULL;
  388         accentmap_t     *accmap = NULL;
  389         fkeytab_t       *fkeymap = NULL;
  390         int              error, needfree, fkeymap_size, delay[2];
  391 
  392         if (*kbdp == NULL) {
  393                 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
  394                 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
  395                 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
  396                 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
  397                 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
  398                 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
  399                 needfree = 1;
  400 
  401                 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
  402                     (accmap == NULL) || (fkeymap == NULL)) {
  403                         error = ENOMEM;
  404                         goto bad;
  405                 }
  406 
  407                 KBDMUX_LOCK_INIT(state);
  408                 clist_alloc_cblocks(&state->ks_inq,
  409                                 KBDMUX_Q_SIZE, KBDMUX_Q_SIZE / 2);
  410                 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
  411                 KBDMUX_CALLOUT_INIT(state);
  412                 SLIST_INIT(&state->ks_kbds);
  413         } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
  414                 return (0);
  415         } else {
  416                 kbd = *kbdp;
  417                 state = (kbdmux_state_t *) kbd->kb_data;
  418                 keymap = kbd->kb_keymap;
  419                 accmap = kbd->kb_accentmap;
  420                 fkeymap = kbd->kb_fkeytab;
  421                 fkeymap_size = kbd->kb_fkeytab_size;
  422                 needfree = 0;
  423         }
  424 
  425         if (!KBD_IS_PROBED(kbd)) {
  426                 /* XXX assume 101/102 keys keyboard */
  427                 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
  428                 bcopy(&key_map, keymap, sizeof(key_map));
  429                 bcopy(&accent_map, accmap, sizeof(accent_map));
  430                 bcopy(fkey_tab, fkeymap,
  431                         imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
  432                 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
  433                 kbd->kb_data = (void *)state;
  434         
  435                 KBD_FOUND_DEVICE(kbd);
  436                 KBD_PROBE_DONE(kbd);
  437 
  438                 KBDMUX_LOCK(state);
  439                 kbdmux_clear_state_locked(state);
  440                 state->ks_mode = K_XLATE;
  441                 KBDMUX_UNLOCK(state);
  442         }
  443 
  444         if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
  445                 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
  446 
  447                 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
  448 
  449                 delay[0] = kbd->kb_delay1;
  450                 delay[1] = kbd->kb_delay2;
  451                 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
  452 
  453                 KBD_INIT_DONE(kbd);
  454         }
  455 
  456         if (!KBD_IS_CONFIGURED(kbd)) {
  457                 if (kbd_register(kbd) < 0) {
  458                         error = ENXIO;
  459                         goto bad;
  460                 }
  461 
  462                 KBD_CONFIG_DONE(kbd);
  463 
  464                 KBDMUX_LOCK(state);
  465                 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
  466                 KBDMUX_UNLOCK(state);
  467         }
  468 
  469         return (0);
  470 bad:
  471         if (needfree) {
  472                 if (state != NULL) {
  473                         clist_free_cblocks(&state->ks_inq);
  474                         free(state, M_KBDMUX);
  475                 }
  476                 if (keymap != NULL)
  477                         free(keymap, M_KBDMUX);
  478                 if (accmap != NULL)
  479                         free(accmap, M_KBDMUX);
  480                 if (fkeymap != NULL)
  481                         free(fkeymap, M_KBDMUX);
  482                 if (kbd != NULL) {
  483                         free(kbd, M_KBDMUX);
  484                         *kbdp = NULL;   /* insure ref doesn't leak to caller */
  485                 }
  486         }
  487 
  488         return (error);
  489 }
  490 
  491 /*
  492  * Finish using this keyboard
  493  */
  494 static int
  495 kbdmux_term(keyboard_t *kbd)
  496 {
  497         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  498         kbdmux_kbd_t    *k;
  499 
  500         KBDMUX_LOCK(state);
  501 
  502         /* kill callout */
  503         callout_stop(&state->ks_timo);
  504 
  505         /* wait for interrupt task */
  506         while (state->ks_flags & TASK)
  507                 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
  508 
  509         /* release all keyboards from the mux */
  510         while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
  511                 kbd_release(k->kbd, &k->kbd);
  512                 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
  513 
  514                 k->kbd = NULL;
  515 
  516                 free(k, M_KBDMUX);
  517         }
  518 
  519         /* flush input queue */
  520         ndflush(&state->ks_inq, state->ks_inq.c_cc);
  521         clist_free_cblocks(&state->ks_inq);
  522 
  523         KBDMUX_UNLOCK(state);
  524 
  525         kbd_unregister(kbd);
  526 
  527         KBDMUX_LOCK_DESTROY(state);
  528         bzero(state, sizeof(*state));
  529         free(state, M_KBDMUX);
  530 
  531         free(kbd->kb_keymap, M_KBDMUX);
  532         free(kbd->kb_accentmap, M_KBDMUX);
  533         free(kbd->kb_fkeytab, M_KBDMUX);
  534         free(kbd, M_KBDMUX);
  535 
  536         return (0);
  537 }
  538 
  539 /*
  540  * Keyboard interrupt routine
  541  */
  542 static int
  543 kbdmux_intr(keyboard_t *kbd, void *arg)
  544 {
  545         int     c;
  546 
  547         if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
  548                 /* let the callback function to process the input */
  549                 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
  550                                             kbd->kb_callback.kc_arg);
  551         } else {
  552                 /* read and discard the input; no one is waiting for input */
  553                 do {
  554                         c = kbdmux_read_char(kbd, FALSE);
  555                 } while (c != NOKEY);
  556         }
  557 
  558         return (0);
  559 }
  560 
  561 /*
  562  * Test the interface to the device
  563  */
  564 static int
  565 kbdmux_test_if(keyboard_t *kbd)
  566 {
  567         return (0);
  568 }
  569 
  570 /* 
  571  * Enable the access to the device; until this function is called,
  572  * the client cannot read from the keyboard.
  573  */
  574 static int
  575 kbdmux_enable(keyboard_t *kbd)
  576 {
  577         KBD_ACTIVATE(kbd);
  578         return (0);
  579 }
  580 
  581 /*
  582  * Disallow the access to the device
  583  */
  584 static int
  585 kbdmux_disable(keyboard_t *kbd)
  586 {
  587         KBD_DEACTIVATE(kbd);
  588         return (0);
  589 }
  590 
  591 /*
  592  * Read one byte from the keyboard if it's allowed
  593  */
  594 static int
  595 kbdmux_read(keyboard_t *kbd, int wait)
  596 {
  597         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  598         int              c;
  599 
  600         KBDMUX_LOCK(state);
  601         c = getc(&state->ks_inq);
  602         KBDMUX_UNLOCK(state);
  603 
  604         if (c != -1)
  605                 kbd->kb_count ++;
  606 
  607         return (KBD_IS_ACTIVE(kbd)? c : -1);
  608 }
  609 
  610 /*
  611  * Check if data is waiting
  612  */
  613 static int
  614 kbdmux_check(keyboard_t *kbd)
  615 {
  616         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  617         int              ready;
  618 
  619         if (!KBD_IS_ACTIVE(kbd))
  620                 return (FALSE);
  621 
  622         KBDMUX_LOCK(state);
  623         ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
  624         KBDMUX_UNLOCK(state);
  625 
  626         return (ready);
  627 }
  628 
  629 /*
  630  * Read char from the keyboard (stolen from atkbd.c)
  631  */
  632 static u_int
  633 kbdmux_read_char(keyboard_t *kbd, int wait)
  634 {
  635         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  636         u_int            action;
  637         int              scancode, keycode;
  638 
  639         KBDMUX_LOCK(state);
  640 
  641 next_code:
  642 
  643         /* do we have a composed char to return? */
  644         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
  645                 action = state->ks_composed_char;
  646                 state->ks_composed_char = 0;
  647                 if (action > UCHAR_MAX) {
  648                         KBDMUX_UNLOCK(state);
  649 
  650                         return (ERRKEY);
  651                 }
  652 
  653                 KBDMUX_UNLOCK(state);
  654 
  655                 return (action);
  656         }
  657 
  658         /* see if there is something in the keyboard queue */
  659         scancode = getc(&state->ks_inq);
  660         if (scancode == -1) {
  661                 if (state->ks_flags & POLLING) {
  662                         kbdmux_kbd_t    *k;
  663 
  664                         SLIST_FOREACH(k, &state->ks_kbds, next) {
  665                                 while (KBDMUX_CHECK_CHAR(k->kbd)) {
  666                                         scancode = KBDMUX_READ_CHAR(k->kbd, 0);
  667                                         if (scancode == NOKEY)
  668                                                 break;
  669                                         if (scancode == ERRKEY)
  670                                                 continue;
  671                                         if (!KBD_IS_BUSY(k->kbd))
  672                                                 continue; 
  673 
  674                                         putc(scancode, &state->ks_inq);
  675                                 }
  676                         }
  677 
  678                         if (state->ks_inq.c_cc > 0)
  679                                 goto next_code;
  680                 }
  681 
  682                 KBDMUX_UNLOCK(state);
  683                 return (NOKEY);
  684         }
  685         /* XXX FIXME: check for -1 if wait == 1! */
  686 
  687         kbd->kb_count ++;
  688 
  689         /* return the byte as is for the K_RAW mode */
  690         if (state->ks_mode == K_RAW) {
  691                 KBDMUX_UNLOCK(state);
  692                 return (scancode);
  693         }
  694 
  695         /* translate the scan code into a keycode */
  696         keycode = scancode & 0x7F;
  697         switch (state->ks_prefix) {
  698         case 0x00:      /* normal scancode */
  699                 switch(scancode) {
  700                 case 0xB8:      /* left alt (compose key) released */
  701                         if (state->ks_flags & COMPOSE) {
  702                                 state->ks_flags &= ~COMPOSE;
  703                                 if (state->ks_composed_char > UCHAR_MAX)
  704                                         state->ks_composed_char = 0;
  705                         }
  706                         break;
  707                 case 0x38:      /* left alt (compose key) pressed */
  708                         if (!(state->ks_flags & COMPOSE)) {
  709                                 state->ks_flags |= COMPOSE;
  710                                 state->ks_composed_char = 0;
  711                         }
  712                         break;
  713                 case 0xE0:
  714                 case 0xE1:
  715                         state->ks_prefix = scancode;
  716                         goto next_code;
  717                 }
  718                 break;
  719         case 0xE0:      /* 0xE0 prefix */
  720                 state->ks_prefix = 0;
  721                 switch (keycode) {
  722                 case 0x1C:      /* right enter key */
  723                         keycode = 0x59;
  724                         break;
  725                 case 0x1D:      /* right ctrl key */
  726                         keycode = 0x5A;
  727                         break;
  728                 case 0x35:      /* keypad divide key */
  729                         keycode = 0x5B;
  730                         break;
  731                 case 0x37:      /* print scrn key */
  732                         keycode = 0x5C;
  733                         break;
  734                 case 0x38:      /* right alt key (alt gr) */
  735                         keycode = 0x5D;
  736                         break;
  737                 case 0x46:      /* ctrl-pause/break on AT 101 (see below) */
  738                         keycode = 0x68;
  739                         break;
  740                 case 0x47:      /* grey home key */
  741                         keycode = 0x5E;
  742                         break;
  743                 case 0x48:      /* grey up arrow key */
  744                         keycode = 0x5F;
  745                         break;
  746                 case 0x49:      /* grey page up key */
  747                         keycode = 0x60;
  748                         break;
  749                 case 0x4B:      /* grey left arrow key */
  750                         keycode = 0x61;
  751                         break;
  752                 case 0x4D:      /* grey right arrow key */
  753                         keycode = 0x62;
  754                         break;
  755                 case 0x4F:      /* grey end key */
  756                         keycode = 0x63;
  757                         break;
  758                 case 0x50:      /* grey down arrow key */
  759                         keycode = 0x64;
  760                         break;
  761                 case 0x51:      /* grey page down key */
  762                         keycode = 0x65;
  763                         break;
  764                 case 0x52:      /* grey insert key */
  765                         keycode = 0x66;
  766                         break;
  767                 case 0x53:      /* grey delete key */
  768                         keycode = 0x67;
  769                         break;
  770                 /* the following 3 are only used on the MS "Natural" keyboard */
  771                 case 0x5b:      /* left Window key */
  772                         keycode = 0x69;
  773                         break;
  774                 case 0x5c:      /* right Window key */
  775                         keycode = 0x6a;
  776                         break;
  777                 case 0x5d:      /* menu key */
  778                         keycode = 0x6b;
  779                         break;
  780                 case 0x5e:      /* power key */
  781                         keycode = 0x6d;
  782                         break;
  783                 case 0x5f:      /* sleep key */
  784                         keycode = 0x6e;
  785                         break;
  786                 case 0x63:      /* wake key */
  787                         keycode = 0x6f;
  788                         break;
  789                 case 0x64:      /* [JP106USB] backslash, underscore */
  790                         keycode = 0x73;
  791                         break;
  792                 default:        /* ignore everything else */
  793                         goto next_code;
  794                 }
  795                 break;
  796         case 0xE1:      /* 0xE1 prefix */
  797                 /* 
  798                  * The pause/break key on the 101 keyboard produces:
  799                  * E1-1D-45 E1-9D-C5
  800                  * Ctrl-pause/break produces:
  801                  * E0-46 E0-C6 (See above.)
  802                  */
  803                 state->ks_prefix = 0;
  804                 if (keycode == 0x1D)
  805                         state->ks_prefix = 0x1D;
  806                 goto next_code;
  807                 /* NOT REACHED */
  808         case 0x1D:      /* pause / break */
  809                 state->ks_prefix = 0;
  810                 if (keycode != 0x45)
  811                         goto next_code;
  812                 keycode = 0x68;
  813                 break;
  814         }
  815 
  816         /* XXX assume 101/102 keys AT keyboard */
  817         switch (keycode) {
  818         case 0x5c:      /* print screen */
  819                 if (state->ks_flags & ALTS)
  820                         keycode = 0x54; /* sysrq */
  821                 break;
  822         case 0x68:      /* pause/break */
  823                 if (state->ks_flags & CTLS)
  824                         keycode = 0x6c; /* break */
  825                 break;
  826         }
  827 
  828         /* return the key code in the K_CODE mode */
  829         if (state->ks_mode == K_CODE) {
  830                 KBDMUX_UNLOCK(state);
  831                 return (keycode | (scancode & 0x80));
  832         }
  833 
  834         /* compose a character code */
  835         if (state->ks_flags & COMPOSE) {
  836                 switch (keycode | (scancode & 0x80)) {
  837                 /* key pressed, process it */
  838                 case 0x47: case 0x48: case 0x49:        /* keypad 7,8,9 */
  839                         state->ks_composed_char *= 10;
  840                         state->ks_composed_char += keycode - 0x40;
  841                         if (state->ks_composed_char > UCHAR_MAX) {
  842                                 KBDMUX_UNLOCK(state);
  843                                 return (ERRKEY);
  844                         }
  845                         goto next_code;
  846                 case 0x4B: case 0x4C: case 0x4D:        /* keypad 4,5,6 */
  847                         state->ks_composed_char *= 10;
  848                         state->ks_composed_char += keycode - 0x47;
  849                         if (state->ks_composed_char > UCHAR_MAX) {
  850                                 KBDMUX_UNLOCK(state);
  851                                 return (ERRKEY);
  852                         }
  853                         goto next_code;
  854                 case 0x4F: case 0x50: case 0x51:        /* keypad 1,2,3 */
  855                         state->ks_composed_char *= 10;
  856                         state->ks_composed_char += keycode - 0x4E;
  857                         if (state->ks_composed_char > UCHAR_MAX) {
  858                                 KBDMUX_UNLOCK(state);
  859                                 return (ERRKEY);
  860                         }
  861                         goto next_code;
  862                 case 0x52:      /* keypad 0 */
  863                         state->ks_composed_char *= 10;
  864                         if (state->ks_composed_char > UCHAR_MAX) {
  865                                 KBDMUX_UNLOCK(state);
  866                                 return (ERRKEY);
  867                         }
  868                         goto next_code;
  869 
  870                 /* key released, no interest here */
  871                 case 0xC7: case 0xC8: case 0xC9:        /* keypad 7,8,9 */
  872                 case 0xCB: case 0xCC: case 0xCD:        /* keypad 4,5,6 */
  873                 case 0xCF: case 0xD0: case 0xD1:        /* keypad 1,2,3 */
  874                 case 0xD2:                              /* keypad 0 */
  875                         goto next_code;
  876 
  877                 case 0x38:                              /* left alt key */
  878                         break;
  879 
  880                 default:
  881                         if (state->ks_composed_char > 0) {
  882                                 state->ks_flags &= ~COMPOSE;
  883                                 state->ks_composed_char = 0;
  884                                 KBDMUX_UNLOCK(state);
  885                                 return (ERRKEY);
  886                         }
  887                         break;
  888                 }
  889         }
  890 
  891         /* keycode to key action */
  892         action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
  893                         &state->ks_state, &state->ks_accents);
  894         if (action == NOKEY)
  895                 goto next_code;
  896 
  897         KBDMUX_UNLOCK(state);
  898 
  899         return (action);
  900 }
  901 
  902 /*
  903  * Check if char is waiting
  904  */
  905 static int
  906 kbdmux_check_char(keyboard_t *kbd)
  907 {
  908         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  909         int              ready;
  910 
  911         if (!KBD_IS_ACTIVE(kbd))
  912                 return (FALSE);
  913 
  914         KBDMUX_LOCK(state);
  915 
  916         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
  917                 ready = TRUE;
  918         else
  919                 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE;
  920 
  921         KBDMUX_UNLOCK(state);
  922 
  923         return (ready);
  924 }
  925 
  926 /*
  927  * Keyboard ioctl's
  928  */
  929 static int
  930 kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
  931 {
  932         static int       delays[] = {
  933                 250, 500, 750, 1000
  934         };
  935 
  936         static int       rates[]  =  {
  937                 34,  38,  42,  46,  50,   55,  59,  63,
  938                 68,  76,  84,  92,  100, 110, 118, 126,
  939                 136, 152, 168, 184, 200, 220, 236, 252,
  940                 272, 304, 336, 368, 400, 440, 472, 504
  941         };
  942 
  943         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  944         kbdmux_kbd_t    *k;
  945         keyboard_info_t *ki;
  946         int              error = 0, mode;
  947 #ifdef COMPAT_FREEBSD6
  948         int              ival;
  949 #endif
  950 
  951         if (state == NULL)
  952                 return (ENXIO);
  953 
  954         switch (cmd) {
  955         case KBADDKBD: /* add keyboard to the mux */
  956                 ki = (keyboard_info_t *) arg;
  957 
  958                 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
  959                     strcmp(ki->kb_name, "*") == 0)
  960                         return (EINVAL); /* bad input */
  961 
  962                 KBDMUX_LOCK(state);
  963 
  964                 SLIST_FOREACH(k, &state->ks_kbds, next)
  965                         if (k->kbd->kb_unit == ki->kb_unit &&
  966                             strcmp(k->kbd->kb_name, ki->kb_name) == 0)
  967                                 break;
  968 
  969                 if (k != NULL) {
  970                         KBDMUX_UNLOCK(state);
  971 
  972                         return (0); /* keyboard already in the mux */
  973                 }
  974 
  975                 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
  976                 if (k == NULL) {
  977                         KBDMUX_UNLOCK(state);
  978 
  979                         return (ENOMEM); /* out of memory */
  980                 }
  981 
  982                 k->kbd = kbd_get_keyboard(
  983                                 kbd_allocate(
  984                                         ki->kb_name,
  985                                         ki->kb_unit,
  986                                         (void *) &k->kbd,
  987                                         kbdmux_kbd_event, (void *) state));
  988                 if (k->kbd == NULL) {
  989                         KBDMUX_UNLOCK(state);
  990                         free(k, M_KBDMUX);
  991 
  992                         return (EINVAL); /* bad keyboard */
  993                 }
  994 
  995                 KBDMUX_ENABLE(k->kbd);
  996                 KBDMUX_CLEAR_STATE(k->kbd);
  997 
  998                 /* set K_RAW mode on slave keyboard */
  999                 mode = K_RAW;
 1000                 error = KBDMUX_IOCTL(k->kbd, KDSKBMODE, &mode);
 1001                 if (error == 0) {
 1002                         /* set lock keys state on slave keyboard */
 1003                         mode = state->ks_state & LOCK_MASK;
 1004                         error = KBDMUX_IOCTL(k->kbd, KDSKBSTATE, &mode);
 1005                 }
 1006 
 1007                 if (error != 0) {
 1008                         KBDMUX_UNLOCK(state);
 1009 
 1010                         kbd_release(k->kbd, &k->kbd);
 1011                         k->kbd = NULL;
 1012 
 1013                         free(k, M_KBDMUX);
 1014 
 1015                         return (error); /* could not set mode */
 1016                 }
 1017 
 1018                 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
 1019 
 1020                 KBDMUX_UNLOCK(state);
 1021                 break;
 1022 
 1023         case KBRELKBD: /* release keyboard from the mux */
 1024                 ki = (keyboard_info_t *) arg;
 1025 
 1026                 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
 1027                     strcmp(ki->kb_name, "*") == 0)
 1028                         return (EINVAL); /* bad input */
 1029 
 1030                 KBDMUX_LOCK(state);
 1031 
 1032                 SLIST_FOREACH(k, &state->ks_kbds, next)
 1033                         if (k->kbd->kb_unit == ki->kb_unit &&
 1034                             strcmp(k->kbd->kb_name, ki->kb_name) == 0)
 1035                                 break;
 1036 
 1037                 if (k != NULL) {
 1038                         error = kbd_release(k->kbd, &k->kbd);
 1039                         if (error == 0) {
 1040                                 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
 1041 
 1042                                 k->kbd = NULL;
 1043 
 1044                                 free(k, M_KBDMUX);
 1045                         }
 1046                 } else
 1047                         error = ENXIO; /* keyboard is not in the mux */
 1048 
 1049                 KBDMUX_UNLOCK(state);
 1050                 break;
 1051 
 1052         case KDGKBMODE: /* get kyboard mode */
 1053                 KBDMUX_LOCK(state);
 1054                 *(int *)arg = state->ks_mode;
 1055                 KBDMUX_UNLOCK(state);
 1056                 break;
 1057 
 1058 #ifdef COMPAT_FREEBSD6
 1059         case _IO('K', 7):
 1060                 ival = IOCPARM_IVAL(arg);
 1061                 arg = (caddr_t)&ival;
 1062                 /* FALLTHROUGH */
 1063 #endif
 1064         case KDSKBMODE: /* set keyboard mode */
 1065                 KBDMUX_LOCK(state);
 1066 
 1067                 switch (*(int *)arg) {
 1068                 case K_XLATE:
 1069                         if (state->ks_mode != K_XLATE) {
 1070                                 /* make lock key state and LED state match */
 1071                                 state->ks_state &= ~LOCK_MASK;
 1072                                 state->ks_state |= KBD_LED_VAL(kbd);
 1073                         }
 1074                         /* FALLTHROUGH */
 1075 
 1076                 case K_RAW:
 1077                 case K_CODE:
 1078                         if (state->ks_mode != *(int *)arg) {
 1079                                 kbdmux_clear_state_locked(state);
 1080                                 state->ks_mode = *(int *)arg;
 1081                         }
 1082                         break;
 1083 
 1084                 default:
 1085                         error = EINVAL;
 1086                         break;
 1087                 }
 1088 
 1089                 KBDMUX_UNLOCK(state);
 1090                 break;
 1091 
 1092         case KDGETLED: /* get keyboard LED */
 1093                 KBDMUX_LOCK(state);
 1094                 *(int *)arg = KBD_LED_VAL(kbd);
 1095                 KBDMUX_UNLOCK(state);
 1096                 break;
 1097 
 1098 #ifdef COMPAT_FREEBSD6
 1099         case _IO('K', 66):
 1100                 ival = IOCPARM_IVAL(arg);
 1101                 arg = (caddr_t)&ival;
 1102                 /* FALLTHROUGH */
 1103 #endif
 1104         case KDSETLED: /* set keyboard LED */
 1105                 KBDMUX_LOCK(state);
 1106 
 1107                 /* NOTE: lock key state in ks_state won't be changed */
 1108                 if (*(int *)arg & ~LOCK_MASK) {
 1109                         KBDMUX_UNLOCK(state);
 1110 
 1111                         return (EINVAL);
 1112                 }
 1113 
 1114                 KBD_LED_VAL(kbd) = *(int *)arg;
 1115 
 1116                 /* KDSETLED on all slave keyboards */
 1117                 SLIST_FOREACH(k, &state->ks_kbds, next)
 1118                         KBDMUX_IOCTL(k->kbd, KDSETLED, arg);
 1119 
 1120                 KBDMUX_UNLOCK(state);
 1121                 break;
 1122 
 1123         case KDGKBSTATE: /* get lock key state */
 1124                 KBDMUX_LOCK(state);
 1125                 *(int *)arg = state->ks_state & LOCK_MASK;
 1126                 KBDMUX_UNLOCK(state);
 1127                 break;
 1128 
 1129 #ifdef COMPAT_FREEBSD6
 1130         case _IO('K', 20):
 1131                 ival = IOCPARM_IVAL(arg);
 1132                 arg = (caddr_t)&ival;
 1133                 /* FALLTHROUGH */
 1134 #endif
 1135         case KDSKBSTATE: /* set lock key state */
 1136                 KBDMUX_LOCK(state);
 1137 
 1138                 if (*(int *)arg & ~LOCK_MASK) {
 1139                         KBDMUX_UNLOCK(state);
 1140 
 1141                         return (EINVAL);
 1142                 }
 1143 
 1144                 state->ks_state &= ~LOCK_MASK;
 1145                 state->ks_state |= *(int *)arg;
 1146 
 1147                 /* KDSKBSTATE on all slave keyboards */
 1148                 SLIST_FOREACH(k, &state->ks_kbds, next)
 1149                         KBDMUX_IOCTL(k->kbd, KDSKBSTATE, arg);
 1150 
 1151                 KBDMUX_UNLOCK(state);
 1152 
 1153                 return (kbdmux_ioctl(kbd, KDSETLED, arg));
 1154                 /* NOT REACHED */
 1155 
 1156 #ifdef COMPAT_FREEBSD6
 1157         case _IO('K', 67):
 1158                 cmd = KDSETRAD;
 1159                 ival = IOCPARM_IVAL(arg);
 1160                 arg = (caddr_t)&ival;
 1161                 /* FALLTHROUGH */
 1162 #endif
 1163         case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
 1164         case KDSETRAD: /* set keyboard repeat rate (old interface) */
 1165                 KBDMUX_LOCK(state);
 1166 
 1167                 if (cmd == KDSETREPEAT) {
 1168                         int     i;
 1169 
 1170                         /* lookup delay */
 1171                         for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
 1172                                 if (((int *)arg)[0] >= delays[i])
 1173                                         break;
 1174                         mode = i << 5;
 1175 
 1176                         /* lookup rate */
 1177                         for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
 1178                                 if (((int *)arg)[1] >= rates[i])
 1179                                         break;
 1180                         mode |= i;
 1181                 } else
 1182                         mode = *(int *)arg;
 1183 
 1184                 if (mode & ~0x7f) {
 1185                         KBDMUX_UNLOCK(state);
 1186 
 1187                         return (EINVAL);
 1188                 }
 1189 
 1190                 kbd->kb_delay1 = delays[(mode >> 5) & 3];
 1191                 kbd->kb_delay2 = rates[mode & 0x1f];
 1192 
 1193                 /* perform command on all slave keyboards */
 1194                 SLIST_FOREACH(k, &state->ks_kbds, next)
 1195                         KBDMUX_IOCTL(k->kbd, cmd, arg);
 1196 
 1197                 KBDMUX_UNLOCK(state);
 1198                 break;
 1199 
 1200         case PIO_KEYMAP:        /* set keyboard translation table */
 1201         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
 1202         case PIO_DEADKEYMAP:    /* set accent key translation table */
 1203                 KBDMUX_LOCK(state);
 1204                 state->ks_accents = 0;
 1205 
 1206                 /* perform command on all slave keyboards */
 1207                 SLIST_FOREACH(k, &state->ks_kbds, next)
 1208                         KBDMUX_IOCTL(k->kbd, cmd, arg);
 1209 
 1210                 KBDMUX_UNLOCK(state);
 1211                 /* FALLTHROUGH */
 1212 
 1213         default:
 1214                 error = genkbd_commonioctl(kbd, cmd, arg);
 1215                 break;
 1216         }
 1217 
 1218         return (error);
 1219 }
 1220 
 1221 /*
 1222  * Lock the access to the keyboard
 1223  */
 1224 static int
 1225 kbdmux_lock(keyboard_t *kbd, int lock)
 1226 {
 1227         return (1); /* XXX */
 1228 }
 1229 
 1230 /*
 1231  * Clear the internal state of the keyboard
 1232  */
 1233 static void
 1234 kbdmux_clear_state_locked(kbdmux_state_t *state)
 1235 {
 1236         KBDMUX_LOCK_ASSERT(state, MA_OWNED);
 1237 
 1238         state->ks_flags &= ~(COMPOSE|POLLING);
 1239         state->ks_state &= LOCK_MASK;   /* preserve locking key state */
 1240         state->ks_accents = 0;
 1241         state->ks_composed_char = 0;
 1242 /*      state->ks_prefix = 0;           XXX */
 1243 
 1244         ndflush(&state->ks_inq, state->ks_inq.c_cc);
 1245 }
 1246 
 1247 static void
 1248 kbdmux_clear_state(keyboard_t *kbd)
 1249 {
 1250         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
 1251 
 1252         KBDMUX_LOCK(state);
 1253         kbdmux_clear_state_locked(state);
 1254         KBDMUX_UNLOCK(state);
 1255 }
 1256 
 1257 /*
 1258  * Save the internal state
 1259  */
 1260 static int
 1261 kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
 1262 {
 1263         if (len == 0)
 1264                 return (sizeof(kbdmux_state_t));
 1265         if (len < sizeof(kbdmux_state_t))
 1266                 return (-1);
 1267 
 1268         bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
 1269 
 1270         return (0);
 1271 }
 1272 
 1273 /*
 1274  * Set the internal state
 1275  */
 1276 static int
 1277 kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
 1278 {
 1279         if (len < sizeof(kbdmux_state_t))
 1280                 return (ENOMEM);
 1281 
 1282         bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
 1283 
 1284         return (0);
 1285 }
 1286 
 1287 /*
 1288  * Set polling
 1289  */
 1290 static int
 1291 kbdmux_poll(keyboard_t *kbd, int on)
 1292 {
 1293         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
 1294         kbdmux_kbd_t    *k;
 1295 
 1296         KBDMUX_LOCK(state);
 1297 
 1298         if (on)
 1299                 state->ks_flags |= POLLING; 
 1300         else
 1301                 state->ks_flags &= ~POLLING;
 1302 
 1303         /* set poll on slave keyboards */
 1304         SLIST_FOREACH(k, &state->ks_kbds, next)
 1305                 KBDMUX_POLL(k->kbd, on);
 1306 
 1307         KBDMUX_UNLOCK(state);
 1308 
 1309         return (0);
 1310 }
 1311 
 1312 /*****************************************************************************
 1313  *****************************************************************************
 1314  **                                    Module 
 1315  *****************************************************************************
 1316  *****************************************************************************/
 1317 
 1318 KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
 1319 
 1320 static int
 1321 kbdmux_modevent(module_t mod, int type, void *data)
 1322 {
 1323         keyboard_switch_t       *sw;
 1324         keyboard_t              *kbd;
 1325         int                      error;
 1326 
 1327         switch (type) {
 1328         case MOD_LOAD:
 1329                 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
 1330                         break;
 1331 
 1332                 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
 1333                         kbd_delete_driver(&kbdmux_kbd_driver);
 1334                         error = ENXIO;
 1335                         break;
 1336                 }
 1337 
 1338                 kbd = NULL;
 1339 
 1340                 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
 1341                     (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
 1342                         kbd_delete_driver(&kbdmux_kbd_driver);
 1343                         break;
 1344                 }
 1345 
 1346 #ifdef KBD_INSTALL_CDEV
 1347                 if ((error = kbd_attach(kbd)) != 0) {
 1348                         (*sw->term)(kbd);
 1349                         kbd_delete_driver(&kbdmux_kbd_driver);
 1350                         break;
 1351                 }
 1352 #endif
 1353 
 1354                 if ((error = (*sw->enable)(kbd)) != 0) {
 1355                         (*sw->disable)(kbd);
 1356 #ifdef KBD_INSTALL_CDEV
 1357                         kbd_detach(kbd);
 1358 #endif
 1359                         (*sw->term)(kbd);
 1360                         kbd_delete_driver(&kbdmux_kbd_driver);
 1361                         break;
 1362                 }
 1363                 break;
 1364 
 1365         case MOD_UNLOAD:
 1366                 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
 1367                         panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
 1368 
 1369                 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
 1370                 if (kbd != NULL) {
 1371                         (*sw->disable)(kbd);
 1372 #ifdef KBD_INSTALL_CDEV
 1373                         kbd_detach(kbd);
 1374 #endif
 1375                         (*sw->term)(kbd);
 1376                         kbd_delete_driver(&kbdmux_kbd_driver);
 1377                 }
 1378                 error = 0;
 1379                 break;
 1380 
 1381         default:
 1382                 error = EOPNOTSUPP;
 1383                 break;
 1384         }
 1385 
 1386         return (error);
 1387 }
 1388 
 1389 DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
 1390 

Cache object: fe48aeb29c9e5a4cdc2783046c54e2bf


[ 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.