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/kbd/kbd.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  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer as
   10  *    the first lines of this file unmodified.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 #include "kbd.h"
   30 #include "opt_kbd.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/conf.h>
   37 #include <sys/proc.h>
   38 #include <sys/tty.h>
   39 #include <sys/poll.h>
   40 #include <sys/vnode.h>
   41 #include <sys/uio.h>
   42 
   43 #include <machine/console.h>
   44 
   45 #include <dev/kbd/kbdreg.h>
   46 
   47 #define KBD_INDEX(dev)  minor(dev)
   48 
   49 typedef struct genkbd_softc {
   50         int             gkb_flags;      /* flag/status bits */
   51 #define KB_ASLEEP       (1 << 0)
   52         struct clist    gkb_q;          /* input queue */
   53         struct selinfo  gkb_rsel;
   54 } genkbd_softc_t;
   55 
   56 /* local arrays */
   57 
   58 /*
   59  * We need at least one entry each in order to initialize a keyboard
   60  * for the kernel console.  The arrays will be increased dynamically
   61  * when necessary.
   62  */
   63 
   64 static int              keyboards = 1;
   65 static keyboard_t       *kbd_ini;
   66 static keyboard_t       **keyboard = &kbd_ini;
   67 static keyboard_switch_t *kbdsw_ini;
   68        keyboard_switch_t **kbdsw = &kbdsw_ini;
   69 
   70 #ifdef KBD_INSTALL_CDEV
   71 static genkbd_softc_t   *kbdsoftc_ini;
   72 static genkbd_softc_t   **kbdsoftc = &kbdsoftc_ini;
   73 #endif
   74 
   75 #define ARRAY_DELTA     4
   76 
   77 static int
   78 kbd_realloc_array(void)
   79 {
   80         keyboard_t **new_kbd;
   81         keyboard_switch_t **new_kbdsw;
   82 #ifdef KBD_INSTALL_CDEV
   83         genkbd_softc_t **new_softc;
   84 #endif
   85         int newsize;
   86         int s;
   87 
   88         s = spltty();
   89         newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
   90         new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT);
   91         if (new_kbd == NULL) {
   92                 splx(s);
   93                 return ENOMEM;
   94         }
   95         new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT);
   96         if (new_kbdsw == NULL) {
   97                 free(new_kbd, M_DEVBUF);
   98                 splx(s);
   99                 return ENOMEM;
  100         }
  101 #ifdef KBD_INSTALL_CDEV
  102         new_softc = malloc(sizeof(*new_softc)*newsize, M_DEVBUF, M_NOWAIT);
  103         if (new_softc == NULL) {
  104                 free(new_kbd, M_DEVBUF);
  105                 free(new_kbdsw, M_DEVBUF);
  106                 splx(s);
  107                 return ENOMEM;
  108         }
  109 #endif
  110         bzero(new_kbd, sizeof(*new_kbd)*newsize);
  111         bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
  112         bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
  113         bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
  114 #ifdef KBD_INSTALL_CDEV
  115         bzero(new_softc, sizeof(*new_softc)*newsize);
  116         bcopy(kbdsoftc, new_softc, sizeof(*kbdsoftc)*keyboards);
  117 #endif
  118         if (keyboards > 1) {
  119                 free(keyboard, M_DEVBUF);
  120                 free(kbdsw, M_DEVBUF);
  121 #ifdef KBD_INSTALL_CDEV
  122                 free(kbdsoftc, M_DEVBUF);
  123 #endif
  124         }
  125         keyboard = new_kbd;
  126         kbdsw = new_kbdsw;
  127 #ifdef KBD_INSTALL_CDEV
  128         kbdsoftc = new_softc;
  129 #endif
  130         keyboards = newsize;
  131         splx(s);
  132 
  133         if (bootverbose)
  134                 printf("kbd: new array size %d\n", keyboards);
  135 
  136         return 0;
  137 }
  138 
  139 /*
  140  * Low-level keyboard driver functions
  141  * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
  142  * driver, call these functions to initialize the keyboard_t structure
  143  * and register it to the virtual keyboard driver `kbd'.
  144  */
  145 
  146 /* initialize the keyboard_t structure */
  147 void
  148 kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
  149                 int port, int port_size)
  150 {
  151         kbd->kb_flags = KB_NO_DEVICE;   /* device has not been found */
  152         kbd->kb_name = name;
  153         kbd->kb_type = type;
  154         kbd->kb_unit = unit;
  155         kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
  156         kbd->kb_led = 0;                /* unknown */
  157         kbd->kb_io_base = port;
  158         kbd->kb_io_size = port_size;
  159         kbd->kb_data = NULL;
  160         kbd->kb_keymap = NULL;
  161         kbd->kb_accentmap = NULL;
  162         kbd->kb_fkeytab = NULL;
  163         kbd->kb_fkeytab_size = 0;
  164         kbd->kb_delay1 = KB_DELAY1;     /* these values are advisory only */
  165         kbd->kb_delay2 = KB_DELAY2;
  166 }
  167 
  168 void
  169 kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
  170              fkeytab_t *fkeymap, int fkeymap_size)
  171 {
  172         kbd->kb_keymap = keymap;
  173         kbd->kb_accentmap = accmap;
  174         kbd->kb_fkeytab = fkeymap;
  175         kbd->kb_fkeytab_size = fkeymap_size;
  176 }
  177 
  178 /* register a keyboard and associate it with a function table */
  179 int
  180 kbd_register(keyboard_t *kbd)
  181 {
  182         keyboard_driver_t **list;
  183         keyboard_driver_t *p;
  184         int index;
  185 
  186         for (index = 0; index < keyboards; ++index) {
  187                 if (keyboard[index] == NULL)
  188                         break;
  189         }
  190         if (index >= keyboards) {
  191                 if (kbd_realloc_array())
  192                         return -1;
  193         }
  194 
  195         kbd->kb_index = index;
  196         KBD_UNBUSY(kbd);
  197         KBD_VALID(kbd);
  198         kbd->kb_active = 0;     /* disabled until someone calls kbd_enable() */
  199         kbd->kb_token = NULL;
  200         kbd->kb_callback.kc_func = NULL;
  201         kbd->kb_callback.kc_arg = NULL;
  202 
  203         list = (keyboard_driver_t **)kbddriver_set.ls_items;
  204         while ((p = *list++) != NULL) {
  205                 if (strcmp(p->name, kbd->kb_name) == 0) {
  206                         keyboard[index] = kbd;
  207                         kbdsw[index] = p->kbdsw;
  208                         return index;
  209                 }
  210         }
  211 
  212         return -1;
  213 }
  214 
  215 int
  216 kbd_unregister(keyboard_t *kbd)
  217 {
  218         int error;
  219         int s;
  220 
  221         if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
  222                 return ENOENT;
  223         if (keyboard[kbd->kb_index] != kbd)
  224                 return ENOENT;
  225 
  226         s = spltty();
  227         if (KBD_IS_BUSY(kbd)) {
  228                 error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
  229                                                     kbd->kb_callback.kc_arg);
  230                 if (error) {
  231                         splx(s);
  232                         return error;
  233                 }
  234                 if (KBD_IS_BUSY(kbd)) {
  235                         splx(s);
  236                         return EBUSY;
  237                 }
  238         }
  239         KBD_INVALID(kbd);
  240         keyboard[kbd->kb_index] = NULL;
  241         kbdsw[kbd->kb_index] = NULL;
  242 
  243         splx(s);
  244         return 0;
  245 }
  246 
  247 /* find a funciton table by the driver name */
  248 keyboard_switch_t
  249 *kbd_get_switch(char *driver)
  250 {
  251         keyboard_driver_t **list;
  252         keyboard_driver_t *p;
  253 
  254         list = (keyboard_driver_t **)kbddriver_set.ls_items;
  255         while ((p = *list++) != NULL) {
  256                 if (strcmp(p->name, driver) == 0)
  257                         return p->kbdsw;
  258         }
  259 
  260         return NULL;
  261 }
  262 
  263 /*
  264  * Keyboard client functions
  265  * Keyboard clients, such as the console driver `syscons' and the keyboard
  266  * cdev driver, use these functions to claim and release a keyboard for
  267  * exclusive use.
  268  */
  269 
  270 /* find the keyboard specified by a driver name and a unit number */
  271 int
  272 kbd_find_keyboard(char *driver, int unit)
  273 {
  274         int i;
  275 
  276         for (i = 0; i < keyboards; ++i) {
  277                 if (keyboard[i] == NULL)
  278                         continue;
  279                 if (!KBD_IS_VALID(keyboard[i]))
  280                         continue;
  281                 if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
  282                         continue;
  283                 if ((unit != -1) && (keyboard[i]->kb_unit != unit))
  284                         continue;
  285                 return i;
  286         }
  287         return -1;
  288 }
  289 
  290 /* allocate a keyboard */
  291 int
  292 kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
  293              void *arg)
  294 {
  295         int index;
  296         int s;
  297 
  298         if (func == NULL)
  299                 return -1;
  300 
  301         s = spltty();
  302         index = kbd_find_keyboard(driver, unit);
  303         if (index >= 0) {
  304                 if (KBD_IS_BUSY(keyboard[index])) {
  305                         splx(s);
  306                         return -1;
  307                 }
  308                 keyboard[index]->kb_token = id;
  309                 KBD_BUSY(keyboard[index]);
  310                 keyboard[index]->kb_callback.kc_func = func;
  311                 keyboard[index]->kb_callback.kc_arg = arg;
  312                 (*kbdsw[index]->clear_state)(keyboard[index]);
  313         }
  314         splx(s);
  315         return index;
  316 }
  317 
  318 int
  319 kbd_release(keyboard_t *kbd, void *id)
  320 {
  321         int error;
  322         int s;
  323 
  324         s = spltty();
  325         if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
  326                 error = EINVAL;
  327         } else if (kbd->kb_token != id) {
  328                 error = EPERM;
  329         } else {
  330                 kbd->kb_token = NULL;
  331                 KBD_UNBUSY(kbd);
  332                 kbd->kb_callback.kc_func = NULL;
  333                 kbd->kb_callback.kc_arg = NULL;
  334                 (*kbdsw[kbd->kb_index]->clear_state)(kbd);
  335                 error = 0;
  336         }
  337         splx(s);
  338         return error;
  339 }
  340 
  341 int
  342 kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
  343                     void *arg)
  344 {
  345         int error;
  346         int s;
  347 
  348         s = spltty();
  349         if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
  350                 error = EINVAL;
  351         } else if (kbd->kb_token != id) {
  352                 error = EPERM;
  353         } else if (func == NULL) {
  354                 error = EINVAL;
  355         } else {
  356                 kbd->kb_callback.kc_func = func;
  357                 kbd->kb_callback.kc_arg = arg;
  358                 error = 0;
  359         }
  360         splx(s);
  361         return error;
  362 }
  363 
  364 /* get a keyboard structure */
  365 keyboard_t
  366 *kbd_get_keyboard(int index)
  367 {
  368         if ((index < 0) || (index >= keyboards))
  369                 return NULL;
  370         if (keyboard[index] == NULL)
  371                 return NULL;
  372         if (!KBD_IS_VALID(keyboard[index]))
  373                 return NULL;
  374         return keyboard[index];
  375 }
  376 
  377 /*
  378  * The back door for the console driver; configure keyboards
  379  * This function is for the kernel console to initialize keyboards
  380  * at very early stage.
  381  */
  382 
  383 int
  384 kbd_configure(int flags)
  385 {
  386         keyboard_driver_t **list;
  387         keyboard_driver_t *p;
  388 
  389         list = (keyboard_driver_t **)kbddriver_set.ls_items;
  390         while ((p = *list++) != NULL) {
  391                 if (p->configure != NULL)
  392                         (*p->configure)(flags);
  393         }
  394 
  395         return 0;
  396 }
  397 
  398 #ifdef KBD_INSTALL_CDEV
  399 
  400 /*
  401  * Virtual keyboard cdev driver functions
  402  * The virtual keyboard driver dispatches driver functions to
  403  * appropriate subdrivers.
  404  */
  405 
  406 #define KBD_UNIT(dev)   minor(dev)
  407 
  408 static d_open_t         genkbdopen;
  409 static d_close_t        genkbdclose;
  410 static d_read_t         genkbdread;
  411 static d_write_t        genkbdwrite;
  412 static d_ioctl_t        genkbdioctl;
  413 static d_poll_t         genkbdpoll;
  414 
  415 #define CDEV_MAJOR      112
  416 
  417 static struct cdevsw kbd_cdevsw = {
  418         genkbdopen,     genkbdclose,    genkbdread,     genkbdwrite,   /* ??? */
  419         genkbdioctl,    nullstop,       noreset,        nodevtotty,
  420         genkbdpoll,     nommap,         nostrategy,     "kbd",
  421         NULL,           -1,             nodump,         nopsize,
  422 };
  423 
  424 static void
  425 vkbdattach(void *arg)
  426 {
  427         static int kbd_devsw_installed = FALSE;
  428         dev_t dev;
  429 
  430         if (!kbd_devsw_installed) {
  431                 dev = makedev(CDEV_MAJOR, 0);
  432                 cdevsw_add(&dev, &kbd_cdevsw, NULL);
  433                 kbd_devsw_installed = TRUE;
  434         }
  435 }
  436 
  437 PSEUDO_SET(vkbdattach, kbd);
  438 
  439 int
  440 kbd_attach(keyboard_t *kbd)
  441 {
  442         if (kbd->kb_index >= keyboards)
  443                 return EINVAL;
  444         if (keyboard[kbd->kb_index] != kbd)
  445                 return EINVAL;
  446 
  447         kbdsoftc[kbd->kb_index] = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
  448                                          M_WAITOK);
  449         bzero(kbdsoftc[kbd->kb_index], sizeof(genkbd_softc_t));
  450         /* XXX: DEVFS? */
  451 
  452         printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
  453         return 0;
  454 }
  455 
  456 int
  457 kbd_detach(keyboard_t *kbd)
  458 {
  459         if (kbd->kb_index >= keyboards)
  460                 return EINVAL;
  461         if (keyboard[kbd->kb_index] != kbd)
  462                 return EINVAL;
  463 
  464         if (kbd->kb_index > 0) {
  465                 free(kbdsoftc[kbd->kb_index], M_DEVBUF);
  466                 kbdsoftc[kbd->kb_index] = NULL;
  467         }
  468 
  469         return 0;
  470 }
  471 
  472 /*
  473  * Generic keyboard cdev driver functions
  474  * Keyboard subdrivers may call these functions to implement common
  475  * driver functions.
  476  */
  477 
  478 #define KB_QSIZE        512
  479 #define KB_BUFSIZE      64
  480 
  481 static kbd_callback_func_t genkbd_event;
  482 
  483 static int
  484 genkbdopen(dev_t dev, int mode, int flag, struct proc *p)
  485 {
  486         keyboard_t *kbd;
  487         genkbd_softc_t *sc;
  488         int s;
  489         int i;
  490 
  491         if (KBD_INDEX(dev) >= keyboards)
  492                 return ENXIO;
  493         s = spltty();
  494         sc = kbdsoftc[KBD_INDEX(dev)];
  495         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  496         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  497                 splx(s);
  498                 return ENXIO;
  499         }
  500         i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
  501                          genkbd_event, (void *)sc);
  502         if (i < 0) {
  503                 splx(s);
  504                 return EBUSY;
  505         }
  506         /* assert(i == kbd->kb_index) */
  507         /* assert(kbd == kbd_get_keyboard(i)) */
  508 
  509         /*
  510          * NOTE: even when we have successfully claimed a keyboard,
  511          * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
  512          */
  513 
  514 #if 0
  515         bzero(&sc->gkb_q, sizeof(sc->gkb_q));
  516 #endif
  517         clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
  518         sc->gkb_rsel.si_flags = 0;
  519         sc->gkb_rsel.si_pid = 0;
  520         splx(s);
  521 
  522         return 0;
  523 }
  524 
  525 static int
  526 genkbdclose(dev_t dev, int mode, int flag, struct proc *p)
  527 {
  528         keyboard_t *kbd;
  529         genkbd_softc_t *sc;
  530         int s;
  531 
  532         /*
  533          * NOTE: the device may have already become invalid.
  534          * kbd == NULL || !KBD_IS_VALID(kbd)
  535          */
  536         s = spltty();
  537         sc = kbdsoftc[KBD_INDEX(dev)];
  538         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  539         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  540                 /* XXX: we shall be forgiving and don't report error... */
  541         } else {
  542                 kbd_release(kbd, (void *)sc);
  543 #if 0
  544                 clist_free_cblocks(&sc->gkb_q);
  545 #endif
  546         }
  547         splx(s);
  548         return 0;
  549 }
  550 
  551 static int
  552 genkbdread(dev_t dev, struct uio *uio, int flag)
  553 {
  554         keyboard_t *kbd;
  555         genkbd_softc_t *sc;
  556         u_char buffer[KB_BUFSIZE];
  557         int len;
  558         int error;
  559         int s;
  560 
  561         /* wait for input */
  562         s = spltty();
  563         sc = kbdsoftc[KBD_INDEX(dev)];
  564         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  565         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  566                 splx(s);
  567                 return ENXIO;
  568         }
  569         while (sc->gkb_q.c_cc == 0) {
  570                 if (flag & IO_NDELAY) {
  571                         splx(s);
  572                         return EWOULDBLOCK;
  573                 }
  574                 sc->gkb_flags |= KB_ASLEEP;
  575                 error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
  576                 kbd = kbd_get_keyboard(KBD_INDEX(dev));
  577                 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
  578                         splx(s);
  579                         return ENXIO;   /* our keyboard has gone... */
  580                 }
  581                 if (error) {
  582                         sc->gkb_flags &= ~KB_ASLEEP;
  583                         splx(s);
  584                         return error;
  585                 }
  586         }
  587         splx(s);
  588 
  589         /* copy as much input as possible */
  590         error = 0;
  591         while (uio->uio_resid > 0) {
  592                 len = imin(uio->uio_resid, sizeof(buffer));
  593                 len = q_to_b(&sc->gkb_q, buffer, len);
  594                 if (len <= 0)
  595                         break;
  596                 error = uiomove(buffer, len, uio);
  597                 if (error)
  598                         break;
  599         }
  600 
  601         return error;
  602 }
  603 
  604 static int
  605 genkbdwrite(dev_t dev, struct uio *uio, int flag)
  606 {
  607         keyboard_t *kbd;
  608 
  609         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  610         if ((kbd == NULL) || !KBD_IS_VALID(kbd))
  611                 return ENXIO;
  612         return ENODEV;
  613 }
  614 
  615 static int
  616 genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
  617 {
  618         keyboard_t *kbd;
  619         int error;
  620 
  621         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  622         if ((kbd == NULL) || !KBD_IS_VALID(kbd))
  623                 return ENXIO;
  624         error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
  625         if (error == ENOIOCTL)
  626                 error = ENODEV;
  627         return error;
  628 }
  629 
  630 static int
  631 genkbdpoll(dev_t dev, int events, struct proc *p)
  632 {
  633         keyboard_t *kbd;
  634         genkbd_softc_t *sc;
  635         int revents;
  636         int s;
  637 
  638         revents = 0;
  639         s = spltty();
  640         sc = kbdsoftc[KBD_INDEX(dev)];
  641         kbd = kbd_get_keyboard(KBD_INDEX(dev));
  642         if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  643                 revents =  POLLHUP;     /* the keyboard has gone */
  644         } else if (events & (POLLIN | POLLRDNORM)) {
  645                 if (sc->gkb_q.c_cc > 0)
  646                         revents = events & (POLLIN | POLLRDNORM);
  647                 else
  648                         selrecord(p, &sc->gkb_rsel);
  649         }
  650         splx(s);
  651         return revents;
  652 }
  653 
  654 static int
  655 genkbd_event(keyboard_t *kbd, int event, void *arg)
  656 {
  657         genkbd_softc_t *sc;
  658         size_t len;
  659         u_char *cp;
  660         int mode;
  661         int c;
  662 
  663         /* assert(KBD_IS_VALID(kbd)) */
  664         sc = (genkbd_softc_t *)arg;
  665 
  666         switch (event) {
  667         case KBDIO_KEYINPUT:
  668                 break;
  669         case KBDIO_UNLOADING:
  670                 /* the keyboard is going... */
  671                 kbd_release(kbd, (void *)sc);
  672                 if (sc->gkb_flags & KB_ASLEEP) {
  673                         sc->gkb_flags &= ~KB_ASLEEP;
  674                         wakeup((caddr_t)sc);
  675                 }
  676                 selwakeup(&sc->gkb_rsel);
  677                 return 0;
  678         default:
  679                 return EINVAL;
  680         }
  681 
  682         /* obtain the current key input mode */
  683         if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
  684                 mode = K_XLATE;
  685 
  686         /* read all pending input */
  687         while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
  688                 c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
  689                 if (c == NOKEY)
  690                         continue;
  691                 if (c == ERRKEY)        /* XXX: ring bell? */
  692                         continue;
  693                 if (!KBD_IS_BUSY(kbd))
  694                         /* the device is not open, discard the input */
  695                         continue;
  696 
  697                 /* store the byte as is for K_RAW and K_CODE modes */
  698                 if (mode != K_XLATE) {
  699                         putc(KEYCHAR(c), &sc->gkb_q);
  700                         continue;
  701                 }
  702 
  703                 /* K_XLATE */
  704                 if (c & RELKEY) /* key release is ignored */
  705                         continue;
  706 
  707                 /* process special keys; most of them are just ignored... */
  708                 if (c & SPCLKEY) {
  709                         switch (KEYCHAR(c)) {
  710                         /* locking keys */
  711                         case NLK:  case CLK:  case SLK:  case ALK:
  712                         /* shift keys */
  713                         case LSH:  case RSH:  case LCTR: case RCTR:
  714                         case LALT: case RALT: case ASH:  case META:
  715                         /* other special keys */
  716                         case NOP:  case SPSC: case RBT:  case SUSP:
  717                         case STBY: case DBG:  case NEXT:
  718                                 /* ignore them... */
  719                                 continue;
  720                         case BTAB:      /* a backtab: ESC [ Z */
  721                                 putc(0x1b, &sc->gkb_q);
  722                                 putc('[', &sc->gkb_q);
  723                                 putc('Z', &sc->gkb_q);
  724                                 continue;
  725                         }
  726                 }
  727 
  728                 /* normal chars, normal chars with the META, function keys */
  729                 switch (KEYFLAGS(c)) {
  730                 case 0:                 /* a normal char */
  731                         putc(KEYCHAR(c), &sc->gkb_q);
  732                         break;
  733                 case MKEY:              /* the META flag: prepend ESC */
  734                         putc(0x1b, &sc->gkb_q);
  735                         putc(KEYCHAR(c), &sc->gkb_q);
  736                         break;
  737                 case FKEY | SPCLKEY:    /* a function key, return string */
  738                         cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
  739                                                         KEYCHAR(c), &len);
  740                         if (cp != NULL) {
  741                                 while (len-- >  0)
  742                                         putc(*cp++, &sc->gkb_q);
  743                         }
  744                         break;
  745                 }
  746         }
  747 
  748         /* wake up sleeping/polling processes */
  749         if (sc->gkb_q.c_cc > 0) {
  750                 if (sc->gkb_flags & KB_ASLEEP) {
  751                         sc->gkb_flags &= ~KB_ASLEEP;
  752                         wakeup((caddr_t)sc);
  753                 }
  754                 selwakeup(&sc->gkb_rsel);
  755         }
  756 
  757         return 0;
  758 }
  759 
  760 #endif /* KBD_INSTALL_CDEV */
  761 
  762 /*
  763  * Generic low-level keyboard functions
  764  * The low-level functions in the keyboard subdriver may use these
  765  * functions.
  766  */
  767 
  768 int
  769 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
  770 {
  771         keyarg_t *keyp;
  772         fkeyarg_t *fkeyp;
  773         int s;
  774         int i;
  775 
  776         s = spltty();
  777         switch (cmd) {
  778 
  779         case KDGKBINFO:         /* get keyboard information */
  780                 ((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
  781                 i = imin(strlen(kbd->kb_name) + 1,
  782                          sizeof(((keyboard_info_t *)arg)->kb_name));
  783                 bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
  784                 ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
  785                 ((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
  786                 ((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
  787                 ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
  788                 break;
  789 
  790         case KDGKBTYPE:         /* get keyboard type */
  791                 *(int *)arg = kbd->kb_type;
  792                 break;
  793 
  794         case KDGETREPEAT:       /* get keyboard repeat rate */
  795                 ((int *)arg)[0] = kbd->kb_delay1;
  796                 ((int *)arg)[1] = kbd->kb_delay2; 
  797                 break;
  798 
  799         case GIO_KEYMAP:        /* get keyboard translation table */
  800                 bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
  801                 break;
  802         case PIO_KEYMAP:        /* set keyboard translation table */
  803 #ifndef KBD_DISABLE_KEYMAP_LOAD
  804                 bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
  805                 bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
  806                 break;
  807 #else
  808                 splx(s);
  809                 return ENODEV;
  810 #endif
  811 
  812         case GIO_KEYMAPENT:     /* get keyboard translation table entry */
  813                 keyp = (keyarg_t *)arg;
  814                 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
  815                                         /sizeof(kbd->kb_keymap->key[0])) {
  816                         splx(s);
  817                         return EINVAL;
  818                 }
  819                 bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
  820                       sizeof(keyp->key));
  821                 break;
  822         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
  823 #ifndef KBD_DISABLE_KEYMAP_LOAD
  824                 keyp = (keyarg_t *)arg;
  825                 if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
  826                                         /sizeof(kbd->kb_keymap->key[0])) {
  827                         splx(s);
  828                         return EINVAL;
  829                 }
  830                 bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
  831                       sizeof(keyp->key));
  832                 break;
  833 #else
  834                 splx(s);
  835                 return ENODEV;
  836 #endif
  837 
  838         case GIO_DEADKEYMAP:    /* get accent key translation table */
  839                 bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
  840                 break;
  841         case PIO_DEADKEYMAP:    /* set accent key translation table */
  842 #ifndef KBD_DISABLE_KEYMAP_LOAD
  843                 bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
  844                 break;
  845 #else
  846                 splx(s);
  847                 return ENODEV;
  848 #endif
  849 
  850         case GETFKEY:           /* get functionkey string */
  851                 fkeyp = (fkeyarg_t *)arg;
  852                 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
  853                         splx(s);
  854                         return EINVAL;
  855                 }
  856                 bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
  857                       kbd->kb_fkeytab[fkeyp->keynum].len);
  858                 fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
  859                 break;
  860         case SETFKEY:           /* set functionkey string */
  861 #ifndef KBD_DISABLE_KEYMAP_LOAD
  862                 fkeyp = (fkeyarg_t *)arg;
  863                 if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
  864                         splx(s);
  865                         return EINVAL;
  866                 }
  867                 kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
  868                 bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
  869                       kbd->kb_fkeytab[fkeyp->keynum].len);
  870                 break;
  871 #else
  872                 splx(s);
  873                 return ENODEV;
  874 #endif
  875 
  876         default:
  877                 splx(s);
  878                 return ENOIOCTL;
  879         }
  880 
  881         splx(s);
  882         return 0;
  883 }
  884 
  885 /* get a pointer to the string associated with the given function key */
  886 u_char
  887 *genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
  888 {
  889         if (kbd == NULL)
  890                 return NULL;
  891         fkey -= F_FN;
  892         if (fkey > kbd->kb_fkeytab_size)
  893                 return NULL;
  894         *len = kbd->kb_fkeytab[fkey].len;
  895         return kbd->kb_fkeytab[fkey].str;
  896 }
  897 
  898 /* diagnostic dump */
  899 static char
  900 *get_kbd_type_name(int type)
  901 {
  902         static struct {
  903                 int type;
  904                 char *name;
  905         } name_table[] = {
  906                 { KB_84,        "AT 84" },
  907                 { KB_101,       "AT 101/102" },
  908                 { KB_OTHER,     "generic" },
  909         };
  910         int i;
  911 
  912         for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
  913                 if (type == name_table[i].type)
  914                         return name_table[i].name;
  915         }
  916         return "unknown";
  917 }
  918 
  919 void
  920 genkbd_diag(keyboard_t *kbd, int level)
  921 {
  922         if (level > 0) {
  923                 printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 
  924                        kbd->kb_index, kbd->kb_name, kbd->kb_unit,
  925                        get_kbd_type_name(kbd->kb_type), kbd->kb_type,
  926                        kbd->kb_config, kbd->kb_flags);
  927                 if (kbd->kb_io_base > 0)
  928                         printf(", port:0x%x-0x%x", kbd->kb_io_base, 
  929                                kbd->kb_io_base + kbd->kb_io_size - 1);
  930                 printf("\n");
  931         }
  932 }
  933 
  934 #define set_lockkey_state(k, s, l)                              \
  935         if (!((s) & l ## DOWN)) {                               \
  936                 int i;                                          \
  937                 (s) |= l ## DOWN;                               \
  938                 (s) ^= l ## ED;                                 \
  939                 i = (s) & LOCK_MASK;                            \
  940                 (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
  941         }
  942 
  943 static u_int
  944 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
  945 {
  946         int i;
  947 
  948         /* make an index into the accent map */
  949         i = key - F_ACC + 1;
  950         if ((i > kbd->kb_accentmap->n_accs)
  951             || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
  952                 /* the index is out of range or pointing to an empty entry */
  953                 *accents = 0;
  954                 return ERRKEY;
  955         }
  956 
  957         /* 
  958          * If the same accent key has been hit twice, produce the accent char
  959          * itself.
  960          */
  961         if (i == *accents) {
  962                 key = kbd->kb_accentmap->acc[i - 1].accchar;
  963                 *accents = 0;
  964                 return key;
  965         }
  966 
  967         /* remember the index and wait for the next key  */
  968         *accents = i; 
  969         return NOKEY;
  970 }
  971 
  972 static u_int
  973 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
  974 {
  975         struct acc_t *acc;
  976         int i;
  977 
  978         acc = &kbd->kb_accentmap->acc[*accents - 1];
  979         *accents = 0;
  980 
  981         /* 
  982          * If the accent key is followed by the space key,
  983          * produce the accent char itself.
  984          */
  985         if (ch == ' ')
  986                 return acc->accchar;
  987 
  988         /* scan the accent map */
  989         for (i = 0; i < NUM_ACCENTCHARS; ++i) {
  990                 if (acc->map[i][0] == 0)        /* end of table */
  991                         break;
  992                 if (acc->map[i][0] == ch)
  993                         return acc->map[i][1];
  994         }
  995         /* this char cannot be accented... */
  996         return ERRKEY;
  997 }
  998 
  999 int
 1000 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
 1001                  int *accents)
 1002 {
 1003         struct keyent_t *key;
 1004         int state = *shiftstate;
 1005         int action;
 1006         int f;
 1007         int i;
 1008 
 1009         f = state & (AGRS | ALKED);
 1010         if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
 1011                 keycode += ALTGR_OFFSET;
 1012         key = &kbd->kb_keymap->key[keycode];
 1013         i = ((state & SHIFTS) ? 1 : 0)
 1014             | ((state & CTLS) ? 2 : 0)
 1015             | ((state & ALTS) ? 4 : 0);
 1016         if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
 1017                 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
 1018                 i ^= 1;
 1019 
 1020         action = key->map[i];
 1021         if (up) {       /* break: key released */
 1022                 if (key->spcl & (0x80 >> i)) {
 1023                         /* special keys */
 1024                         switch (action) {
 1025                         case LSH:
 1026                                 state &= ~SHIFTS1;
 1027                                 break;
 1028                         case RSH:
 1029                                 state &= ~SHIFTS2;
 1030                                 break;
 1031                         case LCTR:
 1032                                 state &= ~CTLS1;
 1033                                 break;
 1034                         case RCTR:
 1035                                 state &= ~CTLS2;
 1036                                 break;
 1037                         case LALT:
 1038                                 state &= ~ALTS1;
 1039                                 break;
 1040                         case RALT:
 1041                                 state &= ~ALTS2;
 1042                                 break;
 1043                         case ASH:
 1044                                 state &= ~AGRS1;
 1045                                 break;
 1046                         case META:
 1047                                 state &= ~METAS1;
 1048                                 break;
 1049                         case NLK:
 1050                                 state &= ~NLKDOWN;
 1051                                 break;
 1052                         case CLK:
 1053 #ifndef PC98
 1054                                 state &= ~CLKDOWN;
 1055 #else
 1056                                 state &= ~CLKED;
 1057                                 i = state & LOCK_MASK;
 1058                                 (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
 1059                                                                (caddr_t)&i);
 1060 #endif
 1061                                 break;
 1062                         case SLK:
 1063                                 state &= ~SLKDOWN;
 1064                                 break;
 1065                         case ALK:
 1066                                 state &= ~ALKDOWN;
 1067                                 break;
 1068                         }
 1069                         *shiftstate = state;
 1070                         return (SPCLKEY | RELKEY | action);
 1071                 }
 1072                 /* release events of regular keys are not reported */
 1073                 return NOKEY;
 1074         } else {        /* make: key pressed */
 1075                 if (key->spcl & (0x80 >> i)) {
 1076                         /* special keys */
 1077                         switch (action) {
 1078                         /* LOCKING KEYS */
 1079                         case NLK:
 1080                                 set_lockkey_state(kbd, state, NLK);
 1081                                 break;
 1082                         case CLK:
 1083 #ifndef PC98
 1084                                 set_lockkey_state(kbd, state, CLK);
 1085 #else
 1086                                 state |= CLKED;
 1087                                 i = state & LOCK_MASK;
 1088                                 (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
 1089                                                                (caddr_t)&i);
 1090 #endif
 1091                                 break;
 1092                         case SLK:
 1093                                 set_lockkey_state(kbd, state, SLK);
 1094                                 break;
 1095                         case ALK:
 1096                                 set_lockkey_state(kbd, state, ALK);
 1097                                 break;
 1098                         /* NON-LOCKING KEYS */
 1099                         case SPSC: case RBT:  case SUSP: case STBY:
 1100                         case DBG:  case NEXT:
 1101                                 *accents = 0;
 1102                                 break;
 1103                         case BTAB:
 1104                                 *accents = 0;
 1105                                 action |= BKEY;
 1106                                 break;
 1107                         case LSH:
 1108                                 state |= SHIFTS1;
 1109                                 break;
 1110                         case RSH:
 1111                                 state |= SHIFTS2;
 1112                                 break;
 1113                         case LCTR:
 1114                                 state |= CTLS1;
 1115                                 break;
 1116                         case RCTR:
 1117                                 state |= CTLS2;
 1118                                 break;
 1119                         case LALT:
 1120                                 state |= ALTS1;
 1121                                 break;
 1122                         case RALT:
 1123                                 state |= ALTS2;
 1124                                 break;
 1125                         case ASH:
 1126                                 state |= AGRS1;
 1127                                 break;
 1128                         case META:
 1129                                 state |= METAS1;
 1130                                 break;
 1131                         default:
 1132                                 /* is this an accent (dead) key? */
 1133                                 if (action >= F_ACC && action <= L_ACC) {
 1134                                         action = save_accent_key(kbd, action,
 1135                                                                  accents);
 1136                                         switch (action) {
 1137                                         case NOKEY:
 1138                                         case ERRKEY:
 1139                                                 return action;
 1140                                         default:
 1141                                                 if (state & METAS)
 1142                                                         return (action | MKEY);
 1143                                                 else
 1144                                                         return action;
 1145                                         }
 1146                                         /* NOT REACHED */
 1147                                 }
 1148                                 /* other special keys */
 1149                                 if (*accents > 0) {
 1150                                         *accents = 0;
 1151                                         return ERRKEY;
 1152                                 }
 1153                                 if (action >= F_FN && action <= L_FN)
 1154                                         action |= FKEY;
 1155                                 /* XXX: return fkey string for the FKEY? */
 1156                         }
 1157                         *shiftstate = state;
 1158                         return (SPCLKEY | action);
 1159                 } else {
 1160                         /* regular keys */
 1161                         if (*accents > 0) {
 1162                                 /* make an accented char */
 1163                                 action = make_accent_char(kbd, action, accents);
 1164                                 if (action == ERRKEY)
 1165                                         return action;
 1166                         }
 1167                         if (state & METAS)
 1168                                 action |= MKEY;
 1169                         return action;
 1170                 }
 1171         }
 1172         /* NOT REACHED */
 1173 }

Cache object: c41b605edc6598262aa7014ef8790ecc


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