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

Cache object: e7610c09978e79470d4e90127800f0c4


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