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

Cache object: 30c93313e501283bb357e8a85984c257


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