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

Cache object: cbeee0af4cc5a2b40970ff2d33862fa5


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