142421Syokota/*- 242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 342421Syokota * All rights reserved. 442421Syokota * 542421Syokota * Redistribution and use in source and binary forms, with or without 642421Syokota * modification, are permitted provided that the following conditions 742421Syokota * are met: 842421Syokota * 1. Redistributions of source code must retain the above copyright 942421Syokota * notice, this list of conditions and the following disclaimer as 1042421Syokota * the first lines of this file unmodified. 1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright 1242421Syokota * notice, this list of conditions and the following disclaimer in the 1342421Syokota * documentation and/or other materials provided with the distribution. 1442421Syokota * 1542421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1642421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1742421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1842421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1942421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2042421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2142421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2242421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2342421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2442421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2542421Syokota * 2642421Syokota */ 2742421Syokota 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD$"); 30119418Sobrien 31162711Sru#include "opt_compat.h" 3242421Syokota#include "opt_kbd.h" 3344628Syokota#include "opt_atkbd.h" 3442421Syokota 3542421Syokota#include <sys/param.h> 3642421Syokota#include <sys/systm.h> 3742421Syokota#include <sys/kernel.h> 3847336Syokota#include <sys/bus.h> 39147271Smarius#include <sys/eventhandler.h> 4042421Syokota#include <sys/proc.h> 41114216Skan#include <sys/limits.h> 4242421Syokota#include <sys/malloc.h> 4342421Syokota 4458271Syokota#include <machine/bus.h> 4558271Syokota#include <machine/resource.h> 4658271Syokota 47197501Sjkim#if defined(__i386__) || defined(__amd64__) 4855731Syokota#include <machine/md_var.h> 4955731Syokota#include <machine/psl.h> 50197444Sjkim#include <compat/x86bios/x86bios.h> 5155731Syokota#include <machine/pc/bios.h> 5255731Syokota 5355731Syokota#include <vm/vm.h> 5455731Syokota#include <vm/pmap.h> 55130312Sjhb#include <vm/vm_param.h> 56147271Smarius 57147271Smarius#include <isa/isareg.h> 58197384Sdelphij#endif /* __i386__ || __amd64__ */ 5955731Syokota 6080040Syokota#include <sys/kbio.h> 6142421Syokota#include <dev/kbd/kbdreg.h> 62147271Smarius#include <dev/atkbdc/atkbdreg.h> 63147271Smarius#include <dev/atkbdc/atkbdcreg.h> 6442421Syokota 6542421Syokotastatic timeout_t atkbd_timeout; 66147271Smariusstatic void atkbd_shutdown_final(void *v); 6742421Syokota 6842421Syokotaint 69246045Simpatkbd_probe_unit(device_t dev, int irq, int flags) 7042421Syokota{ 7142421Syokota keyboard_switch_t *sw; 7242421Syokota int args[2]; 7344628Syokota int error; 7442421Syokota 7542421Syokota sw = kbd_get_switch(ATKBD_DRIVER_NAME); 7642421Syokota if (sw == NULL) 7742421Syokota return ENXIO; 7842421Syokota 79246045Simp args[0] = device_get_unit(device_get_parent(dev)); 8042421Syokota args[1] = irq; 81246045Simp error = (*sw->probe)(device_get_unit(dev), args, flags); 8244628Syokota if (error) 8344628Syokota return error; 8444628Syokota return 0; 8542421Syokota} 8642421Syokota 8742421Syokotaint 88246045Simpatkbd_attach_unit(device_t dev, keyboard_t **kbd, int irq, int flags) 8942421Syokota{ 9042421Syokota keyboard_switch_t *sw; 9144628Syokota int args[2]; 9242421Syokota int error; 93246045Simp int unit; 9442421Syokota 9542421Syokota sw = kbd_get_switch(ATKBD_DRIVER_NAME); 9642421Syokota if (sw == NULL) 9742421Syokota return ENXIO; 9842421Syokota 9942421Syokota /* reset, initialize and enable the device */ 100246045Simp unit = device_get_unit(dev); 101246045Simp args[0] = device_get_unit(device_get_parent(dev)); 10244628Syokota args[1] = irq; 10350154Syokota *kbd = NULL; 10444628Syokota error = (*sw->probe)(unit, args, flags); 10542421Syokota if (error) 10644628Syokota return error; 10750154Syokota error = (*sw->init)(unit, kbd, args, flags); 10844628Syokota if (error) 10944628Syokota return error; 11050154Syokota (*sw->enable)(*kbd); 11142421Syokota 11242421Syokota#ifdef KBD_INSTALL_CDEV 11342421Syokota /* attach a virtual keyboard cdev */ 11450154Syokota error = kbd_attach(*kbd); 11542421Syokota if (error) 11642421Syokota return error; 11742421Syokota#endif 11842421Syokota 11942421Syokota /* 12042421Syokota * This is a kludge to compensate for lost keyboard interrupts. 12142421Syokota * A similar code used to be in syscons. See below. XXX 12242421Syokota */ 12350154Syokota atkbd_timeout(*kbd); 12442421Syokota 12542421Syokota if (bootverbose) 12650154Syokota (*sw->diag)(*kbd, bootverbose); 127147271Smarius 128147271Smarius EVENTHANDLER_REGISTER(shutdown_final, atkbd_shutdown_final, *kbd, 129147271Smarius SHUTDOWN_PRI_DEFAULT); 130147271Smarius 13142421Syokota return 0; 13242421Syokota} 13342421Syokota 13442421Syokotastatic void 13542421Syokotaatkbd_timeout(void *arg) 13642421Syokota{ 13742421Syokota keyboard_t *kbd; 13842421Syokota int s; 13942421Syokota 14056334Syokota /* 14156334Syokota * The original text of the following comments are extracted 14256334Syokota * from syscons.c (1.287) 14356334Syokota * 14442421Syokota * With release 2.1 of the Xaccel server, the keyboard is left 14542421Syokota * hanging pretty often. Apparently an interrupt from the 14642421Syokota * keyboard is lost, and I don't know why (yet). 14756334Syokota * This ugly hack calls the low-level interrupt routine if input 14856334Syokota * is ready for the keyboard and conveniently hides the problem. XXX 14956334Syokota * 15056334Syokota * Try removing anything stuck in the keyboard controller; whether 15156334Syokota * it's a keyboard scan code or mouse data. The low-level 15256334Syokota * interrupt routine doesn't read the mouse data directly, 15356334Syokota * but the keyboard controller driver will, as a side effect. 15442421Syokota */ 15542421Syokota /* 15656334Syokota * And here is bde's original comment about this: 15756334Syokota * 15856334Syokota * This is necessary to handle edge triggered interrupts - if we 15956334Syokota * returned when our IRQ is high due to unserviced input, then there 16056334Syokota * would be no more keyboard IRQs until the keyboard is reset by 16156334Syokota * external powers. 16256334Syokota * 16356334Syokota * The keyboard apparently unwedges the irq in most cases. 16442421Syokota */ 16542421Syokota s = spltty(); 16642421Syokota kbd = (keyboard_t *)arg; 167174984Swkoszek if (kbdd_lock(kbd, TRUE)) { 16842421Syokota /* 16942421Syokota * We have seen the lock flag is not set. Let's reset 17042421Syokota * the flag early, otherwise the LED update routine fails 17142421Syokota * which may want the lock during the interrupt routine. 17242421Syokota */ 173174984Swkoszek kbdd_lock(kbd, FALSE); 174174984Swkoszek if (kbdd_check_char(kbd)) 175174984Swkoszek kbdd_intr(kbd, NULL); 17642421Syokota } 17742421Syokota splx(s); 17842421Syokota timeout(atkbd_timeout, arg, hz/10); 17942421Syokota} 18042421Syokota 18142421Syokota/* LOW-LEVEL */ 18242421Syokota 18342421Syokota#define ATKBD_DEFAULT 0 18442421Syokota 18542421Syokotatypedef struct atkbd_state { 18642421Syokota KBDC kbdc; /* keyboard controller */ 18742421Syokota int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 18842421Syokota int ks_flags; /* flags */ 18942421Syokota#define COMPOSE (1 << 0) 19044628Syokota int ks_polling; 19142421Syokota int ks_state; /* shift/lock key state */ 19242421Syokota int ks_accents; /* accent key index (> 0) */ 19342421Syokota u_int ks_composed_char; /* composed char code (> 0) */ 19442421Syokota u_char ks_prefix; /* AT scan code prefix */ 19542421Syokota} atkbd_state_t; 19642421Syokota 19742421Syokota/* keyboard driver declaration */ 19842421Syokotastatic int atkbd_configure(int flags); 19942421Syokotastatic kbd_probe_t atkbd_probe; 20042421Syokotastatic kbd_init_t atkbd_init; 20142421Syokotastatic kbd_term_t atkbd_term; 20242421Syokotastatic kbd_intr_t atkbd_intr; 20342421Syokotastatic kbd_test_if_t atkbd_test_if; 20442421Syokotastatic kbd_enable_t atkbd_enable; 20542421Syokotastatic kbd_disable_t atkbd_disable; 20642421Syokotastatic kbd_read_t atkbd_read; 20742421Syokotastatic kbd_check_t atkbd_check; 20842421Syokotastatic kbd_read_char_t atkbd_read_char; 20942421Syokotastatic kbd_check_char_t atkbd_check_char; 21042421Syokotastatic kbd_ioctl_t atkbd_ioctl; 21142421Syokotastatic kbd_lock_t atkbd_lock; 21242421Syokotastatic kbd_clear_state_t atkbd_clear_state; 21342421Syokotastatic kbd_get_state_t atkbd_get_state; 21442421Syokotastatic kbd_set_state_t atkbd_set_state; 21544628Syokotastatic kbd_poll_mode_t atkbd_poll; 21642421Syokota 217114293Smarkmstatic keyboard_switch_t atkbdsw = { 21842421Syokota atkbd_probe, 21942421Syokota atkbd_init, 22042421Syokota atkbd_term, 22142421Syokota atkbd_intr, 22242421Syokota atkbd_test_if, 22342421Syokota atkbd_enable, 22442421Syokota atkbd_disable, 22542421Syokota atkbd_read, 22642421Syokota atkbd_check, 22742421Syokota atkbd_read_char, 22842421Syokota atkbd_check_char, 22942421Syokota atkbd_ioctl, 23042421Syokota atkbd_lock, 23142421Syokota atkbd_clear_state, 23242421Syokota atkbd_get_state, 23342421Syokota atkbd_set_state, 23442421Syokota genkbd_get_fkeystr, 23544628Syokota atkbd_poll, 23642421Syokota genkbd_diag, 23742421Syokota}; 23842421Syokota 23942421SyokotaKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); 24042421Syokota 24142421Syokota/* local functions */ 24255731Syokotastatic int get_typematic(keyboard_t *kbd); 24342421Syokotastatic int setup_kbd_port(KBDC kbdc, int port, int intr); 24442421Syokotastatic int get_kbd_echo(KBDC kbdc); 24542421Syokotastatic int probe_keyboard(KBDC kbdc, int flags); 24642421Syokotastatic int init_keyboard(KBDC kbdc, int *type, int flags); 24742421Syokotastatic int write_kbd(KBDC kbdc, int command, int data); 24842421Syokotastatic int get_kbd_id(KBDC kbdc); 24944628Syokotastatic int typematic(int delay, int rate); 25054543Syokotastatic int typematic_delay(int delay); 25154543Syokotastatic int typematic_rate(int rate); 25242421Syokota 25342421Syokota/* local variables */ 25442421Syokota 25542421Syokota/* the initial key map, accent map and fkey strings */ 25644628Syokota#ifdef ATKBD_DFLT_KEYMAP 25744628Syokota#define KBD_DFLT_KEYMAP 25844628Syokota#include "atkbdmap.h" 25944628Syokota#endif 26042831Syokota#include <dev/kbd/kbdtables.h> 26142421Syokota 26242421Syokota/* structures for the default keyboard */ 26342421Syokotastatic keyboard_t default_kbd; 26442421Syokotastatic atkbd_state_t default_kbd_state; 26542421Syokotastatic keymap_t default_keymap; 26642421Syokotastatic accentmap_t default_accentmap; 26742421Syokotastatic fkeytab_t default_fkeytab[NUM_FKEYS]; 26842421Syokota 26942421Syokota/* 27042421Syokota * The back door to the keyboard driver! 27142421Syokota * This function is called by the console driver, via the kbdio module, 27242421Syokota * to tickle keyboard drivers when the low-level console is being initialized. 27342421Syokota * Almost nothing in the kernel has been initialied yet. Try to probe 27442421Syokota * keyboards if possible. 27594228Sasmodai * NOTE: because of the way the low-level console is initialized, this routine 27642421Syokota * may be called more than once!! 27742421Syokota */ 27842421Syokotastatic int 27942421Syokotaatkbd_configure(int flags) 28042421Syokota{ 28142421Syokota keyboard_t *kbd; 28242421Syokota int arg[2]; 28344628Syokota int i; 28442421Syokota 285158041Ssobomax /* 286158041Ssobomax * Probe the keyboard controller, if not present or if the driver 287158041Ssobomax * is disabled, unregister the keyboard if any. 288158041Ssobomax */ 289158041Ssobomax if (atkbdc_configure() != 0 || 290158041Ssobomax resource_disabled("atkbd", ATKBD_DEFAULT)) { 29146764Syokota i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT); 29246764Syokota if (i >= 0) { 29346764Syokota kbd = kbd_get_keyboard(i); 29446764Syokota kbd_unregister(kbd); 29546764Syokota kbd->kb_flags &= ~KB_REGISTERED; 29644628Syokota } 29748878Syokota return 0; 29844628Syokota } 29945720Speter 30046764Syokota /* XXX: a kludge to obtain the device configuration flags */ 30146764Syokota if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0) 30246764Syokota flags |= i; 30346764Syokota 30442421Syokota /* probe the default keyboard */ 30542421Syokota arg[0] = -1; 30642421Syokota arg[1] = -1; 30744628Syokota kbd = NULL; 30844628Syokota if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) 30942421Syokota return 0; 31044628Syokota if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) 31144628Syokota return 0; 31242421Syokota 31344628Syokota /* return the number of found keyboards */ 31444628Syokota return 1; 31544628Syokota} 31644628Syokota 31744628Syokota/* low-level functions */ 31844628Syokota 31944628Syokota/* detect a keyboard */ 32044628Syokotastatic int 32144628Syokotaatkbd_probe(int unit, void *arg, int flags) 32244628Syokota{ 32344628Syokota KBDC kbdc; 32458271Syokota int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 32544628Syokota 32644628Syokota /* XXX */ 32744628Syokota if (unit == ATKBD_DEFAULT) { 32844628Syokota if (KBD_IS_PROBED(&default_kbd)) 32942421Syokota return 0; 33042421Syokota } 33142421Syokota 33258271Syokota kbdc = atkbdc_open(data[0]); 33344628Syokota if (kbdc == NULL) 33444628Syokota return ENXIO; 33544628Syokota if (probe_keyboard(kbdc, flags)) { 33644628Syokota if (flags & KB_CONF_FAIL_IF_NO_KBD) 33744628Syokota return ENXIO; 33842421Syokota } 33944628Syokota return 0; 34042421Syokota} 34142421Syokota 34244628Syokota/* reset and initialize the device */ 34342421Syokotastatic int 34444628Syokotaatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 34542421Syokota{ 34642421Syokota keyboard_t *kbd; 34742421Syokota atkbd_state_t *state; 34842421Syokota keymap_t *keymap; 34942421Syokota accentmap_t *accmap; 35042421Syokota fkeytab_t *fkeymap; 35142421Syokota int fkeymap_size; 35255731Syokota int delay[2]; 35358271Syokota int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 354142569Ssam int error, needfree; 35542421Syokota 35642421Syokota /* XXX */ 35742421Syokota if (unit == ATKBD_DEFAULT) { 35842421Syokota *kbdp = kbd = &default_kbd; 35944628Syokota if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) 36042421Syokota return 0; 36142421Syokota state = &default_kbd_state; 36242421Syokota keymap = &default_keymap; 36342421Syokota accmap = &default_accentmap; 36442421Syokota fkeymap = default_fkeytab; 36542421Syokota fkeymap_size = 36642421Syokota sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 367142569Ssam needfree = 0; 36842421Syokota } else if (*kbdp == NULL) { 36969781Sdwmalone *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO); 37069781Sdwmalone state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO); 371142569Ssam /* NB: these will always be initialized 'cuz !KBD_IS_PROBED */ 37242421Syokota keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); 37342421Syokota accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); 37442421Syokota fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); 37542421Syokota fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 376142569Ssam needfree = 1; 37769781Sdwmalone if ((kbd == NULL) || (state == NULL) || (keymap == NULL) 37869781Sdwmalone || (accmap == NULL) || (fkeymap == NULL)) { 379142569Ssam error = ENOMEM; 380142569Ssam goto bad; 38142421Syokota } 38244628Syokota } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 38342421Syokota return 0; 38442421Syokota } else { 38542421Syokota kbd = *kbdp; 38642421Syokota state = (atkbd_state_t *)kbd->kb_data; 38742421Syokota bzero(state, sizeof(*state)); 38842421Syokota keymap = kbd->kb_keymap; 38942421Syokota accmap = kbd->kb_accentmap; 39042421Syokota fkeymap = kbd->kb_fkeytab; 39142421Syokota fkeymap_size = kbd->kb_fkeytab_size; 392142569Ssam needfree = 0; 39342421Syokota } 39442421Syokota 39544628Syokota if (!KBD_IS_PROBED(kbd)) { 39658271Syokota state->kbdc = atkbdc_open(data[0]); 397142569Ssam if (state->kbdc == NULL) { 398142569Ssam error = ENXIO; 399142569Ssam goto bad; 400142569Ssam } 40144628Syokota kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 40258271Syokota 0, 0); 40344628Syokota bcopy(&key_map, keymap, sizeof(key_map)); 40444628Syokota bcopy(&accent_map, accmap, sizeof(accent_map)); 40544628Syokota bcopy(fkey_tab, fkeymap, 406246045Simp imin(fkeymap_size * sizeof(fkeymap[0]), sizeof(fkey_tab))); 40744628Syokota kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 40844628Syokota kbd->kb_data = (void *)state; 40944628Syokota 41044628Syokota if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ 411142569Ssam if (flags & KB_CONF_FAIL_IF_NO_KBD) { 412142569Ssam error = ENXIO; 413142569Ssam goto bad; 414142569Ssam } 41544628Syokota } else { 41644628Syokota KBD_FOUND_DEVICE(kbd); 41744628Syokota } 41844628Syokota atkbd_clear_state(kbd); 41944628Syokota state->ks_mode = K_XLATE; 42044628Syokota /* 42144628Syokota * FIXME: set the initial value for lock keys in ks_state 42244628Syokota * according to the BIOS data? 42344628Syokota */ 42444628Syokota KBD_PROBE_DONE(kbd); 42542421Syokota } 42644628Syokota if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 42749820Syokota kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 42842421Syokota if (KBD_HAS_DEVICE(kbd) 429246045Simp && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 430246045Simp && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { 431117513Ssimokawa kbd_unregister(kbd); 432142569Ssam error = ENXIO; 433142569Ssam goto bad; 434117513Ssimokawa } 43544628Syokota atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 43655731Syokota get_typematic(kbd); 43755731Syokota delay[0] = kbd->kb_delay1; 43855731Syokota delay[1] = kbd->kb_delay2; 43955731Syokota atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 44042421Syokota KBD_INIT_DONE(kbd); 44142421Syokota } 44242421Syokota if (!KBD_IS_CONFIGURED(kbd)) { 443142569Ssam if (kbd_register(kbd) < 0) { 444142569Ssam error = ENXIO; 445142569Ssam goto bad; 446142569Ssam } 44742421Syokota KBD_CONFIG_DONE(kbd); 44842421Syokota } 44942421Syokota 45042421Syokota return 0; 451142569Ssambad: 452142569Ssam if (needfree) { 453142569Ssam if (state != NULL) 454142569Ssam free(state, M_DEVBUF); 455142569Ssam if (keymap != NULL) 456142569Ssam free(keymap, M_DEVBUF); 457142569Ssam if (accmap != NULL) 458142569Ssam free(accmap, M_DEVBUF); 459142569Ssam if (fkeymap != NULL) 460142569Ssam free(fkeymap, M_DEVBUF); 461142569Ssam if (kbd != NULL) { 462142569Ssam free(kbd, M_DEVBUF); 463142569Ssam *kbdp = NULL; /* insure ref doesn't leak to caller */ 464142569Ssam } 465142569Ssam } 466142569Ssam return error; 46742421Syokota} 46842421Syokota 46942421Syokota/* finish using this keyboard */ 47042421Syokotastatic int 47142421Syokotaatkbd_term(keyboard_t *kbd) 47242421Syokota{ 47342421Syokota kbd_unregister(kbd); 47442421Syokota return 0; 47542421Syokota} 47642421Syokota 47742421Syokota/* keyboard interrupt routine */ 47842421Syokotastatic int 47944628Syokotaatkbd_intr(keyboard_t *kbd, void *arg) 48042421Syokota{ 481191164Semax atkbd_state_t *state = (atkbd_state_t *)kbd->kb_data; 48255731Syokota int delay[2]; 48342421Syokota int c; 48442421Syokota 485163687Sru if (!KBD_HAS_DEVICE(kbd)) { 486163687Sru /* 487163687Sru * The keyboard was not detected before; 488163687Sru * it must have been reconnected! 489163687Sru */ 490246045Simp init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config); 491163687Sru KBD_FOUND_DEVICE(kbd); 492163687Sru atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 493163687Sru get_typematic(kbd); 494163687Sru delay[0] = kbd->kb_delay1; 495163687Sru delay[1] = kbd->kb_delay2; 496163687Sru atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 497163687Sru } 498163687Sru 499191164Semax if (state->ks_polling) 500191164Semax return 0; 501191164Semax 50242421Syokota if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 50342421Syokota /* let the callback function to process the input */ 50442421Syokota (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 50542421Syokota kbd->kb_callback.kc_arg); 50642421Syokota } else { 50742421Syokota /* read and discard the input; no one is waiting for input */ 50842421Syokota do { 50942421Syokota c = atkbd_read_char(kbd, FALSE); 51042421Syokota } while (c != NOKEY); 51142421Syokota } 51242421Syokota return 0; 51342421Syokota} 51442421Syokota 51542421Syokota/* test the interface to the device */ 51642421Syokotastatic int 51742421Syokotaatkbd_test_if(keyboard_t *kbd) 51842421Syokota{ 51942421Syokota int error; 52042421Syokota int s; 52142421Syokota 52242421Syokota error = 0; 52342421Syokota empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10); 52442421Syokota s = spltty(); 52542421Syokota if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc)) 52642421Syokota error = EIO; 52742421Syokota else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0) 52842421Syokota error = EIO; 52942421Syokota splx(s); 53042421Syokota 53142421Syokota return error; 53242421Syokota} 53342421Syokota 53442421Syokota/* 53542421Syokota * Enable the access to the device; until this function is called, 53642421Syokota * the client cannot read from the keyboard. 53742421Syokota */ 53842421Syokotastatic int 53942421Syokotaatkbd_enable(keyboard_t *kbd) 54042421Syokota{ 54142421Syokota int s; 54242421Syokota 54342421Syokota s = spltty(); 54442421Syokota KBD_ACTIVATE(kbd); 54542421Syokota splx(s); 54642421Syokota return 0; 54742421Syokota} 54842421Syokota 54942421Syokota/* disallow the access to the device */ 55042421Syokotastatic int 55142421Syokotaatkbd_disable(keyboard_t *kbd) 55242421Syokota{ 55342421Syokota int s; 55442421Syokota 55542421Syokota s = spltty(); 55642421Syokota KBD_DEACTIVATE(kbd); 55742421Syokota splx(s); 55842421Syokota return 0; 55942421Syokota} 56042421Syokota 56142421Syokota/* read one byte from the keyboard if it's allowed */ 56242421Syokotastatic int 56342421Syokotaatkbd_read(keyboard_t *kbd, int wait) 56442421Syokota{ 56542421Syokota int c; 56642421Syokota 56742421Syokota if (wait) 56842421Syokota c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc); 56942421Syokota else 57042421Syokota c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc); 57154382Syokota if (c != -1) 57254382Syokota ++kbd->kb_count; 57342421Syokota return (KBD_IS_ACTIVE(kbd) ? c : -1); 57442421Syokota} 57542421Syokota 57642421Syokota/* check if data is waiting */ 57742421Syokotastatic int 57842421Syokotaatkbd_check(keyboard_t *kbd) 57942421Syokota{ 58042421Syokota if (!KBD_IS_ACTIVE(kbd)) 58142421Syokota return FALSE; 58242421Syokota return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc); 58342421Syokota} 58442421Syokota 58542421Syokota/* read char from the keyboard */ 58642421Syokotastatic u_int 58742421Syokotaatkbd_read_char(keyboard_t *kbd, int wait) 58842421Syokota{ 58942421Syokota atkbd_state_t *state; 59042421Syokota u_int action; 59142421Syokota int scancode; 59242421Syokota int keycode; 59342421Syokota 59442421Syokota state = (atkbd_state_t *)kbd->kb_data; 59542421Syokotanext_code: 59642421Syokota /* do we have a composed char to return? */ 59742421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 59842421Syokota action = state->ks_composed_char; 59942421Syokota state->ks_composed_char = 0; 60042421Syokota if (action > UCHAR_MAX) 60142421Syokota return ERRKEY; 60242421Syokota return action; 60342421Syokota } 60442421Syokota 60542421Syokota /* see if there is something in the keyboard port */ 60642421Syokota if (wait) { 60742421Syokota do { 60842421Syokota scancode = read_kbd_data(state->kbdc); 60942421Syokota } while (scancode == -1); 61042421Syokota } else { 61142421Syokota scancode = read_kbd_data_no_wait(state->kbdc); 61242421Syokota if (scancode == -1) 61342421Syokota return NOKEY; 61442421Syokota } 61554382Syokota ++kbd->kb_count; 61642421Syokota 61754382Syokota#if KBDIO_DEBUG >= 10 61854382Syokota printf("atkbd_read_char(): scancode:0x%x\n", scancode); 61954382Syokota#endif 62054382Syokota 62142421Syokota /* return the byte as is for the K_RAW mode */ 62242421Syokota if (state->ks_mode == K_RAW) 62342421Syokota return scancode; 62442421Syokota 62542421Syokota /* translate the scan code into a keycode */ 62642421Syokota keycode = scancode & 0x7F; 62742421Syokota switch (state->ks_prefix) { 62842421Syokota case 0x00: /* normal scancode */ 62942421Syokota switch(scancode) { 63042421Syokota case 0xB8: /* left alt (compose key) released */ 63142421Syokota if (state->ks_flags & COMPOSE) { 63242421Syokota state->ks_flags &= ~COMPOSE; 63342421Syokota if (state->ks_composed_char > UCHAR_MAX) 63442421Syokota state->ks_composed_char = 0; 63542421Syokota } 63642421Syokota break; 63742421Syokota case 0x38: /* left alt (compose key) pressed */ 63842421Syokota if (!(state->ks_flags & COMPOSE)) { 63942421Syokota state->ks_flags |= COMPOSE; 64042421Syokota state->ks_composed_char = 0; 64142421Syokota } 64242421Syokota break; 64342421Syokota case 0xE0: 64442421Syokota case 0xE1: 64542421Syokota state->ks_prefix = scancode; 64642421Syokota goto next_code; 64742421Syokota } 64842421Syokota break; 649246045Simp case 0xE0: /* 0xE0 prefix */ 65042421Syokota state->ks_prefix = 0; 65142421Syokota switch (keycode) { 65242421Syokota case 0x1C: /* right enter key */ 65342421Syokota keycode = 0x59; 65442421Syokota break; 65542421Syokota case 0x1D: /* right ctrl key */ 65642421Syokota keycode = 0x5A; 65742421Syokota break; 65842421Syokota case 0x35: /* keypad divide key */ 659246045Simp keycode = 0x5B; 660246045Simp break; 66142421Syokota case 0x37: /* print scrn key */ 662246045Simp keycode = 0x5C; 663246045Simp break; 66442421Syokota case 0x38: /* right alt key (alt gr) */ 665246045Simp keycode = 0x5D; 666246045Simp break; 66743337Syokota case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 66843337Syokota keycode = 0x68; 669246045Simp break; 67042421Syokota case 0x47: /* grey home key */ 671246045Simp keycode = 0x5E; 672246045Simp break; 67342421Syokota case 0x48: /* grey up arrow key */ 674246045Simp keycode = 0x5F; 675246045Simp break; 67642421Syokota case 0x49: /* grey page up key */ 677246045Simp keycode = 0x60; 678246045Simp break; 67942421Syokota case 0x4B: /* grey left arrow key */ 680246045Simp keycode = 0x61; 681246045Simp break; 68242421Syokota case 0x4D: /* grey right arrow key */ 683246045Simp keycode = 0x62; 684246045Simp break; 68542421Syokota case 0x4F: /* grey end key */ 686246045Simp keycode = 0x63; 687246045Simp break; 68842421Syokota case 0x50: /* grey down arrow key */ 689246045Simp keycode = 0x64; 690246045Simp break; 69142421Syokota case 0x51: /* grey page down key */ 692246045Simp keycode = 0x65; 693246045Simp break; 69442421Syokota case 0x52: /* grey insert key */ 695246045Simp keycode = 0x66; 696246045Simp break; 69742421Syokota case 0x53: /* grey delete key */ 698246045Simp keycode = 0x67; 699246045Simp break; 700246045Simp /* the following 3 are only used on the MS "Natural" keyboard */ 70142421Syokota case 0x5b: /* left Window key */ 702246045Simp keycode = 0x69; 703246045Simp break; 70442421Syokota case 0x5c: /* right Window key */ 705246045Simp keycode = 0x6a; 706246045Simp break; 70742421Syokota case 0x5d: /* menu key */ 708246045Simp keycode = 0x6b; 709246045Simp break; 710120875Sfjoe case 0x5e: /* power key */ 711120875Sfjoe keycode = 0x6d; 712120875Sfjoe break; 713120875Sfjoe case 0x5f: /* sleep key */ 714120875Sfjoe keycode = 0x6e; 715120875Sfjoe break; 716120875Sfjoe case 0x63: /* wake key */ 717120875Sfjoe keycode = 0x6f; 718120875Sfjoe break; 71942421Syokota default: /* ignore everything else */ 720246045Simp goto next_code; 72142421Syokota } 72242421Syokota break; 723246045Simp case 0xE1: /* 0xE1 prefix */ 72443337Syokota /* 72543337Syokota * The pause/break key on the 101 keyboard produces: 72643337Syokota * E1-1D-45 E1-9D-C5 72743337Syokota * Ctrl-pause/break produces: 72843337Syokota * E0-46 E0-C6 (See above.) 72943337Syokota */ 73042421Syokota state->ks_prefix = 0; 73142421Syokota if (keycode == 0x1D) 732246045Simp state->ks_prefix = 0x1D; 73342421Syokota goto next_code; 73442421Syokota /* NOT REACHED */ 735246045Simp case 0x1D: /* pause / break */ 73642421Syokota state->ks_prefix = 0; 73742421Syokota if (keycode != 0x45) 73843337Syokota goto next_code; 73942421Syokota keycode = 0x68; 74042421Syokota break; 74142421Syokota } 74242421Syokota 74343337Syokota if (kbd->kb_type == KB_84) { 74443337Syokota switch (keycode) { 74543337Syokota case 0x37: /* *(numpad)/print screen */ 74643337Syokota if (state->ks_flags & SHIFTS) 747246045Simp keycode = 0x5c; /* print screen */ 74843337Syokota break; 74943337Syokota case 0x45: /* num lock/pause */ 75043337Syokota if (state->ks_flags & CTLS) 75143337Syokota keycode = 0x68; /* pause */ 75243337Syokota break; 75343337Syokota case 0x46: /* scroll lock/break */ 75443337Syokota if (state->ks_flags & CTLS) 75543337Syokota keycode = 0x6c; /* break */ 75643337Syokota break; 75743337Syokota } 75843337Syokota } else if (kbd->kb_type == KB_101) { 75943337Syokota switch (keycode) { 76043337Syokota case 0x5c: /* print screen */ 76143337Syokota if (state->ks_flags & ALTS) 76243337Syokota keycode = 0x54; /* sysrq */ 76343337Syokota break; 76443337Syokota case 0x68: /* pause/break */ 76543337Syokota if (state->ks_flags & CTLS) 76643337Syokota keycode = 0x6c; /* break */ 76743337Syokota break; 76843337Syokota } 76943337Syokota } 77043337Syokota 77142421Syokota /* return the key code in the K_CODE mode */ 77242421Syokota if (state->ks_mode == K_CODE) 77342421Syokota return (keycode | (scancode & 0x80)); 77442421Syokota 77542421Syokota /* compose a character code */ 77642421Syokota if (state->ks_flags & COMPOSE) { 77747293Syokota switch (keycode | (scancode & 0x80)) { 77842421Syokota /* key pressed, process it */ 77942421Syokota case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 78042421Syokota state->ks_composed_char *= 10; 78146765Syokota state->ks_composed_char += keycode - 0x40; 78242421Syokota if (state->ks_composed_char > UCHAR_MAX) 78342421Syokota return ERRKEY; 78442421Syokota goto next_code; 78542421Syokota case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 78642421Syokota state->ks_composed_char *= 10; 78746765Syokota state->ks_composed_char += keycode - 0x47; 78842421Syokota if (state->ks_composed_char > UCHAR_MAX) 78942421Syokota return ERRKEY; 79042421Syokota goto next_code; 79142421Syokota case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 79242421Syokota state->ks_composed_char *= 10; 79346765Syokota state->ks_composed_char += keycode - 0x4E; 79442421Syokota if (state->ks_composed_char > UCHAR_MAX) 79542421Syokota return ERRKEY; 79642421Syokota goto next_code; 79742421Syokota case 0x52: /* keypad 0 */ 79842421Syokota state->ks_composed_char *= 10; 79942421Syokota if (state->ks_composed_char > UCHAR_MAX) 80042421Syokota return ERRKEY; 80142421Syokota goto next_code; 80242421Syokota 80342421Syokota /* key released, no interest here */ 80442421Syokota case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 80542421Syokota case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 80642421Syokota case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 80742421Syokota case 0xD2: /* keypad 0 */ 80842421Syokota goto next_code; 80942421Syokota 81042421Syokota case 0x38: /* left alt key */ 81142421Syokota break; 81242421Syokota 81342421Syokota default: 81442421Syokota if (state->ks_composed_char > 0) { 81542421Syokota state->ks_flags &= ~COMPOSE; 81642421Syokota state->ks_composed_char = 0; 81742421Syokota return ERRKEY; 81842421Syokota } 81942421Syokota break; 82042421Syokota } 82142421Syokota } 82242421Syokota 82342421Syokota /* keycode to key action */ 82442421Syokota action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 82542421Syokota &state->ks_state, &state->ks_accents); 82642421Syokota if (action == NOKEY) 82742421Syokota goto next_code; 82842421Syokota else 82942421Syokota return action; 83042421Syokota} 83142421Syokota 83242421Syokota/* check if char is waiting */ 83342421Syokotastatic int 83442421Syokotaatkbd_check_char(keyboard_t *kbd) 83542421Syokota{ 83642421Syokota atkbd_state_t *state; 83742421Syokota 83842421Syokota if (!KBD_IS_ACTIVE(kbd)) 83942421Syokota return FALSE; 84042421Syokota state = (atkbd_state_t *)kbd->kb_data; 84142421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 84242421Syokota return TRUE; 84342421Syokota return kbdc_data_ready(state->kbdc); 84442421Syokota} 84542421Syokota 84642421Syokota/* some useful control functions */ 84742421Syokotastatic int 84842421Syokotaatkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 84942421Syokota{ 850147271Smarius /* translate LED_XXX bits into the device specific bits */ 85142421Syokota static u_char ledmap[8] = { 85242421Syokota 0, 4, 2, 6, 1, 5, 3, 7, 85342421Syokota }; 85442421Syokota atkbd_state_t *state = kbd->kb_data; 85542421Syokota int error; 85642421Syokota int s; 85742421Syokota int i; 858162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 859162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 860162711Sru int ival; 861162711Sru#endif 86242421Syokota 86342421Syokota s = spltty(); 86442421Syokota switch (cmd) { 86542421Syokota 86642421Syokota case KDGKBMODE: /* get keyboard mode */ 86742421Syokota *(int *)arg = state->ks_mode; 86842421Syokota break; 869162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 870162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 871162711Sru case _IO('K', 7): 872162711Sru ival = IOCPARM_IVAL(arg); 873162711Sru arg = (caddr_t)&ival; 874162711Sru /* FALLTHROUGH */ 875162711Sru#endif 87642421Syokota case KDSKBMODE: /* set keyboard mode */ 87742421Syokota switch (*(int *)arg) { 87842421Syokota case K_XLATE: 87942421Syokota if (state->ks_mode != K_XLATE) { 88042421Syokota /* make lock key state and LED state match */ 88142421Syokota state->ks_state &= ~LOCK_MASK; 88242421Syokota state->ks_state |= KBD_LED_VAL(kbd); 88342421Syokota } 884102412Scharnier /* FALLTHROUGH */ 88542421Syokota case K_RAW: 88642421Syokota case K_CODE: 88742421Syokota if (state->ks_mode != *(int *)arg) { 88842421Syokota atkbd_clear_state(kbd); 88942421Syokota state->ks_mode = *(int *)arg; 89042421Syokota } 89142421Syokota break; 89242421Syokota default: 89342421Syokota splx(s); 89442421Syokota return EINVAL; 89542421Syokota } 89642421Syokota break; 89742421Syokota 89842421Syokota case KDGETLED: /* get keyboard LED */ 89942421Syokota *(int *)arg = KBD_LED_VAL(kbd); 90042421Syokota break; 901162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 902162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 903162711Sru case _IO('K', 66): 904162711Sru ival = IOCPARM_IVAL(arg); 905162711Sru arg = (caddr_t)&ival; 906162711Sru /* FALLTHROUGH */ 907162711Sru#endif 90842421Syokota case KDSETLED: /* set keyboard LED */ 90942421Syokota /* NOTE: lock key state in ks_state won't be changed */ 91042421Syokota if (*(int *)arg & ~LOCK_MASK) { 91142421Syokota splx(s); 91242421Syokota return EINVAL; 91342421Syokota } 91442421Syokota i = *(int *)arg; 91542421Syokota /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 91661004Sache if (state->ks_mode == K_XLATE && 91761004Sache kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 91842421Syokota if (i & ALKED) 91942421Syokota i |= CLKED; 92042421Syokota else 92142421Syokota i &= ~CLKED; 92242421Syokota } 92342421Syokota if (KBD_HAS_DEVICE(kbd)) { 92442421Syokota error = write_kbd(state->kbdc, KBDC_SET_LEDS, 92542421Syokota ledmap[i & LED_MASK]); 92642421Syokota if (error) { 92742421Syokota splx(s); 92842421Syokota return error; 92942421Syokota } 93042421Syokota } 93142421Syokota KBD_LED_VAL(kbd) = *(int *)arg; 93242421Syokota break; 93342421Syokota 93442421Syokota case KDGKBSTATE: /* get lock key state */ 93542421Syokota *(int *)arg = state->ks_state & LOCK_MASK; 93642421Syokota break; 937162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 938162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 939162711Sru case _IO('K', 20): 940162711Sru ival = IOCPARM_IVAL(arg); 941162711Sru arg = (caddr_t)&ival; 942162711Sru /* FALLTHROUGH */ 943162711Sru#endif 94442421Syokota case KDSKBSTATE: /* set lock key state */ 94542421Syokota if (*(int *)arg & ~LOCK_MASK) { 94642421Syokota splx(s); 94742421Syokota return EINVAL; 94842421Syokota } 94942421Syokota state->ks_state &= ~LOCK_MASK; 95042421Syokota state->ks_state |= *(int *)arg; 95142421Syokota splx(s); 95242421Syokota /* set LEDs and quit */ 95342421Syokota return atkbd_ioctl(kbd, KDSETLED, arg); 95442421Syokota 95544628Syokota case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 95642421Syokota splx(s); 95742421Syokota if (!KBD_HAS_DEVICE(kbd)) 95842421Syokota return 0; 95944628Syokota i = typematic(((int *)arg)[0], ((int *)arg)[1]); 96054543Syokota error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); 96154543Syokota if (error == 0) { 96254543Syokota kbd->kb_delay1 = typematic_delay(i); 96354543Syokota kbd->kb_delay2 = typematic_rate(i); 96454543Syokota } 96554543Syokota return error; 96642421Syokota 967162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 968162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 969162711Sru case _IO('K', 67): 970162711Sru ival = IOCPARM_IVAL(arg); 971162711Sru arg = (caddr_t)&ival; 972162711Sru /* FALLTHROUGH */ 973162711Sru#endif 97444628Syokota case KDSETRAD: /* set keyboard repeat rate (old interface) */ 97544628Syokota splx(s); 97644628Syokota if (!KBD_HAS_DEVICE(kbd)) 97744628Syokota return 0; 97854543Syokota error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); 97954543Syokota if (error == 0) { 98054543Syokota kbd->kb_delay1 = typematic_delay(*(int *)arg); 98154543Syokota kbd->kb_delay2 = typematic_rate(*(int *)arg); 98254543Syokota } 98354543Syokota return error; 98444628Syokota 98542421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 986224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 98742421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 98842421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 98942421Syokota state->ks_accents = 0; 990102412Scharnier /* FALLTHROUGH */ 99142421Syokota default: 99242421Syokota splx(s); 99342421Syokota return genkbd_commonioctl(kbd, cmd, arg); 99442421Syokota } 99542421Syokota 99642421Syokota splx(s); 99742421Syokota return 0; 99842421Syokota} 99942421Syokota 100042421Syokota/* lock the access to the keyboard */ 100142421Syokotastatic int 100242421Syokotaatkbd_lock(keyboard_t *kbd, int lock) 100342421Syokota{ 100442421Syokota return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock); 100542421Syokota} 100642421Syokota 100742421Syokota/* clear the internal state of the keyboard */ 100842421Syokotastatic void 100942421Syokotaatkbd_clear_state(keyboard_t *kbd) 101042421Syokota{ 101142421Syokota atkbd_state_t *state; 101242421Syokota 101342421Syokota state = (atkbd_state_t *)kbd->kb_data; 101442421Syokota state->ks_flags = 0; 101544628Syokota state->ks_polling = 0; 101642421Syokota state->ks_state &= LOCK_MASK; /* preserve locking key state */ 101742421Syokota state->ks_accents = 0; 101842421Syokota state->ks_composed_char = 0; 101942421Syokota#if 0 102042421Syokota state->ks_prefix = 0; /* XXX */ 102142421Syokota#endif 102242421Syokota} 102342421Syokota 102442421Syokota/* save the internal state */ 102542421Syokotastatic int 102642421Syokotaatkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 102742421Syokota{ 102842421Syokota if (len == 0) 102942421Syokota return sizeof(atkbd_state_t); 103042421Syokota if (len < sizeof(atkbd_state_t)) 103142421Syokota return -1; 103242421Syokota bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t)); 103342421Syokota return 0; 103442421Syokota} 103542421Syokota 103642421Syokota/* set the internal state */ 103742421Syokotastatic int 103842421Syokotaatkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 103942421Syokota{ 104042421Syokota if (len < sizeof(atkbd_state_t)) 104142421Syokota return ENOMEM; 104242421Syokota if (((atkbd_state_t *)kbd->kb_data)->kbdc 104342421Syokota != ((atkbd_state_t *)buf)->kbdc) 104442421Syokota return ENOMEM; 104542421Syokota bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t)); 104642421Syokota return 0; 104742421Syokota} 104842421Syokota 104944628Syokotastatic int 105044628Syokotaatkbd_poll(keyboard_t *kbd, int on) 105144628Syokota{ 105244628Syokota atkbd_state_t *state; 105344628Syokota int s; 105444628Syokota 105544628Syokota state = (atkbd_state_t *)kbd->kb_data; 105644628Syokota s = spltty(); 105744628Syokota if (on) 105844628Syokota ++state->ks_polling; 105944628Syokota else 106044628Syokota --state->ks_polling; 106144628Syokota splx(s); 106244628Syokota return 0; 106344628Syokota} 106444628Syokota 1065147271Smariusstatic void 1066147271Smariusatkbd_shutdown_final(void *v) 1067147271Smarius{ 1068147271Smarius#ifdef __sparc64__ 1069147271Smarius keyboard_t *kbd = v; 1070147271Smarius KBDC kbdc = ((atkbd_state_t *)kbd->kb_data)->kbdc; 1071147271Smarius 1072147271Smarius /* 1073147271Smarius * Turn off the translation in preparation for handing the keyboard 1074147271Smarius * over to the OFW as the OBP driver doesn't use translation and 1075147271Smarius * also doesn't disable it itself resulting in a broken keymap at 1076147271Smarius * the boot prompt. Also disable the aux port and the interrupts as 1077147271Smarius * the OBP driver doesn't use them, i.e. polls the keyboard. Not 1078147271Smarius * disabling the interrupts doesn't cause real problems but the 1079147271Smarius * responsiveness is a bit better when they are turned off. 1080147271Smarius */ 1081147271Smarius send_kbd_command(kbdc, KBDC_DISABLE_KBD); 1082147271Smarius set_controller_command_byte(kbdc, 1083147271Smarius KBD_AUX_CONTROL_BITS | KBD_KBD_CONTROL_BITS | KBD_TRANSLATION, 1084147271Smarius KBD_DISABLE_AUX_PORT | KBD_DISABLE_KBD_INT | KBD_ENABLE_KBD_PORT); 1085147271Smarius send_kbd_command(kbdc, KBDC_ENABLE_KBD); 1086147271Smarius#endif 1087147271Smarius} 1088147271Smarius 108942421Syokota/* local functions */ 109042421Syokota 109142421Syokotastatic int 109255731Syokotaget_typematic(keyboard_t *kbd) 109355731Syokota{ 1094197501Sjkim#if defined(__i386__) || defined(__amd64__) 109555731Syokota /* 1096198251Sjkim * Only some systems allow us to retrieve the keyboard repeat 109755731Syokota * rate previously set via the BIOS... 109855731Syokota */ 1099197384Sdelphij x86regs_t regs; 1100197501Sjkim uint8_t *p; 110155731Syokota 1102222967Sdelphij /* 1103222967Sdelphij * Traditional entry points of int 0x15 and 0x16 are fixed 1104222967Sdelphij * and later BIOSes follow them. (U)EFI CSM specification 1105223341Sdelphij * also mandates these fixed entry points. 1106222967Sdelphij * 1107222967Sdelphij * Validate the entry points here before we proceed further. 1108222967Sdelphij * It's known that some recent laptops does not have the 1109222967Sdelphij * same entry point and hang on boot if we call it. 1110222967Sdelphij */ 1111222795Sjkim if (x86bios_get_intr(0x15) != 0xf000f859 || 1112222795Sjkim x86bios_get_intr(0x16) != 0xf000e82e) 1113198251Sjkim return (ENODEV); 1114198251Sjkim 1115197501Sjkim /* Is BIOS system configuration table supported? */ 1116198251Sjkim x86bios_init_regs(®s); 1117197501Sjkim regs.R_AH = 0xc0; 1118197466Sjkim x86bios_intr(®s, 0x15); 1119197504Sjkim if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0) 1120197501Sjkim return (ENODEV); 1121197501Sjkim 1122198251Sjkim /* Is int 0x16, function 0x09 supported? */ 1123197501Sjkim p = x86bios_offset((regs.R_ES << 4) + regs.R_BX); 1124197501Sjkim if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0) 1125197501Sjkim return (ENODEV); 1126197501Sjkim 1127198251Sjkim /* Is int 0x16, function 0x0306 supported? */ 1128198251Sjkim x86bios_init_regs(®s); 1129197501Sjkim regs.R_AH = 0x09; 1130197466Sjkim x86bios_intr(®s, 0x16); 1131197501Sjkim if ((regs.R_AL & 0x08) == 0) 1132197501Sjkim return (ENODEV); 1133197501Sjkim 1134198251Sjkim x86bios_init_regs(®s); 1135197384Sdelphij regs.R_AX = 0x0306; 1136197466Sjkim x86bios_intr(®s, 0x16); 1137197384Sdelphij kbd->kb_delay1 = typematic_delay(regs.R_BH << 5); 1138197384Sdelphij kbd->kb_delay2 = typematic_rate(regs.R_BL); 1139197501Sjkim return (0); 114055731Syokota#else 1141197501Sjkim return (ENODEV); 1142197384Sdelphij#endif /* __i386__ || __amd64__ */ 114355731Syokota} 114455731Syokota 114555731Syokotastatic int 114642421Syokotasetup_kbd_port(KBDC kbdc, int port, int intr) 114742421Syokota{ 114842421Syokota if (!set_controller_command_byte(kbdc, 114942421Syokota KBD_KBD_CONTROL_BITS, 115042421Syokota ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) 115142421Syokota | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT))) 115242421Syokota return 1; 115342421Syokota return 0; 115442421Syokota} 115542421Syokota 115642421Syokotastatic int 115742421Syokotaget_kbd_echo(KBDC kbdc) 115842421Syokota{ 115942421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 116042421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) 116142421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 116242421Syokota return ENXIO; 116342421Syokota 116442421Syokota /* see if something is present */ 116542421Syokota write_kbd_command(kbdc, KBDC_ECHO); 116642421Syokota if (read_kbd_data(kbdc) != KBD_ECHO) { 116742421Syokota empty_both_buffers(kbdc, 10); 116842421Syokota test_controller(kbdc); 116942421Syokota test_kbd_port(kbdc); 117042421Syokota return ENXIO; 117142421Syokota } 117242421Syokota 117342421Syokota /* enable the keyboard port and intr. */ 117442421Syokota if (setup_kbd_port(kbdc, TRUE, TRUE)) { 117542421Syokota /* 117642421Syokota * CONTROLLER ERROR 117742421Syokota * This is serious; the keyboard intr is left disabled! 117842421Syokota */ 117942421Syokota return ENXIO; 118042421Syokota } 1181246045Simp 118242421Syokota return 0; 118342421Syokota} 118442421Syokota 118542421Syokotastatic int 118642421Syokotaprobe_keyboard(KBDC kbdc, int flags) 118742421Syokota{ 118842421Syokota /* 118942421Syokota * Don't try to print anything in this function. The low-level 119042421Syokota * console may not have been initialized yet... 119142421Syokota */ 119242421Syokota int err; 119342421Syokota int c; 119442421Syokota int m; 119542421Syokota 119642421Syokota if (!kbdc_lock(kbdc, TRUE)) { 119742421Syokota /* driver error? */ 119842421Syokota return ENXIO; 119942421Syokota } 120042421Syokota 120157131Syokota /* temporarily block data transmission from the keyboard */ 120257131Syokota write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 120357131Syokota 120442421Syokota /* flush any noise in the buffer */ 120557131Syokota empty_both_buffers(kbdc, 100); 120642421Syokota 120742421Syokota /* save the current keyboard controller command byte */ 120842421Syokota m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; 120942421Syokota c = get_controller_command_byte(kbdc); 121042421Syokota if (c == -1) { 121142421Syokota /* CONTROLLER ERROR */ 121242421Syokota kbdc_set_device_mask(kbdc, m); 121342421Syokota kbdc_lock(kbdc, FALSE); 121442421Syokota return ENXIO; 121542421Syokota } 121642421Syokota 121742421Syokota /* 121842421Syokota * The keyboard may have been screwed up by the boot block. 121942421Syokota * We may just be able to recover from error by testing the controller 122042421Syokota * and the keyboard port. The controller command byte needs to be 122142421Syokota * saved before this recovery operation, as some controllers seem 122242421Syokota * to set the command byte to particular values. 122342421Syokota */ 122442421Syokota test_controller(kbdc); 1225138900Sjhb if (!(flags & KB_CONF_NO_PROBE_TEST)) 1226138900Sjhb test_kbd_port(kbdc); 122742421Syokota 122842421Syokota err = get_kbd_echo(kbdc); 122957902Syokota 123057902Syokota /* 123157902Syokota * Even if the keyboard doesn't seem to be present (err != 0), 123257902Syokota * we shall enable the keyboard port and interrupt so that 123357902Syokota * the driver will be operable when the keyboard is attached 123457902Syokota * to the system later. It is NOT recommended to hot-plug 123557902Syokota * the AT keyboard, but many people do so... 123657902Syokota */ 123757902Syokota kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 123857902Syokota setup_kbd_port(kbdc, TRUE, TRUE); 123957902Syokota#if 0 124042421Syokota if (err == 0) { 124142421Syokota kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 124242421Syokota } else { 124357131Syokota /* try to restore the command byte as before */ 124457131Syokota set_controller_command_byte(kbdc, 0xff, c); 124542421Syokota kbdc_set_device_mask(kbdc, m); 124642421Syokota } 124757902Syokota#endif 124842421Syokota 124942421Syokota kbdc_lock(kbdc, FALSE); 125042421Syokota return err; 125142421Syokota} 125242421Syokota 125342421Syokotastatic int 125442421Syokotainit_keyboard(KBDC kbdc, int *type, int flags) 125542421Syokota{ 125642421Syokota int codeset; 125742421Syokota int id; 125842421Syokota int c; 125942421Syokota 126042421Syokota if (!kbdc_lock(kbdc, TRUE)) { 126142421Syokota /* driver error? */ 126242421Syokota return EIO; 126342421Syokota } 126442421Syokota 126557131Syokota /* temporarily block data transmission from the keyboard */ 126657131Syokota write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 126757131Syokota 126842421Syokota /* save the current controller command byte */ 126954382Syokota empty_both_buffers(kbdc, 200); 127042421Syokota c = get_controller_command_byte(kbdc); 127142421Syokota if (c == -1) { 127242421Syokota /* CONTROLLER ERROR */ 127342421Syokota kbdc_lock(kbdc, FALSE); 127442421Syokota printf("atkbd: unable to get the current command byte value.\n"); 127542421Syokota return EIO; 127642421Syokota } 127742421Syokota if (bootverbose) 127842421Syokota printf("atkbd: the current kbd controller command byte %04x\n", 1279246045Simp c); 128042421Syokota#if 0 128142421Syokota /* override the keyboard lock switch */ 128242421Syokota c |= KBD_OVERRIDE_KBD_LOCK; 128342421Syokota#endif 128442421Syokota 128542421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 128642421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) { 128742421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 128842421Syokota printf("atkbd: unable to set the command byte.\n"); 128942421Syokota kbdc_lock(kbdc, FALSE); 129042421Syokota return EIO; 129142421Syokota } 129242421Syokota 129342421Syokota /* 129442421Syokota * Check if we have an XT keyboard before we attempt to reset it. 129542421Syokota * The procedure assumes that the keyboard and the controller have 129642421Syokota * been set up properly by BIOS and have not been messed up 129742421Syokota * during the boot process. 129842421Syokota */ 129942421Syokota codeset = -1; 130042421Syokota if (flags & KB_CONF_ALT_SCANCODESET) 130142421Syokota /* the user says there is a XT keyboard */ 130242421Syokota codeset = 1; 130342421Syokota#ifdef KBD_DETECT_XT_KEYBOARD 130442421Syokota else if ((c & KBD_TRANSLATION) == 0) { 130542421Syokota /* SET_SCANCODE_SET is not always supported; ignore error */ 130642421Syokota if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0) 130742421Syokota == KBD_ACK) 130842421Syokota codeset = read_kbd_data(kbdc); 130942421Syokota } 131042421Syokota if (bootverbose) 131142421Syokota printf("atkbd: scancode set %d\n", codeset); 131242421Syokota#endif /* KBD_DETECT_XT_KEYBOARD */ 131342421Syokota 131442421Syokota *type = KB_OTHER; 131542421Syokota id = get_kbd_id(kbdc); 131642421Syokota switch(id) { 131755730Syokota case 0x41ab: /* 101/102/... Enhanced */ 131855730Syokota case 0x83ab: /* ditto */ 131955730Syokota case 0x54ab: /* SpaceSaver */ 132055730Syokota case 0x84ab: /* ditto */ 132155730Syokota#if 0 132255730Syokota case 0x90ab: /* 'G' */ 132355730Syokota case 0x91ab: /* 'P' */ 132455730Syokota case 0x92ab: /* 'A' */ 132555730Syokota#endif 132642421Syokota *type = KB_101; 132742421Syokota break; 132842421Syokota case -1: /* AT 84 keyboard doesn't return ID */ 132942421Syokota *type = KB_84; 133042421Syokota break; 133142421Syokota default: 133242421Syokota break; 133342421Syokota } 133442421Syokota if (bootverbose) 133542421Syokota printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type); 133642421Syokota 133742421Syokota /* reset keyboard hardware */ 133842421Syokota if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { 133942421Syokota /* 134042421Syokota * KEYBOARD ERROR 134142421Syokota * Keyboard reset may fail either because the keyboard 134242421Syokota * doen't exist, or because the keyboard doesn't pass 134342421Syokota * the self-test, or the keyboard controller on the 134442421Syokota * motherboard and the keyboard somehow fail to shake hands. 134542421Syokota * It is just possible, particularly in the last case, 1346110398Scharnier * that the keyboard controller may be left in a hung state. 134742421Syokota * test_controller() and test_kbd_port() appear to bring 134842421Syokota * the keyboard controller back (I don't know why and how, 134942421Syokota * though.) 135042421Syokota */ 135142421Syokota empty_both_buffers(kbdc, 10); 135242421Syokota test_controller(kbdc); 135342421Syokota test_kbd_port(kbdc); 135442421Syokota /* 135542421Syokota * We could disable the keyboard port and interrupt... but, 135642421Syokota * the keyboard may still exist (see above). 135742421Syokota */ 135842421Syokota set_controller_command_byte(kbdc, 0xff, c); 135942421Syokota kbdc_lock(kbdc, FALSE); 136042421Syokota if (bootverbose) 136142421Syokota printf("atkbd: failed to reset the keyboard.\n"); 136242421Syokota return EIO; 136342421Syokota } 136442421Syokota 136542421Syokota /* 136694275Sphk * Allow us to set the XT_KEYBD flag so that keyboards 136742421Syokota * such as those on the IBM ThinkPad laptop computers can be used 136842421Syokota * with the standard console driver. 136942421Syokota */ 137042421Syokota if (codeset == 1) { 137142421Syokota if (send_kbd_command_and_data(kbdc, 137242421Syokota KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 137342421Syokota /* XT kbd doesn't need scan code translation */ 137442421Syokota c &= ~KBD_TRANSLATION; 137542421Syokota } else { 137642421Syokota /* 137742421Syokota * KEYBOARD ERROR 137842421Syokota * The XT kbd isn't usable unless the proper scan 137942421Syokota * code set is selected. 138042421Syokota */ 138142421Syokota set_controller_command_byte(kbdc, 0xff, c); 138242421Syokota kbdc_lock(kbdc, FALSE); 138342421Syokota printf("atkbd: unable to set the XT keyboard mode.\n"); 138442421Syokota return EIO; 138542421Syokota } 138642421Syokota } 138742421Syokota 1388158471Sjhb#if defined(__sparc64__) 138942831Syokota if (send_kbd_command_and_data( 139042831Syokota kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) { 139142831Syokota printf("atkbd: can't set translation.\n"); 139242831Syokota } 139342831Syokota c |= KBD_TRANSLATION; 139442831Syokota#endif 139542831Syokota 139642421Syokota /* enable the keyboard port and intr. */ 139742421Syokota if (!set_controller_command_byte(kbdc, 139842421Syokota KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 139942421Syokota (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 140042421Syokota | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 140142421Syokota /* 140242421Syokota * CONTROLLER ERROR 140342421Syokota * This is serious; we are left with the disabled 140442421Syokota * keyboard intr. 140542421Syokota */ 140642421Syokota set_controller_command_byte(kbdc, 0xff, c); 140742421Syokota kbdc_lock(kbdc, FALSE); 140842421Syokota printf("atkbd: unable to enable the keyboard port and intr.\n"); 140942421Syokota return EIO; 141042421Syokota } 141142421Syokota 141242421Syokota kbdc_lock(kbdc, FALSE); 141342421Syokota return 0; 141442421Syokota} 141542421Syokota 141642421Syokotastatic int 141742421Syokotawrite_kbd(KBDC kbdc, int command, int data) 141842421Syokota{ 1419246045Simp int s; 142042421Syokota 1421246045Simp /* prevent the timeout routine from polling the keyboard */ 1422246045Simp if (!kbdc_lock(kbdc, TRUE)) 1423246045Simp return EBUSY; 142442421Syokota 1425246045Simp /* disable the keyboard and mouse interrupt */ 1426246045Simp s = spltty(); 142742421Syokota#if 0 1428246045Simp c = get_controller_command_byte(kbdc); 1429246045Simp if ((c == -1) 1430246045Simp || !set_controller_command_byte(kbdc, 1431246045Simp kbdc_get_device_mask(kbdc), 1432246045Simp KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 1433246045Simp | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1434246045Simp /* CONTROLLER ERROR */ 1435246045Simp kbdc_lock(kbdc, FALSE); 1436246045Simp splx(s); 1437246045Simp return EIO; 1438246045Simp } 1439246045Simp /* 1440246045Simp * Now that the keyboard controller is told not to generate 1441246045Simp * the keyboard and mouse interrupts, call `splx()' to allow 1442246045Simp * the other tty interrupts. The clock interrupt may also occur, 1443246045Simp * but the timeout routine (`scrn_timer()') will be blocked 1444246045Simp * by the lock flag set via `kbdc_lock()' 1445246045Simp */ 144642421Syokota splx(s); 144742421Syokota#endif 1448246045Simp if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) 1449246045Simp send_kbd_command(kbdc, KBDC_ENABLE_KBD); 145042421Syokota#if 0 1451246045Simp /* restore the interrupts */ 1452246045Simp if (!set_controller_command_byte(kbdc, kbdc_get_device_mask(kbdc), 145342421Syokota c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 1454246045Simp /* CONTROLLER ERROR */ 1455246045Simp } 145642421Syokota#else 1457246045Simp splx(s); 145842421Syokota#endif 1459246045Simp kbdc_lock(kbdc, FALSE); 146042421Syokota 1461246045Simp return 0; 146242421Syokota} 146342421Syokota 146442421Syokotastatic int 146542421Syokotaget_kbd_id(KBDC kbdc) 146642421Syokota{ 146742421Syokota int id1, id2; 146842421Syokota 146942421Syokota empty_both_buffers(kbdc, 10); 147042421Syokota id1 = id2 = -1; 147142421Syokota if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK) 147242421Syokota return -1; 147342421Syokota 147442421Syokota DELAY(10000); /* 10 msec delay */ 147542421Syokota id1 = read_kbd_data(kbdc); 147642421Syokota if (id1 != -1) 147742421Syokota id2 = read_kbd_data(kbdc); 147842421Syokota 147942421Syokota if ((id1 == -1) || (id2 == -1)) { 148042421Syokota empty_both_buffers(kbdc, 10); 148142421Syokota test_controller(kbdc); 148242421Syokota test_kbd_port(kbdc); 148342421Syokota return -1; 148442421Syokota } 148542421Syokota return ((id2 << 8) | id1); 148642421Syokota} 148742421Syokota 148854543Syokotastatic int delays[] = { 250, 500, 750, 1000 }; 148954543Syokotastatic int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 149054543Syokota 68, 76, 84, 92, 100, 110, 118, 126, 149154543Syokota 136, 152, 168, 184, 200, 220, 236, 252, 149254543Syokota 272, 304, 336, 368, 400, 440, 472, 504 }; 149354543Syokota 149444628Syokotastatic int 149554543Syokotatypematic_delay(int i) 149654543Syokota{ 149754543Syokota return delays[(i >> 5) & 3]; 149854543Syokota} 149954543Syokota 150054543Syokotastatic int 150154543Syokotatypematic_rate(int i) 150254543Syokota{ 150354543Syokota return rates[i & 0x1f]; 150454543Syokota} 150554543Syokota 150654543Syokotastatic int 150744628Syokotatypematic(int delay, int rate) 150844628Syokota{ 150944628Syokota int value; 151044628Syokota int i; 151144628Syokota 151244628Syokota for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { 151344628Syokota if (delay >= delays[i]) 151444628Syokota break; 151544628Syokota } 151644628Syokota value = i << 5; 151744628Syokota for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { 151844628Syokota if (rate >= rates[i]) 151944628Syokota break; 152044628Syokota } 152144628Syokota value |= i; 152244628Syokota return value; 152344628Syokota} 1524