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

Cache object: 1c6d912dddfd6a118c4b08818857d561


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