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/6.4/sys/dev/vkbd/vkbd.c 162998 2006-10-04 06:09:11Z ru $
   32  */
   33 
   34 #include "opt_kbd.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/conf.h>
   38 #include <sys/fcntl.h>
   39 #include <sys/kbio.h>
   40 #include <sys/kernel.h>
   41 #include <sys/limits.h>
   42 #include <sys/lock.h>
   43 #include <sys/malloc.h>
   44 #include <sys/module.h>
   45 #include <sys/mutex.h>
   46 #include <sys/poll.h>
   47 #include <sys/proc.h>
   48 #include <sys/queue.h>
   49 #include <sys/selinfo.h>
   50 #include <sys/systm.h>
   51 #include <sys/taskqueue.h>
   52 #include <sys/uio.h>
   53 #include <dev/kbd/kbdreg.h>
   54 #include <dev/kbd/kbdtables.h>
   55 #include <dev/vkbd/vkbd_var.h>
   56 
   57 #define DEVICE_NAME     "vkbdctl"
   58 #define KEYBOARD_NAME   "vkbd"
   59 
   60 MALLOC_DECLARE(M_VKBD);
   61 MALLOC_DEFINE(M_VKBD, KEYBOARD_NAME, "Virtual AT keyboard");
   62 
   63 /*****************************************************************************
   64  *****************************************************************************
   65  **                             Keyboard state
   66  *****************************************************************************
   67  *****************************************************************************/
   68 
   69 /*
   70  * XXX
   71  * For now rely on Giant mutex to protect our data structures.
   72  * Just like the rest of keyboard drivers and syscons(4) do.
   73  */
   74 
   75 #if 0 /* not yet */
   76 #define VKBD_LOCK_DECL          struct mtx ks_lock
   77 #define VKBD_LOCK_INIT(s)       mtx_init(&(s)->ks_lock, "vkbd_lock", NULL, MTX_DEF|MTX_RECURSE)
   78 #define VKBD_LOCK_DESTROY(s)    mtx_destroy(&(s)->ks_lock)
   79 #define VKBD_LOCK(s)            mtx_lock(&(s)->ks_lock)
   80 #define VKBD_UNLOCK(s)          mtx_unlock(&(s)->ks_lock)
   81 #define VKBD_LOCK_ASSERT(s, w)  mtx_assert(&(s)->ks_lock, w)
   82 #define VKBD_SLEEP(s, f, d, t) \
   83         msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), d, t)
   84 #else
   85 #define VKBD_LOCK_DECL
   86 #define VKBD_LOCK_INIT(s)
   87 #define VKBD_LOCK_DESTROY(s)
   88 #define VKBD_LOCK(s)
   89 #define VKBD_UNLOCK(s)
   90 #define VKBD_LOCK_ASSERT(s, w)
   91 #define VKBD_SLEEP(s, f, d, t)  tsleep(&(s)->f, PCATCH | (PZERO + 1), d, t)
   92 #endif
   93 
   94 #define VKBD_KEYBOARD(d) \
   95         kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, dev2unit(d)))
   96 
   97 /* vkbd queue */
   98 struct vkbd_queue
   99 {
  100         int             q[VKBD_Q_SIZE]; /* queue */
  101         int             head;           /* index of the first code */
  102         int             tail;           /* index of the last code */
  103         int             cc;             /* number of codes in queue */
  104 };
  105 
  106 typedef struct vkbd_queue       vkbd_queue_t;
  107 
  108 /* vkbd state */
  109 struct vkbd_state
  110 {
  111         struct cdev     *ks_dev;        /* control device */
  112 
  113         struct selinfo   ks_rsel;       /* select(2) */
  114         struct selinfo   ks_wsel;
  115 
  116         vkbd_queue_t     ks_inq;        /* input key codes queue */
  117         struct task      ks_task;       /* interrupt task */
  118 
  119         int              ks_flags;      /* flags */
  120 #define OPEN            (1 << 0)        /* control device is open */
  121 #define COMPOSE         (1 << 1)        /* compose flag */
  122 #define STATUS          (1 << 2)        /* status has changed */
  123 #define TASK            (1 << 3)        /* interrupt task queued */
  124 #define READ            (1 << 4)        /* read pending */
  125 #define WRITE           (1 << 5)        /* write pending */
  126 
  127         int              ks_mode;       /* K_XLATE, K_RAW, K_CODE */
  128         int              ks_polling;    /* polling flag */
  129         int              ks_state;      /* shift/lock key state */
  130         int              ks_accents;    /* accent key index (> 0) */
  131         u_int            ks_composed_char; /* composed char code */
  132         u_char           ks_prefix;     /* AT scan code prefix */
  133 
  134         VKBD_LOCK_DECL;
  135 };
  136 
  137 typedef struct vkbd_state       vkbd_state_t;
  138 
  139 /*****************************************************************************
  140  *****************************************************************************
  141  **                             Character device
  142  *****************************************************************************
  143  *****************************************************************************/
  144 
  145 static void             vkbd_dev_clone(void *, struct ucred *, char *, int,
  146                             struct cdev **);
  147 static d_open_t         vkbd_dev_open;
  148 static d_close_t        vkbd_dev_close;
  149 static d_read_t         vkbd_dev_read;
  150 static d_write_t        vkbd_dev_write;
  151 static d_ioctl_t        vkbd_dev_ioctl;
  152 static d_poll_t         vkbd_dev_poll;
  153 static void             vkbd_dev_intr(void *, int);
  154 static void             vkbd_status_changed(vkbd_state_t *);
  155 static int              vkbd_data_ready(vkbd_state_t *);
  156 static int              vkbd_data_read(vkbd_state_t *, int);
  157 
  158 static struct cdevsw    vkbd_dev_cdevsw = {
  159         .d_version =    D_VERSION,
  160         .d_flags =      D_PSEUDO | D_NEEDGIANT,
  161         .d_open =       vkbd_dev_open,
  162         .d_close =      vkbd_dev_close,
  163         .d_read =       vkbd_dev_read,
  164         .d_write =      vkbd_dev_write,
  165         .d_ioctl =      vkbd_dev_ioctl,
  166         .d_poll =       vkbd_dev_poll,
  167         .d_name =       DEVICE_NAME,
  168 };
  169 
  170 static struct clonedevs *vkbd_dev_clones = NULL;
  171 
  172 /* Clone device */
  173 static void
  174 vkbd_dev_clone(void *arg, struct ucred *cred, char *name, int namelen,
  175     struct cdev **dev)
  176 {
  177         int     unit;
  178 
  179         if (*dev != NULL)
  180                 return;
  181 
  182         if (strcmp(name, DEVICE_NAME) == 0)
  183                 unit = -1;
  184         else if (dev_stdclone(name, NULL, DEVICE_NAME, &unit) != 1)
  185                 return; /* don't recognize the name */
  186 
  187         /* find any existing device, or allocate new unit number */
  188         if (clone_create(&vkbd_dev_clones, &vkbd_dev_cdevsw, &unit, dev, 0)) {
  189                 *dev = make_dev(&vkbd_dev_cdevsw, unit2minor(unit),
  190                         UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME "%d", unit);
  191                 if (*dev != NULL) {
  192                         dev_ref(*dev);
  193                         (*dev)->si_flags |= SI_CHEAPCLONE;
  194                 }
  195         }
  196 }
  197 
  198 /* Open device */
  199 static int
  200 vkbd_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
  201 {
  202         int                      unit = dev2unit(dev), error;
  203         keyboard_switch_t       *sw = NULL;
  204         keyboard_t              *kbd = NULL;
  205         vkbd_state_t            *state = (vkbd_state_t *) dev->si_drv1;
  206 
  207         /* XXX FIXME: dev->si_drv1 locking */
  208         if (state == NULL) {
  209                 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
  210                         return (ENXIO);
  211 
  212                 if ((error = (*sw->probe)(unit, NULL, 0)) != 0 ||
  213                     (error = (*sw->init)(unit, &kbd, NULL, 0)) != 0)
  214                         return (error);
  215 
  216                 state = (vkbd_state_t *) kbd->kb_data;
  217 
  218                 if ((error = (*sw->enable)(kbd)) != 0) {
  219                         (*sw->term)(kbd);
  220                         return (error);
  221                 }
  222 
  223 #ifdef KBD_INSTALL_CDEV
  224                 if ((error = kbd_attach(kbd)) != 0) {
  225                         (*sw->disable)(kbd);
  226                         (*sw->term)(kbd);
  227                         return (error);
  228                 }
  229 #endif /* def KBD_INSTALL_CDEV */
  230 
  231                 dev->si_drv1 = kbd->kb_data;
  232         }
  233 
  234         VKBD_LOCK(state);
  235 
  236         if (state->ks_flags & OPEN) {
  237                 VKBD_UNLOCK(state);
  238                 return (EBUSY);
  239         }
  240 
  241         state->ks_flags |= OPEN;
  242         state->ks_dev = dev;
  243 
  244         VKBD_UNLOCK(state);
  245 
  246         return (0);
  247 }
  248 
  249 /* Close device */
  250 static int
  251 vkbd_dev_close(struct cdev *dev, int foo, int bar, struct thread *td)
  252 {
  253         keyboard_t      *kbd = VKBD_KEYBOARD(dev);
  254         vkbd_state_t    *state = NULL;
  255 
  256         if (kbd == NULL)
  257                 return (ENXIO);
  258 
  259         if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
  260                 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
  261 
  262         state = (vkbd_state_t *) kbd->kb_data;
  263 
  264         VKBD_LOCK(state);
  265 
  266         /* wait for interrupt task */
  267         while (state->ks_flags & TASK)
  268                 VKBD_SLEEP(state, ks_task, "vkbdc", 0);
  269 
  270         /* wakeup poll()ers */
  271         selwakeuppri(&state->ks_rsel, PZERO + 1);
  272         selwakeuppri(&state->ks_wsel, PZERO + 1);
  273 
  274         state->ks_flags &= ~OPEN;
  275         state->ks_dev = NULL;
  276         state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
  277 
  278         VKBD_UNLOCK(state);
  279 
  280         (*kbdsw[kbd->kb_index]->disable)(kbd);
  281 #ifdef KBD_INSTALL_CDEV
  282         kbd_detach(kbd);
  283 #endif /* def KBD_INSTALL_CDEV */
  284         (*kbdsw[kbd->kb_index]->term)(kbd);
  285 
  286         /* XXX FIXME: dev->si_drv1 locking */
  287         dev->si_drv1 = NULL;
  288 
  289         return (0);
  290 }
  291 
  292 /* Read status */
  293 static int
  294 vkbd_dev_read(struct cdev *dev, struct uio *uio, int flag)
  295 {
  296         keyboard_t      *kbd = VKBD_KEYBOARD(dev);
  297         vkbd_state_t    *state = NULL;
  298         vkbd_status_t    status;
  299         int              error;
  300 
  301         if (kbd == NULL)
  302                 return (ENXIO);
  303 
  304         if (uio->uio_resid != sizeof(status))
  305                 return (EINVAL);
  306 
  307         if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
  308                 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
  309 
  310         state = (vkbd_state_t *) kbd->kb_data;
  311 
  312         VKBD_LOCK(state);
  313 
  314         if (state->ks_flags & READ) {
  315                 VKBD_UNLOCK(state);
  316                 return (EALREADY);
  317         }
  318 
  319         state->ks_flags |= READ;
  320 again:
  321         if (state->ks_flags & STATUS) {
  322                 state->ks_flags &= ~STATUS;
  323 
  324                 status.mode = state->ks_mode;
  325                 status.leds = KBD_LED_VAL(kbd);
  326                 status.lock = state->ks_state & LOCK_MASK;
  327                 status.delay = kbd->kb_delay1;
  328                 status.rate = kbd->kb_delay2;
  329                 bzero(status.reserved, sizeof(status.reserved));
  330 
  331                 error = uiomove(&status, sizeof(status), uio);
  332         } else {
  333                 if (flag & O_NONBLOCK) {
  334                         error = EWOULDBLOCK;
  335                         goto done;
  336                 }
  337 
  338                 error = VKBD_SLEEP(state, ks_flags, "vkbdr", 0);
  339                 if (error != 0) 
  340                         goto done;
  341 
  342                 goto again;
  343         }
  344 done:
  345         state->ks_flags &= ~READ;
  346 
  347         VKBD_UNLOCK(state);
  348         
  349         return (error);
  350 }
  351 
  352 /* Write scancodes */
  353 static int
  354 vkbd_dev_write(struct cdev *dev, struct uio *uio, int flag)
  355 {
  356         keyboard_t      *kbd = VKBD_KEYBOARD(dev);
  357         vkbd_state_t    *state = NULL;
  358         vkbd_queue_t    *q = NULL;
  359         int              error, avail, bytes;
  360 
  361         if (kbd == NULL)
  362                 return (ENXIO);
  363 
  364         if (uio->uio_resid <= 0)
  365                 return (EINVAL);
  366 
  367         if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
  368                 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
  369 
  370         state = (vkbd_state_t *) kbd->kb_data;
  371 
  372         VKBD_LOCK(state);
  373 
  374         if (state->ks_flags & WRITE) {
  375                 VKBD_UNLOCK(state);
  376                 return (EALREADY);
  377         }
  378 
  379         state->ks_flags |= WRITE;
  380         error = 0;
  381         q = &state->ks_inq;
  382 
  383         while (uio->uio_resid >= sizeof(q->q[0])) {
  384                 if (q->head == q->tail) {
  385                         if (q->cc == 0)
  386                                 avail = sizeof(q->q)/sizeof(q->q[0]) - q->head;
  387                         else
  388                                 avail = 0; /* queue must be full */
  389                 } else if (q->head < q->tail)
  390                         avail = sizeof(q->q)/sizeof(q->q[0]) - q->tail;
  391                 else
  392                         avail = q->head - q->tail;
  393 
  394                 if (avail == 0) {
  395                         if (flag & O_NONBLOCK) {
  396                                 error = EWOULDBLOCK;
  397                                 break;
  398                         }
  399 
  400                         error = VKBD_SLEEP(state, ks_inq, "vkbdw", 0);
  401                         if (error != 0)
  402                                 break;
  403                 } else {
  404                         bytes = avail * sizeof(q->q[0]);
  405                         if (bytes > uio->uio_resid) {
  406                                 avail = uio->uio_resid / sizeof(q->q[0]);
  407                                 bytes = avail * sizeof(q->q[0]);
  408                         }
  409 
  410                         error = uiomove((void *) &q->q[q->tail], bytes, uio);
  411                         if (error != 0)
  412                                 break;
  413 
  414                         q->cc += avail;
  415                         q->tail += avail;
  416                         if (q->tail == sizeof(q->q)/sizeof(q->q[0]))
  417                                 q->tail = 0;
  418 
  419                         /* queue interrupt task if needed */
  420                         if (!(state->ks_flags & TASK) &&
  421                             taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task) == 0)
  422                                 state->ks_flags |= TASK;
  423                 }
  424         }
  425 
  426         state->ks_flags &= ~WRITE;
  427 
  428         VKBD_UNLOCK(state);
  429 
  430         return (error);
  431 }
  432 
  433 /* Process ioctl */
  434 static int
  435 vkbd_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  436 {
  437         keyboard_t      *kbd = VKBD_KEYBOARD(dev);
  438 
  439         return ((kbd == NULL)? ENXIO : 
  440                         (*kbdsw[kbd->kb_index]->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         (*kbdsw[kbd->kb_index]->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         int              ival;
 1096 
 1097         VKBD_LOCK(state);
 1098 
 1099         switch (cmd) {
 1100         case KDGKBMODE:         /* get keyboard mode */
 1101                 *(int *)arg = state->ks_mode;
 1102                 break;
 1103 
 1104         case _IO('K', 7):
 1105                 ival = IOCPARM_IVAL(arg);
 1106                 arg = (caddr_t)&ival;
 1107                 /* FALLTHROUGH */
 1108         case KDSKBMODE:         /* set keyboard mode */
 1109                 switch (*(int *)arg) {
 1110                 case K_XLATE:
 1111                         if (state->ks_mode != K_XLATE) {
 1112                                 /* make lock key state and LED state match */
 1113                                 state->ks_state &= ~LOCK_MASK;
 1114                                 state->ks_state |= KBD_LED_VAL(kbd);
 1115                                 vkbd_status_changed(state);
 1116                         }
 1117                         /* FALLTHROUGH */
 1118 
 1119                 case K_RAW:
 1120                 case K_CODE:
 1121                         if (state->ks_mode != *(int *)arg) {
 1122                                 vkbd_clear_state_locked(state);
 1123                                 state->ks_mode = *(int *)arg;
 1124                                 vkbd_status_changed(state);
 1125                         }
 1126                         break;
 1127 
 1128                 default:
 1129                         VKBD_UNLOCK(state);
 1130                         return (EINVAL);
 1131                 }
 1132                 break;
 1133 
 1134         case KDGETLED:          /* get keyboard LED */
 1135                 *(int *)arg = KBD_LED_VAL(kbd);
 1136                 break;
 1137 
 1138         case _IO('K', 66):
 1139                 ival = IOCPARM_IVAL(arg);
 1140                 arg = (caddr_t)&ival;
 1141                 /* FALLTHROUGH */
 1142         case KDSETLED:          /* set keyboard LED */
 1143                 /* NOTE: lock key state in ks_state won't be changed */
 1144                 if (*(int *)arg & ~LOCK_MASK) {
 1145                         VKBD_UNLOCK(state);
 1146                         return (EINVAL);
 1147                 }
 1148 
 1149                 i = *(int *)arg;
 1150                 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
 1151                 if (state->ks_mode == K_XLATE &&
 1152                     kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
 1153                         if (i & ALKED)
 1154                                 i |= CLKED;
 1155                         else
 1156                                 i &= ~CLKED;
 1157                 }
 1158 
 1159                 KBD_LED_VAL(kbd) = *(int *)arg;
 1160                 vkbd_status_changed(state);
 1161                 break;
 1162 
 1163         case KDGKBSTATE:        /* get lock key state */
 1164                 *(int *)arg = state->ks_state & LOCK_MASK;
 1165                 break;
 1166 
 1167         case _IO('K', 20):
 1168                 ival = IOCPARM_IVAL(arg);
 1169                 arg = (caddr_t)&ival;
 1170                 /* FALLTHROUGH */
 1171         case KDSKBSTATE:        /* set lock key state */
 1172                 if (*(int *)arg & ~LOCK_MASK) {
 1173                         VKBD_UNLOCK(state);
 1174                         return (EINVAL);
 1175                 }
 1176                 state->ks_state &= ~LOCK_MASK;
 1177                 state->ks_state |= *(int *)arg;
 1178                 vkbd_status_changed(state);
 1179                 VKBD_UNLOCK(state);
 1180                 /* set LEDs and quit */
 1181                 return (vkbd_ioctl(kbd, KDSETLED, arg));
 1182 
 1183         case KDSETREPEAT:       /* set keyboard repeat rate (new interface) */
 1184                 i = typematic(((int *)arg)[0], ((int *)arg)[1]);
 1185                 kbd->kb_delay1 = typematic_delay(i);
 1186                 kbd->kb_delay2 = typematic_rate(i);
 1187                 vkbd_status_changed(state);
 1188                 break;
 1189 
 1190         case _IO('K', 67):
 1191                 ival = IOCPARM_IVAL(arg);
 1192                 arg = (caddr_t)&ival;
 1193                 /* FALLTHROUGH */
 1194         case KDSETRAD:          /* set keyboard repeat rate (old interface) */
 1195                 kbd->kb_delay1 = typematic_delay(*(int *)arg);
 1196                 kbd->kb_delay2 = typematic_rate(*(int *)arg);
 1197                 vkbd_status_changed(state);
 1198                 break;
 1199 
 1200         case PIO_KEYMAP:        /* set keyboard translation table */
 1201         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
 1202         case PIO_DEADKEYMAP:    /* set accent key translation table */
 1203                 state->ks_accents = 0;
 1204                 /* FALLTHROUGH */
 1205 
 1206         default:
 1207                 VKBD_UNLOCK(state);
 1208                 return (genkbd_commonioctl(kbd, cmd, arg));
 1209         }
 1210 
 1211         VKBD_UNLOCK(state);
 1212 
 1213         return (0);
 1214 }
 1215 
 1216 /* Lock the access to the keyboard */
 1217 static int
 1218 vkbd_lock(keyboard_t *kbd, int lock)
 1219 {
 1220         return (1); /* XXX */
 1221 }
 1222 
 1223 /* Clear the internal state of the keyboard */
 1224 static void
 1225 vkbd_clear_state_locked(vkbd_state_t *state)
 1226 {
 1227         VKBD_LOCK_ASSERT(state, MA_OWNED);
 1228 
 1229         state->ks_flags &= ~COMPOSE;
 1230         state->ks_polling = 0;
 1231         state->ks_state &= LOCK_MASK;   /* preserve locking key state */
 1232         state->ks_accents = 0;
 1233         state->ks_composed_char = 0;
 1234 /*      state->ks_prefix = 0;           XXX */
 1235 
 1236         /* flush ks_inq and wakeup writers/poll()ers */
 1237         state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
 1238         selwakeuppri(&state->ks_wsel, PZERO + 1);
 1239         wakeup(&state->ks_inq);
 1240 }
 1241 
 1242 static void
 1243 vkbd_clear_state(keyboard_t *kbd)
 1244 {
 1245         vkbd_state_t    *state = (vkbd_state_t *) kbd->kb_data;
 1246 
 1247         VKBD_LOCK(state);
 1248         vkbd_clear_state_locked(state);
 1249         VKBD_UNLOCK(state);
 1250 }
 1251 
 1252 /* Save the internal state */
 1253 static int
 1254 vkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
 1255 {
 1256         if (len == 0)
 1257                 return (sizeof(vkbd_state_t));
 1258         if (len < sizeof(vkbd_state_t))
 1259                 return (-1);
 1260         bcopy(kbd->kb_data, buf, sizeof(vkbd_state_t)); /* XXX locking? */
 1261         return (0);
 1262 }
 1263 
 1264 /* Set the internal state */
 1265 static int
 1266 vkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
 1267 {
 1268         if (len < sizeof(vkbd_state_t))
 1269                 return (ENOMEM);
 1270         bcopy(buf, kbd->kb_data, sizeof(vkbd_state_t)); /* XXX locking? */
 1271         return (0);
 1272 }
 1273 
 1274 /* Set polling */
 1275 static int
 1276 vkbd_poll(keyboard_t *kbd, int on)
 1277 {
 1278         vkbd_state_t    *state = NULL;
 1279 
 1280         state = (vkbd_state_t *) kbd->kb_data;
 1281 
 1282         VKBD_LOCK(state);
 1283 
 1284         if (on)
 1285                 state->ks_polling ++;
 1286         else
 1287                 state->ks_polling --;
 1288 
 1289         VKBD_UNLOCK(state);
 1290 
 1291         return (0);
 1292 }
 1293 
 1294 /*
 1295  * Local functions
 1296  */
 1297 
 1298 static int delays[] = { 250, 500, 750, 1000 };
 1299 static int rates[] = {  34,  38,  42,  46,  50,  55,  59,  63,
 1300                         68,  76,  84,  92, 100, 110, 118, 126,
 1301                         136, 152, 168, 184, 200, 220, 236, 252,
 1302                         272, 304, 336, 368, 400, 440, 472, 504 };
 1303 
 1304 static int
 1305 typematic_delay(int i)
 1306 {
 1307         return (delays[(i >> 5) & 3]);
 1308 }
 1309 
 1310 static int
 1311 typematic_rate(int i)
 1312 {
 1313         return (rates[i & 0x1f]);
 1314 }
 1315 
 1316 static int
 1317 typematic(int delay, int rate)
 1318 {
 1319         int value;
 1320         int i;
 1321 
 1322         for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) {
 1323                 if (delay >= delays[i])
 1324                         break;
 1325         }
 1326         value = i << 5;
 1327         for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) {
 1328                 if (rate >= rates[i])
 1329                         break;
 1330         }
 1331         value |= i;
 1332         return (value);
 1333 }
 1334 
 1335 /*****************************************************************************
 1336  *****************************************************************************
 1337  **                                    Module 
 1338  *****************************************************************************
 1339  *****************************************************************************/
 1340 
 1341 KEYBOARD_DRIVER(vkbd, vkbdsw, vkbd_configure);
 1342 
 1343 static int
 1344 vkbd_modevent(module_t mod, int type, void *data)
 1345 {
 1346         static eventhandler_tag tag;
 1347 
 1348         switch (type) {
 1349         case MOD_LOAD:
 1350                 clone_setup(&vkbd_dev_clones);
 1351                 tag = EVENTHANDLER_REGISTER(dev_clone, vkbd_dev_clone, 0, 1000);
 1352                 if (tag == NULL) {
 1353                         clone_cleanup(&vkbd_dev_clones);
 1354                         return (ENOMEM);
 1355                 }
 1356                 kbd_add_driver(&vkbd_kbd_driver);
 1357                 break;
 1358 
 1359         case MOD_UNLOAD:
 1360                 kbd_delete_driver(&vkbd_kbd_driver);
 1361                 EVENTHANDLER_DEREGISTER(dev_clone, tag);
 1362                 clone_cleanup(&vkbd_dev_clones);
 1363                 break;
 1364 
 1365         default:
 1366                 return (EOPNOTSUPP);
 1367         }
 1368 
 1369         return (0);
 1370 }
 1371 
 1372 DEV_MODULE(vkbd, vkbd_modevent, NULL);
 1373 

Cache object: c67955f67b93c8ce6fec0bbcc99983da


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