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

Cache object: d3e6357bc070cf66b95ef1fd90cf2443


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