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/pc98/pc98/pc98kbd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1999 FreeBSD(98) port team.
    3  * All rights reserved.
    4  * 
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer as
   10  *    the first lines of this file unmodified.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  * 
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * $FreeBSD: releng/5.0/sys/pc98/pc98/pc98kbd.c 102412 2002-08-25 13:23:09Z charnier $
   29  */
   30 
   31 #include "opt_kbd.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 #include <sys/bus.h>
   38 #include <machine/bus.h>
   39 #include <sys/rman.h>
   40 #include <sys/kbio.h>
   41 
   42 #include <machine/resource.h>
   43 
   44 #include <dev/kbd/kbdreg.h>
   45 
   46 #include <pc98/pc98/pc98.h>
   47 
   48 #include <isa/isavar.h>
   49 
   50 #define DRIVER_NAME             "pckbd"
   51 
   52 /* device configuration flags */
   53 #define KB_CONF_FAIL_IF_NO_KBD  (1 << 0) /* don't install if no kbd is found */
   54 
   55 static devclass_t       pckbd_devclass;
   56 
   57 static int              pckbdprobe(device_t dev);
   58 static int              pckbdattach(device_t dev);
   59 static int              pckbdresume(device_t dev);
   60 static void             pckbd_isa_intr(void *arg);
   61 
   62 static device_method_t pckbd_methods[] = {
   63         /* Device interface */
   64         DEVMETHOD(device_probe,         pckbdprobe),
   65         DEVMETHOD(device_attach,        pckbdattach),
   66         DEVMETHOD(device_resume,        pckbdresume),
   67         { 0, 0 }
   68 };
   69 
   70 static driver_t pckbd_driver = {
   71         DRIVER_NAME,
   72         pckbd_methods,
   73         1,
   74 };
   75 
   76 DRIVER_MODULE(pckbd, isa, pckbd_driver, pckbd_devclass, 0, 0);
   77 
   78 static bus_addr_t pckbd_iat[] = {0, 2};
   79 
   80 static int              pckbd_probe_unit(int unit, int port, int irq,
   81                                          int flags);
   82 static int              pckbd_attach_unit(int unit, keyboard_t **kbd,
   83                                           int port, int irq, int flags);
   84 static timeout_t        pckbd_timeout;
   85 
   86 
   87 static int
   88 pckbdprobe(device_t dev)
   89 {
   90         struct resource *res;
   91         int error, rid;
   92 
   93         /* Check isapnp ids */
   94         if (isa_get_vendorid(dev))
   95                 return (ENXIO);
   96 
   97         device_set_desc(dev, "PC-98 Keyboard");
   98 
   99         rid = 0;
  100         res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
  101                                   RF_ACTIVE);
  102         if (res == NULL)
  103                 return ENXIO;
  104         isa_load_resourcev(res, pckbd_iat, 2);
  105 
  106         error = pckbd_probe_unit(device_get_unit(dev),
  107                                  isa_get_port(dev),
  108                                  (1 << isa_get_irq(dev)),
  109                                  device_get_flags(dev));
  110 
  111         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  112 
  113         return (error);
  114 }
  115 
  116 static int
  117 pckbdattach(device_t dev)
  118 {
  119         keyboard_t      *kbd;
  120         void            *ih;
  121         struct resource *res;
  122         int             error, rid;
  123 
  124         rid = 0;
  125         res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2,
  126                                   RF_ACTIVE);
  127         if (res == NULL)
  128                 return ENXIO;
  129         isa_load_resourcev(res, pckbd_iat, 2);
  130 
  131         error = pckbd_attach_unit(device_get_unit(dev), &kbd,
  132                                   isa_get_port(dev),
  133                                   (1 << isa_get_irq(dev)),
  134                                   device_get_flags(dev));
  135 
  136         rid = 0;
  137         res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE);
  138         if (res == NULL)
  139                 return ENXIO;
  140         BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
  141                        pckbd_isa_intr, kbd, &ih);
  142 
  143         return 0;
  144 }
  145 
  146 static int
  147 pckbdresume(device_t dev)
  148 {
  149         keyboard_t *kbd;
  150 
  151         kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME,
  152                                                  device_get_unit(dev)));
  153         if (kbd)
  154                 (*kbdsw[kbd->kb_index]->clear_state)(kbd);
  155 
  156         return (0);
  157 }
  158 
  159 static void
  160 pckbd_isa_intr(void *arg)
  161 {
  162         keyboard_t      *kbd = arg;
  163 
  164         (*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
  165 }
  166 
  167 static int
  168 pckbd_probe_unit(int unit, int port, int irq, int flags)
  169 {
  170         keyboard_switch_t *sw;
  171         int args[2];
  172         int error;
  173 
  174         sw = kbd_get_switch(DRIVER_NAME);
  175         if (sw == NULL)
  176                 return ENXIO;
  177 
  178         args[0] = port;
  179         args[1] = irq;
  180         error = (*sw->probe)(unit, args, flags);
  181         if (error)
  182                 return error;
  183         return 0;
  184 }
  185 
  186 static int
  187 pckbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags)
  188 {
  189         keyboard_switch_t *sw;
  190         int args[2];
  191         int error;
  192 
  193         sw = kbd_get_switch(DRIVER_NAME);
  194         if (sw == NULL)
  195                 return ENXIO;
  196 
  197         /* reset, initialize and enable the device */
  198         args[0] = port;
  199         args[1] = irq;
  200         *kbd = NULL;
  201         error = (*sw->probe)(unit, args, flags);
  202         if (error)
  203                 return error;
  204         error = (*sw->init)(unit, kbd, args, flags);
  205         if (error)
  206                 return error;
  207         (*sw->enable)(*kbd);
  208 
  209 #ifdef KBD_INSTALL_CDEV
  210         /* attach a virtual keyboard cdev */
  211         error = kbd_attach(*kbd);
  212         if (error)
  213                 return error;
  214 #endif /* KBD_INSTALL_CDEV */
  215 
  216         /*
  217          * This is a kludge to compensate for lost keyboard interrupts.
  218          * A similar code used to be in syscons. See below. XXX
  219          */
  220         pckbd_timeout(*kbd);
  221 
  222         if (bootverbose)
  223                 (*sw->diag)(*kbd, bootverbose);
  224 
  225         return 0;
  226 }
  227 
  228 static void
  229 pckbd_timeout(void *arg)
  230 {
  231         keyboard_t *kbd;
  232         int s;
  233 
  234         /* The following comments are extracted from syscons.c (1.287) */
  235         /* 
  236          * With release 2.1 of the Xaccel server, the keyboard is left
  237          * hanging pretty often. Apparently an interrupt from the
  238          * keyboard is lost, and I don't know why (yet).
  239          * This ugly hack calls scintr if input is ready for the keyboard
  240          * and conveniently hides the problem.                  XXX
  241          */
  242         /*
  243          * Try removing anything stuck in the keyboard controller; whether
  244          * it's a keyboard scan code or mouse data. `scintr()' doesn't
  245          * read the mouse data directly, but `kbdio' routines will, as a
  246          * side effect.
  247          */
  248         s = spltty();
  249         kbd = (keyboard_t *)arg;
  250         if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) {
  251                 /*
  252                  * We have seen the lock flag is not set. Let's reset
  253                  * the flag early, otherwise the LED update routine fails
  254                  * which may want the lock during the interrupt routine.
  255                  */
  256                 (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE);
  257                 if ((*kbdsw[kbd->kb_index]->check_char)(kbd))
  258                         (*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
  259         }
  260         splx(s);
  261         timeout(pckbd_timeout, arg, hz/10);
  262 }
  263 
  264 /* LOW-LEVEL */
  265 
  266 #include <machine/limits.h>
  267 
  268 #define PC98KBD_DEFAULT 0
  269 
  270 typedef caddr_t         KBDC;
  271 
  272 typedef struct pckbd_state {
  273         KBDC            kbdc;           /* keyboard controller */
  274         int             ks_mode;        /* input mode (K_XLATE,K_RAW,K_CODE) */
  275         int             ks_flags;       /* flags */
  276 #define COMPOSE         (1 << 0)
  277         int             ks_state;       /* shift/lock key state */
  278         int             ks_accents;     /* accent key index (> 0) */
  279         u_int           ks_composed_char; /* composed char code (> 0) */
  280 } pckbd_state_t;
  281 
  282 /* keyboard driver declaration */
  283 static int              pckbd_configure(int flags);
  284 static kbd_probe_t      pckbd_probe;
  285 static kbd_init_t       pckbd_init;
  286 static kbd_term_t       pckbd_term;
  287 static kbd_intr_t       pckbd_intr;
  288 static kbd_test_if_t    pckbd_test_if;
  289 static kbd_enable_t     pckbd_enable;
  290 static kbd_disable_t    pckbd_disable;
  291 static kbd_read_t       pckbd_read;
  292 static kbd_check_t      pckbd_check;
  293 static kbd_read_char_t  pckbd_read_char;
  294 static kbd_check_char_t pckbd_check_char;
  295 static kbd_ioctl_t      pckbd_ioctl;
  296 static kbd_lock_t       pckbd_lock;
  297 static kbd_clear_state_t pckbd_clear_state;
  298 static kbd_get_state_t  pckbd_get_state;
  299 static kbd_set_state_t  pckbd_set_state;
  300 static kbd_poll_mode_t  pckbd_poll;
  301 
  302 keyboard_switch_t pckbdsw = {
  303         pckbd_probe,
  304         pckbd_init,
  305         pckbd_term,
  306         pckbd_intr,
  307         pckbd_test_if,
  308         pckbd_enable,
  309         pckbd_disable,
  310         pckbd_read,
  311         pckbd_check,
  312         pckbd_read_char,
  313         pckbd_check_char,
  314         pckbd_ioctl,
  315         pckbd_lock,
  316         pckbd_clear_state,
  317         pckbd_get_state,
  318         pckbd_set_state,
  319         genkbd_get_fkeystr,
  320         pckbd_poll,
  321         genkbd_diag,
  322 };
  323 
  324 KEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure);
  325 
  326 struct kbdc_softc {
  327     int port;                   /* base port address */
  328     int lock;                   /* FIXME: XXX not quite a semaphore... */
  329 }; 
  330 
  331 /* local functions */
  332 static int              probe_keyboard(KBDC kbdc, int flags);
  333 static int              init_keyboard(KBDC kbdc, int *type, int flags);
  334 static KBDC             kbdc_open(int port);
  335 static int              kbdc_lock(KBDC kbdc, int lock);
  336 static int              kbdc_data_ready(KBDC kbdc);
  337 static int              read_kbd_data(KBDC kbdc);
  338 static int              read_kbd_data_no_wait(KBDC kbdc);
  339 static int              wait_for_kbd_data(struct kbdc_softc *kbdc);
  340 
  341 /* local variables */
  342 
  343 /* the initial key map, accent map and fkey strings */
  344 #include <dev/kbd/kbdtables.h>
  345 
  346 /* structures for the default keyboard */
  347 static keyboard_t       default_kbd;
  348 static pckbd_state_t    default_kbd_state;
  349 static keymap_t         default_keymap;
  350 static accentmap_t      default_accentmap;
  351 static fkeytab_t        default_fkeytab[NUM_FKEYS];
  352 
  353 /* 
  354  * The back door to the keyboard driver!
  355  * This function is called by the console driver, via the kbdio module,
  356  * to tickle keyboard drivers when the low-level console is being initialized.
  357  * Almost nothing in the kernel has been initialied yet.  Try to probe
  358  * keyboards if possible.
  359  * NOTE: because of the way the low-level conole is initialized, this routine
  360  * may be called more than once!!
  361  */
  362 static int
  363 pckbd_configure(int flags)
  364 {
  365         keyboard_t *kbd;
  366         int arg[2];
  367         int i;
  368 
  369         /* XXX: a kludge to obtain the device configuration flags */
  370         if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) {
  371                 flags |= i;
  372                 /* if the driver is disabled, unregister the keyboard if any */
  373                 if (resource_int_value(DRIVER_NAME, 0, "disabled", &i) == 0
  374                     && i != 0) {
  375                         i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT);
  376                         if (i >= 0) {
  377                                 kbd = kbd_get_keyboard(i);
  378                                 kbd_unregister(kbd);
  379                                 kbd->kb_flags &= ~KB_REGISTERED;
  380                                 return 0;
  381                         }
  382                 }
  383         }
  384 
  385         /* probe the default keyboard */
  386         arg[0] = -1;
  387         arg[1] = -1;
  388         kbd = NULL;
  389         if (pckbd_probe(PC98KBD_DEFAULT, arg, flags))
  390                 return 0;
  391         if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags))
  392                 return 0;
  393 
  394         /* return the number of found keyboards */
  395         return 1;
  396 }
  397 
  398 /* low-level functions */
  399 
  400 /* detect a keyboard */
  401 static int
  402 pckbd_probe(int unit, void *arg, int flags)
  403 {
  404         KBDC kbdc;
  405         int *data = (int *)arg;
  406 
  407         if (unit != PC98KBD_DEFAULT)
  408                 return ENXIO;
  409         if (KBD_IS_PROBED(&default_kbd))
  410                 return 0;
  411 
  412         kbdc = kbdc_open(data[0]);
  413         if (kbdc == NULL)
  414                 return ENXIO;
  415         if (probe_keyboard(kbdc, flags)) {
  416                 if (flags & KB_CONF_FAIL_IF_NO_KBD)
  417                         return ENXIO;
  418         }
  419         return 0;
  420 }
  421 
  422 /* reset and initialize the device */
  423 static int
  424 pckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
  425 {
  426         keyboard_t *kbd;
  427         pckbd_state_t *state;
  428         keymap_t *keymap;
  429         accentmap_t *accmap;
  430         fkeytab_t *fkeymap;
  431         int fkeymap_size;
  432         int *data = (int *)arg;
  433 
  434         if (unit != PC98KBD_DEFAULT)                    /* shouldn't happen */
  435                 return ENXIO;
  436 
  437         *kbdp = kbd = &default_kbd;
  438         state = &default_kbd_state;
  439         if (!KBD_IS_PROBED(kbd)) {
  440                 keymap = &default_keymap;
  441                 accmap = &default_accentmap;
  442                 fkeymap = default_fkeytab;
  443                 fkeymap_size =
  444                         sizeof(default_fkeytab)/sizeof(default_fkeytab[0]);
  445 
  446                 state->kbdc = kbdc_open(data[0]);
  447                 if (state->kbdc == NULL)
  448                         return ENXIO;
  449                 kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags,
  450                                 data[0], IO_KBDSIZE);
  451                 bcopy(&key_map, keymap, sizeof(key_map));
  452                 bcopy(&accent_map, accmap, sizeof(accent_map));
  453                 bcopy(fkey_tab, fkeymap,
  454                       imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
  455                 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
  456                 kbd->kb_data = (void *)state;
  457 
  458                 if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */
  459                         if (flags & KB_CONF_FAIL_IF_NO_KBD)
  460                                 return ENXIO;
  461                 } else {
  462                         KBD_FOUND_DEVICE(kbd);
  463                 }
  464                 pckbd_clear_state(kbd);
  465                 state->ks_mode = K_XLATE;
  466                 KBD_PROBE_DONE(kbd);
  467         }
  468         if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
  469                 if (KBD_HAS_DEVICE(kbd)
  470                     && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
  471                     && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD))
  472                         return ENXIO;
  473                 pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
  474                 KBD_INIT_DONE(kbd);
  475         }
  476         if (!KBD_IS_CONFIGURED(kbd)) {
  477                 if (kbd_register(kbd) < 0)
  478                         return ENXIO;
  479                 KBD_CONFIG_DONE(kbd);
  480         }
  481 
  482         return 0;
  483 }
  484 
  485 /* finish using this keyboard */
  486 static int
  487 pckbd_term(keyboard_t *kbd)
  488 {
  489         kbd_unregister(kbd);
  490         return 0;
  491 }
  492 
  493 /* keyboard interrupt routine */
  494 static int
  495 pckbd_intr(keyboard_t *kbd, void *arg)
  496 {
  497         int c;
  498 
  499         if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
  500                 /* let the callback function to process the input */
  501                 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
  502                                             kbd->kb_callback.kc_arg);
  503         } else {
  504                 /* read and discard the input; no one is waiting for input */
  505                 do {
  506                         c = pckbd_read_char(kbd, FALSE);
  507                 } while (c != NOKEY);
  508         }
  509         return 0;
  510 }
  511 
  512 /* test the interface to the device */
  513 static int
  514 pckbd_test_if(keyboard_t *kbd)
  515 {
  516         return 0;
  517 }
  518 
  519 /* 
  520  * Enable the access to the device; until this function is called,
  521  * the client cannot read from the keyboard.
  522  */
  523 static int
  524 pckbd_enable(keyboard_t *kbd)
  525 {
  526         int s;
  527 
  528         s = spltty();
  529         KBD_ACTIVATE(kbd);
  530         splx(s);
  531         return 0;
  532 }
  533 
  534 /* disallow the access to the device */
  535 static int
  536 pckbd_disable(keyboard_t *kbd)
  537 {
  538         int s;
  539 
  540         s = spltty();
  541         KBD_DEACTIVATE(kbd);
  542         splx(s);
  543         return 0;
  544 }
  545 
  546 /* read one byte from the keyboard if it's allowed */
  547 static int
  548 pckbd_read(keyboard_t *kbd, int wait)
  549 {
  550         int c;
  551 
  552         if (wait)
  553                 c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc);
  554         else
  555                 c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc);
  556         if (c != -1)
  557                 ++kbd->kb_count;
  558         return (KBD_IS_ACTIVE(kbd) ? c : -1);
  559 }
  560 
  561 /* check if data is waiting */
  562 static int
  563 pckbd_check(keyboard_t *kbd)
  564 {
  565         if (!KBD_IS_ACTIVE(kbd))
  566                 return FALSE;
  567         return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc);
  568 }
  569 
  570 /* read char from the keyboard */
  571 static u_int
  572 pckbd_read_char(keyboard_t *kbd, int wait)
  573 {
  574         pckbd_state_t *state;
  575         u_int action;
  576         int scancode;
  577         int keycode;
  578 
  579         state = (pckbd_state_t *)kbd->kb_data;
  580 next_code:
  581         /* do we have a composed char to return? */
  582         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
  583                 action = state->ks_composed_char;
  584                 state->ks_composed_char = 0;
  585                 if (action > UCHAR_MAX)
  586                         return ERRKEY;
  587                 return action;
  588         }
  589 
  590         /* see if there is something in the keyboard port */
  591         if (wait) {
  592                 do {
  593                         scancode = read_kbd_data(state->kbdc);
  594                 } while (scancode == -1);
  595         } else {
  596                 scancode = read_kbd_data_no_wait(state->kbdc);
  597                 if (scancode == -1)
  598                         return NOKEY;
  599         }
  600         ++kbd->kb_count;
  601 
  602 #if 0
  603         printf("pckbd_read_char(): scancode:0x%x\n", scancode);
  604 #endif
  605 
  606         /* return the byte as is for the K_RAW mode */
  607         if (state->ks_mode == K_RAW)
  608                 return scancode;
  609 
  610         /* translate the scan code into a keycode */
  611         keycode = scancode & 0x7F;
  612         switch(scancode) {
  613         case 0xF3:      /* GRPH (compose key) released */
  614                 if (state->ks_flags & COMPOSE) {
  615                         state->ks_flags &= ~COMPOSE;
  616                         if (state->ks_composed_char > UCHAR_MAX)
  617                                 state->ks_composed_char = 0;
  618                 }
  619                 break;
  620         case 0x73:      /* GRPH (compose key) pressed */
  621                 if (!(state->ks_flags & COMPOSE)) {
  622                         state->ks_flags |= COMPOSE;
  623                         state->ks_composed_char = 0;
  624                 }
  625                 break;
  626         }
  627 
  628         /* return the key code in the K_CODE mode */
  629         if (state->ks_mode == K_CODE)
  630                 return (keycode | (scancode & 0x80));
  631 
  632         /* compose a character code */
  633         if (state->ks_flags & COMPOSE) {
  634                 switch (scancode) {
  635                 /* key pressed, process it */
  636                 case 0x42: case 0x43: case 0x44:        /* keypad 7,8,9 */
  637                         state->ks_composed_char *= 10;
  638                         state->ks_composed_char += scancode - 0x3B;
  639                         if (state->ks_composed_char > UCHAR_MAX)
  640                                 return ERRKEY;
  641                         goto next_code;
  642                 case 0x46: case 0x47: case 0x48:        /* keypad 4,5,6 */
  643                         state->ks_composed_char *= 10;
  644                         state->ks_composed_char += scancode - 0x42;
  645                         if (state->ks_composed_char > UCHAR_MAX)
  646                                 return ERRKEY;
  647                         goto next_code;
  648                 case 0x4A: case 0x4B: case 0x4C:        /* keypad 1,2,3 */
  649                         state->ks_composed_char *= 10;
  650                         state->ks_composed_char += scancode - 0x49;
  651                         if (state->ks_composed_char > UCHAR_MAX)
  652                                 return ERRKEY;
  653                         goto next_code;
  654                 case 0x4E:                              /* keypad 0 */
  655                         state->ks_composed_char *= 10;
  656                         if (state->ks_composed_char > UCHAR_MAX)
  657                                 return ERRKEY;
  658                         goto next_code;
  659 
  660                 /* key released, no interest here */
  661                 case 0xC2: case 0xC3: case 0xC4:        /* keypad 7,8,9 */
  662                 case 0xC6: case 0xC7: case 0xC8:        /* keypad 4,5,6 */
  663                 case 0xCA: case 0xCB: case 0xCC:        /* keypad 1,2,3 */
  664                 case 0xCE:                              /* keypad 0 */
  665                         goto next_code;
  666 
  667                 case 0x73:                              /* GRPH key */
  668                         break;
  669 
  670                 default:
  671                         if (state->ks_composed_char > 0) {
  672                                 state->ks_flags &= ~COMPOSE;
  673                                 state->ks_composed_char = 0;
  674                                 return ERRKEY;
  675                         }
  676                         break;
  677                 }
  678         }
  679 
  680         /* keycode to key action */
  681         action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
  682                                   &state->ks_state, &state->ks_accents);
  683         if (action == NOKEY)
  684                 goto next_code;
  685         else
  686                 return action;
  687 }
  688 
  689 /* check if char is waiting */
  690 static int
  691 pckbd_check_char(keyboard_t *kbd)
  692 {
  693         pckbd_state_t *state;
  694 
  695         if (!KBD_IS_ACTIVE(kbd))
  696                 return FALSE;
  697         state = (pckbd_state_t *)kbd->kb_data;
  698         if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
  699                 return TRUE;
  700         return kbdc_data_ready(state->kbdc);
  701 }
  702 
  703 /* some useful control functions */
  704 static int
  705 pckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
  706 {
  707         pckbd_state_t *state = kbd->kb_data;
  708         int s;
  709         int i;
  710 
  711         s = spltty();
  712         switch (cmd) {
  713 
  714         case KDGKBMODE:         /* get keyboard mode */
  715                 *(int *)arg = state->ks_mode;
  716                 break;
  717         case KDSKBMODE:         /* set keyboard mode */
  718                 switch (*(int *)arg) {
  719                 case K_XLATE:
  720                         if (state->ks_mode != K_XLATE) {
  721                                 /* make lock key state and LED state match */
  722                                 state->ks_state &= ~LOCK_MASK;
  723                                 state->ks_state |= KBD_LED_VAL(kbd);
  724                         }
  725                         /* FALLTHROUGH */
  726                 case K_RAW:
  727                 case K_CODE:
  728                         if (state->ks_mode != *(int *)arg) {
  729                                 pckbd_clear_state(kbd);
  730                                 state->ks_mode = *(int *)arg;
  731                         }
  732                         break;
  733                 default:
  734                         splx(s);
  735                         return EINVAL;
  736                 }
  737                 break;
  738 
  739         case KDGETLED:          /* get keyboard LED */
  740                 *(int *)arg = KBD_LED_VAL(kbd);
  741                 break;
  742         case KDSETLED:          /* set keyboard LED */
  743                 /* NOTE: lock key state in ks_state won't be changed */
  744                 if (*(int *)arg & ~LOCK_MASK) {
  745                         splx(s);
  746                         return EINVAL;
  747                 }
  748                 i = *(int *)arg;
  749                 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
  750                 if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
  751                         if (i & ALKED)
  752                                 i |= CLKED;
  753                         else
  754                                 i &= ~CLKED;
  755                 }
  756                 KBD_LED_VAL(kbd) = *(int *)arg;
  757                 break;
  758 
  759         case KDGKBSTATE:        /* get lock key state */
  760                 *(int *)arg = state->ks_state & LOCK_MASK;
  761                 break;
  762         case KDSKBSTATE:        /* set lock key state */
  763                 if (*(int *)arg & ~LOCK_MASK) {
  764                         splx(s);
  765                         return EINVAL;
  766                 }
  767                 state->ks_state &= ~LOCK_MASK;
  768                 state->ks_state |= *(int *)arg;
  769                 splx(s);
  770                 /* set LEDs and quit */
  771                 return pckbd_ioctl(kbd, KDSETLED, arg);
  772 
  773         case KDSETRAD:          /* set keyboard repeat rate (old interface)*/
  774                 break;
  775         case KDSETREPEAT:       /* set keyboard repeat rate (new interface) */
  776                 break;
  777 
  778         case PIO_KEYMAP:        /* set keyboard translation table */
  779         case PIO_KEYMAPENT:     /* set keyboard translation table entry */
  780         case PIO_DEADKEYMAP:    /* set accent key translation table */
  781                 state->ks_accents = 0;
  782                 /* FALLTHROUGH */
  783         default:
  784                 splx(s);
  785                 return genkbd_commonioctl(kbd, cmd, arg);
  786         }
  787 
  788         splx(s);
  789         return 0;
  790 }
  791 
  792 /* lock the access to the keyboard */
  793 static int
  794 pckbd_lock(keyboard_t *kbd, int lock)
  795 {
  796         return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock);
  797 }
  798 
  799 /* clear the internal state of the keyboard */
  800 static void
  801 pckbd_clear_state(keyboard_t *kbd)
  802 {
  803         pckbd_state_t *state;
  804 
  805         state = (pckbd_state_t *)kbd->kb_data;
  806         state->ks_flags = 0;
  807         state->ks_state &= LOCK_MASK;   /* preserve locking key state */
  808         state->ks_accents = 0;
  809         state->ks_composed_char = 0;
  810 }
  811 
  812 /* save the internal state */
  813 static int
  814 pckbd_get_state(keyboard_t *kbd, void *buf, size_t len)
  815 {
  816         if (len == 0)
  817                 return sizeof(pckbd_state_t);
  818         if (len < sizeof(pckbd_state_t))
  819                 return -1;
  820         bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t));
  821         return 0;
  822 }
  823 
  824 /* set the internal state */
  825 static int
  826 pckbd_set_state(keyboard_t *kbd, void *buf, size_t len)
  827 {
  828         if (len < sizeof(pckbd_state_t))
  829                 return ENOMEM;
  830         if (((pckbd_state_t *)kbd->kb_data)->kbdc
  831                 != ((pckbd_state_t *)buf)->kbdc)
  832                 return ENOMEM;
  833         bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t));
  834         return 0;
  835 }
  836 
  837 /* set polling mode */
  838 static int
  839 pckbd_poll(keyboard_t *kbd, int on)
  840 {
  841         return 0;
  842 }
  843 
  844 /* local functions */
  845 
  846 static int
  847 probe_keyboard(KBDC kbdc, int flags)
  848 {
  849         return 0;
  850 }
  851 
  852 static int
  853 init_keyboard(KBDC kbdc, int *type, int flags)
  854 {
  855         *type = KB_OTHER;
  856         return 0;
  857 }
  858 
  859 /* keyboard I/O routines */
  860 
  861 /* retry count */
  862 #ifndef KBD_MAXRETRY
  863 #define KBD_MAXRETRY    3
  864 #endif
  865 
  866 /* timing parameters */
  867 #ifndef KBD_RESETDELAY
  868 #define KBD_RESETDELAY  200     /* wait 200msec after kbd/mouse reset */
  869 #endif
  870 #ifndef KBD_MAXWAIT
  871 #define KBD_MAXWAIT     5       /* wait 5 times at most after reset */
  872 #endif
  873 
  874 /* I/O recovery time */
  875 #define KBDC_DELAYTIME  37
  876 #define KBDD_DELAYTIME  37
  877 
  878 /* I/O ports */
  879 #define KBD_STATUS_PORT         2       /* status port, read */
  880 #define KBD_DATA_PORT           0       /* data port, read */
  881 
  882 /* status bits (KBD_STATUS_PORT) */
  883 #define KBDS_BUFFER_FULL        0x0002
  884 
  885 /* macros */
  886 
  887 #define kbdcp(p)                ((struct kbdc_softc *)(p))
  888 
  889 /* local variables */
  890 
  891 static struct kbdc_softc kbdc_softc[1] = { { 0 }, };
  892 
  893 /* associate a port number with a KBDC */
  894 
  895 static KBDC
  896 kbdc_open(int port)
  897 {
  898         if (port <= 0)
  899                 port = IO_KBD;
  900 
  901         /* PC-98 has only one keyboard I/F */
  902         kbdc_softc[0].port = port;
  903         kbdc_softc[0].lock = FALSE;
  904         return (KBDC)&kbdc_softc[0];
  905 }
  906 
  907 /* set/reset polling lock */
  908 static int 
  909 kbdc_lock(KBDC p, int lock)
  910 {
  911     int prevlock;
  912 
  913     prevlock = kbdcp(p)->lock;
  914     kbdcp(p)->lock = lock;
  915 
  916     return (prevlock != lock);
  917 }
  918 
  919 /* check if any data is waiting to be processed */
  920 static int
  921 kbdc_data_ready(KBDC p)
  922 {
  923         return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL);
  924 }
  925 
  926 /* wait for data from the keyboard */
  927 static int
  928 wait_for_kbd_data(struct kbdc_softc *kbdc)
  929 {
  930     /* CPU will stay inside the loop for 200msec at most */
  931     int retry = 10000;
  932     int port = kbdc->port;
  933 
  934     while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) {
  935         DELAY(KBDD_DELAYTIME);
  936         DELAY(KBDC_DELAYTIME);
  937         if (--retry < 0)
  938             return 0;
  939     }
  940     DELAY(KBDD_DELAYTIME);
  941     return 1;
  942 }
  943 
  944 /* read one byte from the keyboard */
  945 static int
  946 read_kbd_data(KBDC p)
  947 {
  948     if (!wait_for_kbd_data(kbdcp(p)))
  949         return -1;              /* timeout */
  950     DELAY(KBDC_DELAYTIME);
  951     return inb(kbdcp(p)->port + KBD_DATA_PORT);
  952 }
  953 
  954 /* read one byte from the keyboard, but return immediately if 
  955  * no data is waiting
  956  */
  957 static int
  958 read_kbd_data_no_wait(KBDC p)
  959 {
  960     if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) {
  961         DELAY(KBDD_DELAYTIME);
  962         return inb(kbdcp(p)->port + KBD_DATA_PORT);
  963     }
  964     return -1;          /* no data */
  965 }

Cache object: f3abdcf1aaa8c96d451817a63b3969c6


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