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: releng/8.4/sys/dev/kbdmux/kbdmux.c 193752 2009-06-08 20:24:29Z ed $
   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/uio.h>
   56 #include <dev/kbd/kbdreg.h>
   57 #include <dev/kbd/kbdtables.h>
   58 
   59 #define KEYBOARD_NAME   "kbdmux"
   60 
   61 MALLOC_DECLARE(M_KBDMUX);
   62 MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
   63 
   64 /*****************************************************************************
   65  *****************************************************************************
   66  **                             Keyboard state
   67  *****************************************************************************
   68  *****************************************************************************/
   69 
   70 #define KBDMUX_Q_SIZE   512     /* input queue size */
   71 
   72 /*
   73  * XXX
   74  * For now rely on Giant mutex to protect our data structures.
   75  * Just like the rest of keyboard drivers and syscons(4) do.
   76  * Note that callout is initialized as not MP-safe to make sure
   77  * Giant is held.
   78  */
   79 
   80 #if 0 /* not yet */
   81 #define KBDMUX_LOCK_DECL_GLOBAL \
   82         struct mtx ks_lock
   83 #define KBDMUX_LOCK_INIT(s) \
   84         mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
   85 #define KBDMUX_LOCK_DESTROY(s) \
   86         mtx_destroy(&(s)->ks_lock)
   87 #define KBDMUX_LOCK(s) \
   88         mtx_lock(&(s)->ks_lock)
   89 #define KBDMUX_UNLOCK(s) \
   90         mtx_unlock(&(s)->ks_lock)
   91 #define KBDMUX_LOCK_ASSERT(s, w) \
   92         mtx_assert(&(s)->ks_lock, (w))
   93 #define KBDMUX_SLEEP(s, f, d, t) \
   94         msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t))
   95 #define KBDMUX_CALLOUT_INIT(s) \
   96         callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0)
   97 #define KBDMUX_QUEUE_INTR(s) \
   98         taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
   99 #else
  100 #define KBDMUX_LOCK_DECL_GLOBAL
  101 
  102 #define KBDMUX_LOCK_INIT(s)
  103 
  104 #define KBDMUX_LOCK_DESTROY(s)
  105 
  106 #define KBDMUX_LOCK(s)
  107 
  108 #define KBDMUX_UNLOCK(s)
  109 
  110 #define KBDMUX_LOCK_ASSERT(s, w)
  111 
  112 #define KBDMUX_SLEEP(s, f, d, t) \
  113         tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t))
  114 #define KBDMUX_CALLOUT_INIT(s) \
  115         callout_init(&(s)->ks_timo, 0)
  116 #define KBDMUX_QUEUE_INTR(s) \
  117         taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task)
  118 #endif /* not yet */
  119 
  120 /*
  121  * kbdmux keyboard
  122  */
  123 struct kbdmux_kbd
  124 {
  125         keyboard_t              *kbd;   /* keyboard */
  126         SLIST_ENTRY(kbdmux_kbd)  next;  /* link to next */
  127 };
  128 
  129 typedef struct kbdmux_kbd       kbdmux_kbd_t;
  130 
  131 /*
  132  * kbdmux state
  133  */
  134 struct kbdmux_state
  135 {
  136         char                     ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
  137         unsigned int             ks_inq_start;
  138         unsigned int             ks_inq_length;
  139         struct task              ks_task;       /* interrupt task */
  140         struct callout           ks_timo;       /* timeout handler */
  141 #define TICKS                   (hz)            /* rate */
  142 
  143         int                      ks_flags;      /* flags */
  144 #define COMPOSE                 (1 << 0)        /* compose char flag */ 
  145 #define POLLING                 (1 << 1)        /* polling */
  146 #define TASK                    (1 << 2)        /* interrupt task queued */
  147 
  148         int                      ks_mode;       /* K_XLATE, K_RAW, K_CODE */
  149         int                      ks_state;      /* state */
  150         int                      ks_accents;    /* accent key index (> 0) */
  151         u_int                    ks_composed_char; /* composed char code */
  152         u_char                   ks_prefix;     /* AT scan code prefix */
  153 
  154         SLIST_HEAD(, kbdmux_kbd) ks_kbds;       /* keyboards */
  155 
  156         KBDMUX_LOCK_DECL_GLOBAL;
  157 };
  158 
  159 typedef struct kbdmux_state     kbdmux_state_t;
  160 
  161 /*****************************************************************************
  162  *****************************************************************************
  163  **                             Helper functions
  164  *****************************************************************************
  165  *****************************************************************************/
  166 
  167 static task_fn_t                kbdmux_kbd_intr;
  168 static timeout_t                kbdmux_kbd_intr_timo;
  169 static kbd_callback_func_t      kbdmux_kbd_event;
  170 
  171 static void
  172 kbdmux_kbd_putc(kbdmux_state_t *state, char c)
  173 {
  174         unsigned int p;
  175 
  176         if (state->ks_inq_length == KBDMUX_Q_SIZE)
  177                 return;
  178 
  179         p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
  180         state->ks_inq[p] = c;
  181         state->ks_inq_length++;
  182 }
  183 
  184 static int
  185 kbdmux_kbd_getc(kbdmux_state_t *state)
  186 {
  187         unsigned char c;
  188 
  189         if (state->ks_inq_length == 0)
  190                 return (-1);
  191 
  192         c = state->ks_inq[state->ks_inq_start];
  193         state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
  194         state->ks_inq_length--;
  195 
  196         return (c);
  197 }
  198 
  199 /*
  200  * Interrupt handler task
  201  */
  202 void
  203 kbdmux_kbd_intr(void *xkbd, int pending)
  204 {
  205         keyboard_t      *kbd = (keyboard_t *) xkbd;
  206         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  207 
  208         kbdd_intr(kbd, NULL);
  209 
  210         KBDMUX_LOCK(state);
  211 
  212         state->ks_flags &= ~TASK;
  213         wakeup(&state->ks_task);
  214 
  215         KBDMUX_UNLOCK(state);
  216 }
  217 
  218 /*
  219  * Schedule interrupt handler on timeout. Called with locked state.
  220  */
  221 void
  222 kbdmux_kbd_intr_timo(void *xstate)
  223 {
  224         kbdmux_state_t  *state = (kbdmux_state_t *) xstate;
  225 
  226         KBDMUX_LOCK_ASSERT(state, MA_OWNED);
  227 
  228         if (callout_pending(&state->ks_timo))
  229                 return; /* callout was reset */
  230 
  231         if (!callout_active(&state->ks_timo))
  232                 return; /* callout was stopped */
  233 
  234         callout_deactivate(&state->ks_timo);
  235 
  236         /* queue interrupt task if needed */
  237         if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
  238             KBDMUX_QUEUE_INTR(state) == 0)
  239                 state->ks_flags |= TASK;
  240 
  241         /* re-schedule timeout */
  242         callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
  243 }
  244 
  245 /*
  246  * Process event from one of our keyboards
  247  */
  248 static int
  249 kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
  250 {
  251         kbdmux_state_t  *state = (kbdmux_state_t *) arg;
  252 
  253         switch (event) {
  254         case KBDIO_KEYINPUT: {
  255                 int     c;
  256 
  257                 KBDMUX_LOCK(state);
  258 
  259                 /*
  260                  * Read all chars from the keyboard
  261                  *
  262                  * Turns out that atkbd(4) check_char() method may return
  263                  * "true" while read_char() method returns NOKEY. If this
  264                  * happens we could stuck in the loop below. Avoid this
  265                  * by breaking out of the loop if read_char() method returns
  266                  * NOKEY.
  267                  */
  268 
  269                 while (kbdd_check_char(kbd)) {
  270                         c = kbdd_read_char(kbd, 0);
  271                         if (c == NOKEY)
  272                                 break;
  273                         if (c == ERRKEY)
  274                                 continue; /* XXX ring bell */
  275                         if (!KBD_IS_BUSY(kbd))
  276                                 continue; /* not open - discard the input */
  277 
  278                         kbdmux_kbd_putc(state, c);
  279                 }
  280 
  281                 /* queue interrupt task if needed */
  282                 if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) &&
  283                     KBDMUX_QUEUE_INTR(state) == 0)
  284                         state->ks_flags |= TASK;
  285 
  286                 KBDMUX_UNLOCK(state);
  287                 } break;
  288 
  289         case KBDIO_UNLOADING: {
  290                 kbdmux_kbd_t    *k;
  291 
  292                 KBDMUX_LOCK(state);
  293 
  294                 SLIST_FOREACH(k, &state->ks_kbds, next)
  295                         if (k->kbd == kbd)
  296                                 break;
  297 
  298                 if (k != NULL) {
  299                         kbd_release(k->kbd, &k->kbd);
  300                         SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
  301 
  302                         k->kbd = NULL;
  303 
  304                         free(k, M_KBDMUX);
  305                 }
  306 
  307                 KBDMUX_UNLOCK(state);
  308                 } break;
  309 
  310         default:
  311                 return (EINVAL);
  312                 /* NOT REACHED */
  313         }
  314 
  315         return (0);
  316 }
  317 
  318 /****************************************************************************
  319  ****************************************************************************
  320  **                              Keyboard driver
  321  ****************************************************************************
  322  ****************************************************************************/
  323 
  324 static int              kbdmux_configure(int flags);
  325 static kbd_probe_t      kbdmux_probe;
  326 static kbd_init_t       kbdmux_init;
  327 static kbd_term_t       kbdmux_term;
  328 static kbd_intr_t       kbdmux_intr;
  329 static kbd_test_if_t    kbdmux_test_if;
  330 static kbd_enable_t     kbdmux_enable;
  331 static kbd_disable_t    kbdmux_disable;
  332 static kbd_read_t       kbdmux_read;
  333 static kbd_check_t      kbdmux_check;
  334 static kbd_read_char_t  kbdmux_read_char;
  335 static kbd_check_char_t kbdmux_check_char;
  336 static kbd_ioctl_t      kbdmux_ioctl;
  337 static kbd_lock_t       kbdmux_lock;
  338 static void             kbdmux_clear_state_locked(kbdmux_state_t *state);
  339 static kbd_clear_state_t kbdmux_clear_state;
  340 static kbd_get_state_t  kbdmux_get_state;
  341 static kbd_set_state_t  kbdmux_set_state;
  342 static kbd_poll_mode_t  kbdmux_poll;
  343 
  344 static keyboard_switch_t kbdmuxsw = {
  345         .probe =        kbdmux_probe,
  346         .init =         kbdmux_init,
  347         .term =         kbdmux_term,
  348         .intr =         kbdmux_intr,
  349         .test_if =      kbdmux_test_if,
  350         .enable =       kbdmux_enable,
  351         .disable =      kbdmux_disable,
  352         .read =         kbdmux_read,
  353         .check =        kbdmux_check,
  354         .read_char =    kbdmux_read_char,
  355         .check_char =   kbdmux_check_char,
  356         .ioctl =        kbdmux_ioctl,
  357         .lock =         kbdmux_lock,
  358         .clear_state =  kbdmux_clear_state,
  359         .get_state =    kbdmux_get_state,
  360         .set_state =    kbdmux_set_state,
  361         .get_fkeystr =  genkbd_get_fkeystr,
  362         .poll =         kbdmux_poll,
  363         .diag =         genkbd_diag,
  364 };
  365 
  366 /*
  367  * Return the number of found keyboards
  368  */
  369 static int
  370 kbdmux_configure(int flags)
  371 {
  372         return (1);
  373 }
  374 
  375 /*
  376  * Detect a keyboard
  377  */
  378 static int
  379 kbdmux_probe(int unit, void *arg, int flags)
  380 {
  381         if (resource_disabled(KEYBOARD_NAME, unit))
  382                 return (ENXIO);
  383 
  384         return (0);
  385 }
  386 
  387 /*
  388  * Reset and initialize the keyboard (stolen from atkbd.c)
  389  */
  390 static int
  391 kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
  392 {
  393         keyboard_t      *kbd = NULL;
  394         kbdmux_state_t  *state = NULL;
  395         keymap_t        *keymap = NULL;
  396         accentmap_t     *accmap = NULL;
  397         fkeytab_t       *fkeymap = NULL;
  398         int              error, needfree, fkeymap_size, delay[2];
  399 
  400         if (*kbdp == NULL) {
  401                 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
  402                 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
  403                 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
  404                 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
  405                 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
  406                 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
  407                 needfree = 1;
  408 
  409                 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
  410                     (accmap == NULL) || (fkeymap == NULL)) {
  411                         error = ENOMEM;
  412                         goto bad;
  413                 }
  414 
  415                 KBDMUX_LOCK_INIT(state);
  416                 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
  417                 KBDMUX_CALLOUT_INIT(state);
  418                 SLIST_INIT(&state->ks_kbds);
  419         } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
  420                 return (0);
  421         } else {
  422                 kbd = *kbdp;
  423                 state = (kbdmux_state_t *) kbd->kb_data;
  424                 keymap = kbd->kb_keymap;
  425                 accmap = kbd->kb_accentmap;
  426                 fkeymap = kbd->kb_fkeytab;
  427                 fkeymap_size = kbd->kb_fkeytab_size;
  428                 needfree = 0;
  429         }
  430 
  431         if (!KBD_IS_PROBED(kbd)) {
  432                 /* XXX assume 101/102 keys keyboard */
  433                 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
  434                 bcopy(&key_map, keymap, sizeof(key_map));
  435                 bcopy(&accent_map, accmap, sizeof(accent_map));
  436                 bcopy(fkey_tab, fkeymap,
  437                         imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
  438                 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
  439                 kbd->kb_data = (void *)state;
  440         
  441                 KBD_FOUND_DEVICE(kbd);
  442                 KBD_PROBE_DONE(kbd);
  443 
  444                 KBDMUX_LOCK(state);
  445                 kbdmux_clear_state_locked(state);
  446                 state->ks_mode = K_XLATE;
  447                 KBDMUX_UNLOCK(state);
  448         }
  449 
  450         if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
  451                 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
  452 
  453                 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
  454 
  455                 delay[0] = kbd->kb_delay1;
  456                 delay[1] = kbd->kb_delay2;
  457                 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
  458 
  459                 KBD_INIT_DONE(kbd);
  460         }
  461 
  462         if (!KBD_IS_CONFIGURED(kbd)) {
  463                 if (kbd_register(kbd) < 0) {
  464                         error = ENXIO;
  465                         goto bad;
  466                 }
  467 
  468                 KBD_CONFIG_DONE(kbd);
  469 
  470                 KBDMUX_LOCK(state);
  471                 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
  472                 KBDMUX_UNLOCK(state);
  473         }
  474 
  475         return (0);
  476 bad:
  477         if (needfree) {
  478                 if (state != NULL)
  479                         free(state, M_KBDMUX);
  480                 if (keymap != NULL)
  481                         free(keymap, M_KBDMUX);
  482                 if (accmap != NULL)
  483                         free(accmap, M_KBDMUX);
  484                 if (fkeymap != NULL)
  485                         free(fkeymap, M_KBDMUX);
  486                 if (kbd != NULL) {
  487                         free(kbd, M_KBDMUX);
  488                         *kbdp = NULL;   /* insure ref doesn't leak to caller */
  489                 }
  490         }
  491 
  492         return (error);
  493 }
  494 
  495 /*
  496  * Finish using this keyboard
  497  */
  498 static int
  499 kbdmux_term(keyboard_t *kbd)
  500 {
  501         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
  502         kbdmux_kbd_t    *k;
  503 
  504         KBDMUX_LOCK(state);
  505 
  506         /* kill callout */
  507         callout_stop(&state->ks_timo);
  508 
  509         /* wait for interrupt task */
  510         while (state->ks_flags & TASK)
  511                 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0);
  512 
  513         /* release all keyboards from the mux */
  514         while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
  515                 kbd_release(k->kbd, &k->kbd);
  516                 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
  517 
  518                 k->kbd = NULL;
  519 
  520                 free(k, M_KBDMUX);
  521         }
  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 = kbdmux_kbd_getc(state);
  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_length > 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 = kbdmux_kbd_getc(state);
  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 (kbdd_check_char(k->kbd)) {
  666                                         scancode = kbdd_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                                         kbdmux_kbd_putc(state, scancode);
  675                                 }
  676                         }
  677 
  678                         if (state->ks_inq_length > 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_length > 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                 kbdd_enable(k->kbd);
  996                 kbdd_clear_state(k->kbd);
  997 
  998                 /* set K_RAW mode on slave keyboard */
  999                 mode = K_RAW;
 1000                 error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
 1001                 if (error == 0) {
 1002                         /* set lock keys state on slave keyboard */
 1003                         mode = state->ks_state & LOCK_MASK;
 1004                         error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&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                         kbdd_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                         kbdd_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                         kbdd_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                         kbdd_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         state->ks_inq_length = 0;
 1244 }
 1245 
 1246 static void
 1247 kbdmux_clear_state(keyboard_t *kbd)
 1248 {
 1249         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
 1250 
 1251         KBDMUX_LOCK(state);
 1252         kbdmux_clear_state_locked(state);
 1253         KBDMUX_UNLOCK(state);
 1254 }
 1255 
 1256 /*
 1257  * Save the internal state
 1258  */
 1259 static int
 1260 kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
 1261 {
 1262         if (len == 0)
 1263                 return (sizeof(kbdmux_state_t));
 1264         if (len < sizeof(kbdmux_state_t))
 1265                 return (-1);
 1266 
 1267         bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
 1268 
 1269         return (0);
 1270 }
 1271 
 1272 /*
 1273  * Set the internal state
 1274  */
 1275 static int
 1276 kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
 1277 {
 1278         if (len < sizeof(kbdmux_state_t))
 1279                 return (ENOMEM);
 1280 
 1281         bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
 1282 
 1283         return (0);
 1284 }
 1285 
 1286 /*
 1287  * Set polling
 1288  */
 1289 static int
 1290 kbdmux_poll(keyboard_t *kbd, int on)
 1291 {
 1292         kbdmux_state_t  *state = (kbdmux_state_t *) kbd->kb_data;
 1293         kbdmux_kbd_t    *k;
 1294 
 1295         KBDMUX_LOCK(state);
 1296 
 1297         if (on)
 1298                 state->ks_flags |= POLLING; 
 1299         else
 1300                 state->ks_flags &= ~POLLING;
 1301 
 1302         /* set poll on slave keyboards */
 1303         SLIST_FOREACH(k, &state->ks_kbds, next)
 1304                 kbdd_poll(k->kbd, on);
 1305 
 1306         KBDMUX_UNLOCK(state);
 1307 
 1308         return (0);
 1309 }
 1310 
 1311 /*****************************************************************************
 1312  *****************************************************************************
 1313  **                                    Module 
 1314  *****************************************************************************
 1315  *****************************************************************************/
 1316 
 1317 KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
 1318 
 1319 static int
 1320 kbdmux_modevent(module_t mod, int type, void *data)
 1321 {
 1322         keyboard_switch_t       *sw;
 1323         keyboard_t              *kbd;
 1324         int                      error;
 1325 
 1326         switch (type) {
 1327         case MOD_LOAD:
 1328                 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
 1329                         break;
 1330 
 1331                 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
 1332                         kbd_delete_driver(&kbdmux_kbd_driver);
 1333                         error = ENXIO;
 1334                         break;
 1335                 }
 1336 
 1337                 kbd = NULL;
 1338 
 1339                 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
 1340                     (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) {
 1341                         kbd_delete_driver(&kbdmux_kbd_driver);
 1342                         break;
 1343                 }
 1344 
 1345 #ifdef KBD_INSTALL_CDEV
 1346                 if ((error = kbd_attach(kbd)) != 0) {
 1347                         (*sw->term)(kbd);
 1348                         kbd_delete_driver(&kbdmux_kbd_driver);
 1349                         break;
 1350                 }
 1351 #endif
 1352 
 1353                 if ((error = (*sw->enable)(kbd)) != 0) {
 1354                         (*sw->disable)(kbd);
 1355 #ifdef KBD_INSTALL_CDEV
 1356                         kbd_detach(kbd);
 1357 #endif
 1358                         (*sw->term)(kbd);
 1359                         kbd_delete_driver(&kbdmux_kbd_driver);
 1360                         break;
 1361                 }
 1362                 break;
 1363 
 1364         case MOD_UNLOAD:
 1365                 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
 1366                         panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL");
 1367 
 1368                 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
 1369                 if (kbd != NULL) {
 1370                         (*sw->disable)(kbd);
 1371 #ifdef KBD_INSTALL_CDEV
 1372                         kbd_detach(kbd);
 1373 #endif
 1374                         (*sw->term)(kbd);
 1375                         kbd_delete_driver(&kbdmux_kbd_driver);
 1376                 }
 1377                 error = 0;
 1378                 break;
 1379 
 1380         default:
 1381                 error = EOPNOTSUPP;
 1382                 break;
 1383         }
 1384 
 1385         return (error);
 1386 }
 1387 
 1388 DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
 1389 

Cache object: 60da7a75e3f0836298fb9e54c1fc3395


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