atkbd.c revision 223341
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: head/sys/dev/atkbdc/atkbd.c 223341 2011-06-20 16:42:20Z delphij $"); 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 6958271Syokotaatkbd_probe_unit(int unit, int ctlr, 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 7958271Syokota args[0] = ctlr; 8042421Syokota args[1] = irq; 8144628Syokota error = (*sw->probe)(unit, args, flags); 8244628Syokota if (error) 8344628Syokota return error; 8444628Syokota return 0; 8542421Syokota} 8642421Syokota 8742421Syokotaint 8858271Syokotaatkbd_attach_unit(int unit, keyboard_t **kbd, int ctlr, int irq, int flags) 8942421Syokota{ 9042421Syokota keyboard_switch_t *sw; 9144628Syokota int args[2]; 9242421Syokota int error; 9342421Syokota 9442421Syokota sw = kbd_get_switch(ATKBD_DRIVER_NAME); 9542421Syokota if (sw == NULL) 9642421Syokota return ENXIO; 9742421Syokota 9842421Syokota /* reset, initialize and enable the device */ 9958271Syokota args[0] = ctlr; 10044628Syokota args[1] = irq; 10150154Syokota *kbd = NULL; 10244628Syokota error = (*sw->probe)(unit, args, flags); 10342421Syokota if (error) 10444628Syokota return error; 10550154Syokota error = (*sw->init)(unit, kbd, args, flags); 10644628Syokota if (error) 10744628Syokota return error; 10850154Syokota (*sw->enable)(*kbd); 10942421Syokota 11042421Syokota#ifdef KBD_INSTALL_CDEV 11142421Syokota /* attach a virtual keyboard cdev */ 11250154Syokota error = kbd_attach(*kbd); 11342421Syokota if (error) 11442421Syokota return error; 11542421Syokota#endif 11642421Syokota 11742421Syokota /* 11842421Syokota * This is a kludge to compensate for lost keyboard interrupts. 11942421Syokota * A similar code used to be in syscons. See below. XXX 12042421Syokota */ 12150154Syokota atkbd_timeout(*kbd); 12242421Syokota 12342421Syokota if (bootverbose) 12450154Syokota (*sw->diag)(*kbd, bootverbose); 125147271Smarius 126147271Smarius EVENTHANDLER_REGISTER(shutdown_final, atkbd_shutdown_final, *kbd, 127147271Smarius SHUTDOWN_PRI_DEFAULT); 128147271Smarius 12942421Syokota return 0; 13042421Syokota} 13142421Syokota 13242421Syokotastatic void 13342421Syokotaatkbd_timeout(void *arg) 13442421Syokota{ 13542421Syokota keyboard_t *kbd; 13642421Syokota int s; 13742421Syokota 13856334Syokota /* 13956334Syokota * The original text of the following comments are extracted 14056334Syokota * from syscons.c (1.287) 14156334Syokota * 14242421Syokota * With release 2.1 of the Xaccel server, the keyboard is left 14342421Syokota * hanging pretty often. Apparently an interrupt from the 14442421Syokota * keyboard is lost, and I don't know why (yet). 14556334Syokota * This ugly hack calls the low-level interrupt routine if input 14656334Syokota * is ready for the keyboard and conveniently hides the problem. XXX 14756334Syokota * 14856334Syokota * Try removing anything stuck in the keyboard controller; whether 14956334Syokota * it's a keyboard scan code or mouse data. The low-level 15056334Syokota * interrupt routine doesn't read the mouse data directly, 15156334Syokota * but the keyboard controller driver will, as a side effect. 15242421Syokota */ 15342421Syokota /* 15456334Syokota * And here is bde's original comment about this: 15556334Syokota * 15656334Syokota * This is necessary to handle edge triggered interrupts - if we 15756334Syokota * returned when our IRQ is high due to unserviced input, then there 15856334Syokota * would be no more keyboard IRQs until the keyboard is reset by 15956334Syokota * external powers. 16056334Syokota * 16156334Syokota * The keyboard apparently unwedges the irq in most cases. 16242421Syokota */ 16342421Syokota s = spltty(); 16442421Syokota kbd = (keyboard_t *)arg; 165174984Swkoszek if (kbdd_lock(kbd, TRUE)) { 16642421Syokota /* 16742421Syokota * We have seen the lock flag is not set. Let's reset 16842421Syokota * the flag early, otherwise the LED update routine fails 16942421Syokota * which may want the lock during the interrupt routine. 17042421Syokota */ 171174984Swkoszek kbdd_lock(kbd, FALSE); 172174984Swkoszek if (kbdd_check_char(kbd)) 173174984Swkoszek kbdd_intr(kbd, NULL); 17442421Syokota } 17542421Syokota splx(s); 17642421Syokota timeout(atkbd_timeout, arg, hz/10); 17742421Syokota} 17842421Syokota 17942421Syokota/* LOW-LEVEL */ 18042421Syokota 18142421Syokota#define ATKBD_DEFAULT 0 18242421Syokota 18342421Syokotatypedef struct atkbd_state { 18442421Syokota KBDC kbdc; /* keyboard controller */ 18542421Syokota int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 18642421Syokota int ks_flags; /* flags */ 18742421Syokota#define COMPOSE (1 << 0) 18844628Syokota int ks_polling; 18942421Syokota int ks_state; /* shift/lock key state */ 19042421Syokota int ks_accents; /* accent key index (> 0) */ 19142421Syokota u_int ks_composed_char; /* composed char code (> 0) */ 19242421Syokota u_char ks_prefix; /* AT scan code prefix */ 19342421Syokota} atkbd_state_t; 19442421Syokota 19542421Syokota/* keyboard driver declaration */ 19642421Syokotastatic int atkbd_configure(int flags); 19742421Syokotastatic kbd_probe_t atkbd_probe; 19842421Syokotastatic kbd_init_t atkbd_init; 19942421Syokotastatic kbd_term_t atkbd_term; 20042421Syokotastatic kbd_intr_t atkbd_intr; 20142421Syokotastatic kbd_test_if_t atkbd_test_if; 20242421Syokotastatic kbd_enable_t atkbd_enable; 20342421Syokotastatic kbd_disable_t atkbd_disable; 20442421Syokotastatic kbd_read_t atkbd_read; 20542421Syokotastatic kbd_check_t atkbd_check; 20642421Syokotastatic kbd_read_char_t atkbd_read_char; 20742421Syokotastatic kbd_check_char_t atkbd_check_char; 20842421Syokotastatic kbd_ioctl_t atkbd_ioctl; 20942421Syokotastatic kbd_lock_t atkbd_lock; 21042421Syokotastatic kbd_clear_state_t atkbd_clear_state; 21142421Syokotastatic kbd_get_state_t atkbd_get_state; 21242421Syokotastatic kbd_set_state_t atkbd_set_state; 21344628Syokotastatic kbd_poll_mode_t atkbd_poll; 21442421Syokota 215114293Smarkmstatic keyboard_switch_t atkbdsw = { 21642421Syokota atkbd_probe, 21742421Syokota atkbd_init, 21842421Syokota atkbd_term, 21942421Syokota atkbd_intr, 22042421Syokota atkbd_test_if, 22142421Syokota atkbd_enable, 22242421Syokota atkbd_disable, 22342421Syokota atkbd_read, 22442421Syokota atkbd_check, 22542421Syokota atkbd_read_char, 22642421Syokota atkbd_check_char, 22742421Syokota atkbd_ioctl, 22842421Syokota atkbd_lock, 22942421Syokota atkbd_clear_state, 23042421Syokota atkbd_get_state, 23142421Syokota atkbd_set_state, 23242421Syokota genkbd_get_fkeystr, 23344628Syokota atkbd_poll, 23442421Syokota genkbd_diag, 23542421Syokota}; 23642421Syokota 23742421SyokotaKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); 23842421Syokota 23942421Syokota/* local functions */ 24055731Syokotastatic int get_typematic(keyboard_t *kbd); 24142421Syokotastatic int setup_kbd_port(KBDC kbdc, int port, int intr); 24242421Syokotastatic int get_kbd_echo(KBDC kbdc); 24342421Syokotastatic int probe_keyboard(KBDC kbdc, int flags); 24442421Syokotastatic int init_keyboard(KBDC kbdc, int *type, int flags); 24542421Syokotastatic int write_kbd(KBDC kbdc, int command, int data); 24642421Syokotastatic int get_kbd_id(KBDC kbdc); 24744628Syokotastatic int typematic(int delay, int rate); 24854543Syokotastatic int typematic_delay(int delay); 24954543Syokotastatic int typematic_rate(int rate); 25042421Syokota 25142421Syokota/* local variables */ 25242421Syokota 25342421Syokota/* the initial key map, accent map and fkey strings */ 25444628Syokota#ifdef ATKBD_DFLT_KEYMAP 25544628Syokota#define KBD_DFLT_KEYMAP 25644628Syokota#include "atkbdmap.h" 25744628Syokota#endif 25842831Syokota#include <dev/kbd/kbdtables.h> 25942421Syokota 26042421Syokota/* structures for the default keyboard */ 26142421Syokotastatic keyboard_t default_kbd; 26242421Syokotastatic atkbd_state_t default_kbd_state; 26342421Syokotastatic keymap_t default_keymap; 26442421Syokotastatic accentmap_t default_accentmap; 26542421Syokotastatic fkeytab_t default_fkeytab[NUM_FKEYS]; 26642421Syokota 26742421Syokota/* 26842421Syokota * The back door to the keyboard driver! 26942421Syokota * This function is called by the console driver, via the kbdio module, 27042421Syokota * to tickle keyboard drivers when the low-level console is being initialized. 27142421Syokota * Almost nothing in the kernel has been initialied yet. Try to probe 27242421Syokota * keyboards if possible. 27394228Sasmodai * NOTE: because of the way the low-level console is initialized, this routine 27442421Syokota * may be called more than once!! 27542421Syokota */ 27642421Syokotastatic int 27742421Syokotaatkbd_configure(int flags) 27842421Syokota{ 27942421Syokota keyboard_t *kbd; 28042421Syokota int arg[2]; 28144628Syokota int i; 28242421Syokota 283158041Ssobomax /* 284158041Ssobomax * Probe the keyboard controller, if not present or if the driver 285158041Ssobomax * is disabled, unregister the keyboard if any. 286158041Ssobomax */ 287158041Ssobomax if (atkbdc_configure() != 0 || 288158041Ssobomax resource_disabled("atkbd", ATKBD_DEFAULT)) { 28946764Syokota i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT); 29046764Syokota if (i >= 0) { 29146764Syokota kbd = kbd_get_keyboard(i); 29246764Syokota kbd_unregister(kbd); 29346764Syokota kbd->kb_flags &= ~KB_REGISTERED; 29444628Syokota } 29548878Syokota return 0; 29644628Syokota } 29745720Speter 29846764Syokota /* XXX: a kludge to obtain the device configuration flags */ 29946764Syokota if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0) 30046764Syokota flags |= i; 30146764Syokota 30242421Syokota /* probe the default keyboard */ 30342421Syokota arg[0] = -1; 30442421Syokota arg[1] = -1; 30544628Syokota kbd = NULL; 30644628Syokota if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) 30742421Syokota return 0; 30844628Syokota if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) 30944628Syokota return 0; 31042421Syokota 31144628Syokota /* return the number of found keyboards */ 31244628Syokota return 1; 31344628Syokota} 31444628Syokota 31544628Syokota/* low-level functions */ 31644628Syokota 31744628Syokota/* detect a keyboard */ 31844628Syokotastatic int 31944628Syokotaatkbd_probe(int unit, void *arg, int flags) 32044628Syokota{ 32144628Syokota KBDC kbdc; 32258271Syokota int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 32344628Syokota 32444628Syokota /* XXX */ 32544628Syokota if (unit == ATKBD_DEFAULT) { 32644628Syokota if (KBD_IS_PROBED(&default_kbd)) 32742421Syokota return 0; 32842421Syokota } 32942421Syokota 33058271Syokota kbdc = atkbdc_open(data[0]); 33144628Syokota if (kbdc == NULL) 33244628Syokota return ENXIO; 33344628Syokota if (probe_keyboard(kbdc, flags)) { 33444628Syokota if (flags & KB_CONF_FAIL_IF_NO_KBD) 33544628Syokota return ENXIO; 33642421Syokota } 33744628Syokota return 0; 33842421Syokota} 33942421Syokota 34044628Syokota/* reset and initialize the device */ 34142421Syokotastatic int 34244628Syokotaatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 34342421Syokota{ 34442421Syokota keyboard_t *kbd; 34542421Syokota atkbd_state_t *state; 34642421Syokota keymap_t *keymap; 34742421Syokota accentmap_t *accmap; 34842421Syokota fkeytab_t *fkeymap; 34942421Syokota int fkeymap_size; 35055731Syokota int delay[2]; 35158271Syokota int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 352142569Ssam int error, needfree; 35342421Syokota 35442421Syokota /* XXX */ 35542421Syokota if (unit == ATKBD_DEFAULT) { 35642421Syokota *kbdp = kbd = &default_kbd; 35744628Syokota if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) 35842421Syokota return 0; 35942421Syokota state = &default_kbd_state; 36042421Syokota keymap = &default_keymap; 36142421Syokota accmap = &default_accentmap; 36242421Syokota fkeymap = default_fkeytab; 36342421Syokota fkeymap_size = 36442421Syokota sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 365142569Ssam needfree = 0; 36642421Syokota } else if (*kbdp == NULL) { 36769781Sdwmalone *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO); 36869781Sdwmalone state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO); 369142569Ssam /* NB: these will always be initialized 'cuz !KBD_IS_PROBED */ 37042421Syokota keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); 37142421Syokota accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); 37242421Syokota fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); 37342421Syokota fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 374142569Ssam needfree = 1; 37569781Sdwmalone if ((kbd == NULL) || (state == NULL) || (keymap == NULL) 37669781Sdwmalone || (accmap == NULL) || (fkeymap == NULL)) { 377142569Ssam error = ENOMEM; 378142569Ssam goto bad; 37942421Syokota } 38044628Syokota } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 38142421Syokota return 0; 38242421Syokota } else { 38342421Syokota kbd = *kbdp; 38442421Syokota state = (atkbd_state_t *)kbd->kb_data; 38542421Syokota bzero(state, sizeof(*state)); 38642421Syokota keymap = kbd->kb_keymap; 38742421Syokota accmap = kbd->kb_accentmap; 38842421Syokota fkeymap = kbd->kb_fkeytab; 38942421Syokota fkeymap_size = kbd->kb_fkeytab_size; 390142569Ssam needfree = 0; 39142421Syokota } 39242421Syokota 39344628Syokota if (!KBD_IS_PROBED(kbd)) { 39458271Syokota state->kbdc = atkbdc_open(data[0]); 395142569Ssam if (state->kbdc == NULL) { 396142569Ssam error = ENXIO; 397142569Ssam goto bad; 398142569Ssam } 39944628Syokota kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 40058271Syokota 0, 0); 40144628Syokota bcopy(&key_map, keymap, sizeof(key_map)); 40244628Syokota bcopy(&accent_map, accmap, sizeof(accent_map)); 40344628Syokota bcopy(fkey_tab, fkeymap, 40444628Syokota imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 40544628Syokota kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 40644628Syokota kbd->kb_data = (void *)state; 40744628Syokota 40844628Syokota if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ 409142569Ssam if (flags & KB_CONF_FAIL_IF_NO_KBD) { 410142569Ssam error = ENXIO; 411142569Ssam goto bad; 412142569Ssam } 41344628Syokota } else { 41444628Syokota KBD_FOUND_DEVICE(kbd); 41544628Syokota } 41644628Syokota atkbd_clear_state(kbd); 41744628Syokota state->ks_mode = K_XLATE; 41844628Syokota /* 41944628Syokota * FIXME: set the initial value for lock keys in ks_state 42044628Syokota * according to the BIOS data? 42144628Syokota */ 42244628Syokota KBD_PROBE_DONE(kbd); 42342421Syokota } 42444628Syokota if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 42549820Syokota kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 42642421Syokota if (KBD_HAS_DEVICE(kbd) 42744628Syokota && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 428117513Ssimokawa && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { 429117513Ssimokawa kbd_unregister(kbd); 430142569Ssam error = ENXIO; 431142569Ssam goto bad; 432117513Ssimokawa } 43344628Syokota atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 43455731Syokota get_typematic(kbd); 43555731Syokota delay[0] = kbd->kb_delay1; 43655731Syokota delay[1] = kbd->kb_delay2; 43755731Syokota atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 43842421Syokota KBD_INIT_DONE(kbd); 43942421Syokota } 44042421Syokota if (!KBD_IS_CONFIGURED(kbd)) { 441142569Ssam if (kbd_register(kbd) < 0) { 442142569Ssam error = ENXIO; 443142569Ssam goto bad; 444142569Ssam } 44542421Syokota KBD_CONFIG_DONE(kbd); 44642421Syokota } 44742421Syokota 44842421Syokota return 0; 449142569Ssambad: 450142569Ssam if (needfree) { 451142569Ssam if (state != NULL) 452142569Ssam free(state, M_DEVBUF); 453142569Ssam if (keymap != NULL) 454142569Ssam free(keymap, M_DEVBUF); 455142569Ssam if (accmap != NULL) 456142569Ssam free(accmap, M_DEVBUF); 457142569Ssam if (fkeymap != NULL) 458142569Ssam free(fkeymap, M_DEVBUF); 459142569Ssam if (kbd != NULL) { 460142569Ssam free(kbd, M_DEVBUF); 461142569Ssam *kbdp = NULL; /* insure ref doesn't leak to caller */ 462142569Ssam } 463142569Ssam } 464142569Ssam return error; 46542421Syokota} 46642421Syokota 46742421Syokota/* finish using this keyboard */ 46842421Syokotastatic int 46942421Syokotaatkbd_term(keyboard_t *kbd) 47042421Syokota{ 47142421Syokota kbd_unregister(kbd); 47242421Syokota return 0; 47342421Syokota} 47442421Syokota 47542421Syokota/* keyboard interrupt routine */ 47642421Syokotastatic int 47744628Syokotaatkbd_intr(keyboard_t *kbd, void *arg) 47842421Syokota{ 479191164Semax atkbd_state_t *state = (atkbd_state_t *)kbd->kb_data; 48055731Syokota int delay[2]; 48142421Syokota int c; 48242421Syokota 483163687Sru if (!KBD_HAS_DEVICE(kbd)) { 484163687Sru /* 485163687Sru * The keyboard was not detected before; 486163687Sru * it must have been reconnected! 487163687Sru */ 488163687Sru init_keyboard(state->kbdc, &kbd->kb_type, 489163687Sru kbd->kb_config); 490163687Sru KBD_FOUND_DEVICE(kbd); 491163687Sru atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 492163687Sru get_typematic(kbd); 493163687Sru delay[0] = kbd->kb_delay1; 494163687Sru delay[1] = kbd->kb_delay2; 495163687Sru atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 496163687Sru } 497163687Sru 498191164Semax if (state->ks_polling) 499191164Semax return 0; 500191164Semax 50142421Syokota if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 50242421Syokota /* let the callback function to process the input */ 50342421Syokota (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 50442421Syokota kbd->kb_callback.kc_arg); 50542421Syokota } else { 50642421Syokota /* read and discard the input; no one is waiting for input */ 50742421Syokota do { 50842421Syokota c = atkbd_read_char(kbd, FALSE); 50942421Syokota } while (c != NOKEY); 51042421Syokota } 51142421Syokota return 0; 51242421Syokota} 51342421Syokota 51442421Syokota/* test the interface to the device */ 51542421Syokotastatic int 51642421Syokotaatkbd_test_if(keyboard_t *kbd) 51742421Syokota{ 51842421Syokota int error; 51942421Syokota int s; 52042421Syokota 52142421Syokota error = 0; 52242421Syokota empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10); 52342421Syokota s = spltty(); 52442421Syokota if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc)) 52542421Syokota error = EIO; 52642421Syokota else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0) 52742421Syokota error = EIO; 52842421Syokota splx(s); 52942421Syokota 53042421Syokota return error; 53142421Syokota} 53242421Syokota 53342421Syokota/* 53442421Syokota * Enable the access to the device; until this function is called, 53542421Syokota * the client cannot read from the keyboard. 53642421Syokota */ 53742421Syokotastatic int 53842421Syokotaatkbd_enable(keyboard_t *kbd) 53942421Syokota{ 54042421Syokota int s; 54142421Syokota 54242421Syokota s = spltty(); 54342421Syokota KBD_ACTIVATE(kbd); 54442421Syokota splx(s); 54542421Syokota return 0; 54642421Syokota} 54742421Syokota 54842421Syokota/* disallow the access to the device */ 54942421Syokotastatic int 55042421Syokotaatkbd_disable(keyboard_t *kbd) 55142421Syokota{ 55242421Syokota int s; 55342421Syokota 55442421Syokota s = spltty(); 55542421Syokota KBD_DEACTIVATE(kbd); 55642421Syokota splx(s); 55742421Syokota return 0; 55842421Syokota} 55942421Syokota 56042421Syokota/* read one byte from the keyboard if it's allowed */ 56142421Syokotastatic int 56242421Syokotaatkbd_read(keyboard_t *kbd, int wait) 56342421Syokota{ 56442421Syokota int c; 56542421Syokota 56642421Syokota if (wait) 56742421Syokota c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc); 56842421Syokota else 56942421Syokota c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc); 57054382Syokota if (c != -1) 57154382Syokota ++kbd->kb_count; 57242421Syokota return (KBD_IS_ACTIVE(kbd) ? c : -1); 57342421Syokota} 57442421Syokota 57542421Syokota/* check if data is waiting */ 57642421Syokotastatic int 57742421Syokotaatkbd_check(keyboard_t *kbd) 57842421Syokota{ 57942421Syokota if (!KBD_IS_ACTIVE(kbd)) 58042421Syokota return FALSE; 58142421Syokota return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc); 58242421Syokota} 58342421Syokota 58442421Syokota/* read char from the keyboard */ 58542421Syokotastatic u_int 58642421Syokotaatkbd_read_char(keyboard_t *kbd, int wait) 58742421Syokota{ 58842421Syokota atkbd_state_t *state; 58942421Syokota u_int action; 59042421Syokota int scancode; 59142421Syokota int keycode; 59242421Syokota 59342421Syokota state = (atkbd_state_t *)kbd->kb_data; 59442421Syokotanext_code: 59542421Syokota /* do we have a composed char to return? */ 59642421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 59742421Syokota action = state->ks_composed_char; 59842421Syokota state->ks_composed_char = 0; 59942421Syokota if (action > UCHAR_MAX) 60042421Syokota return ERRKEY; 60142421Syokota return action; 60242421Syokota } 60342421Syokota 60442421Syokota /* see if there is something in the keyboard port */ 60542421Syokota if (wait) { 60642421Syokota do { 60742421Syokota scancode = read_kbd_data(state->kbdc); 60842421Syokota } while (scancode == -1); 60942421Syokota } else { 61042421Syokota scancode = read_kbd_data_no_wait(state->kbdc); 61142421Syokota if (scancode == -1) 61242421Syokota return NOKEY; 61342421Syokota } 61454382Syokota ++kbd->kb_count; 61542421Syokota 61654382Syokota#if KBDIO_DEBUG >= 10 61754382Syokota printf("atkbd_read_char(): scancode:0x%x\n", scancode); 61854382Syokota#endif 61954382Syokota 62042421Syokota /* return the byte as is for the K_RAW mode */ 62142421Syokota if (state->ks_mode == K_RAW) 62242421Syokota return scancode; 62342421Syokota 62442421Syokota /* translate the scan code into a keycode */ 62542421Syokota keycode = scancode & 0x7F; 62642421Syokota switch (state->ks_prefix) { 62742421Syokota case 0x00: /* normal scancode */ 62842421Syokota switch(scancode) { 62942421Syokota case 0xB8: /* left alt (compose key) released */ 63042421Syokota if (state->ks_flags & COMPOSE) { 63142421Syokota state->ks_flags &= ~COMPOSE; 63242421Syokota if (state->ks_composed_char > UCHAR_MAX) 63342421Syokota state->ks_composed_char = 0; 63442421Syokota } 63542421Syokota break; 63642421Syokota case 0x38: /* left alt (compose key) pressed */ 63742421Syokota if (!(state->ks_flags & COMPOSE)) { 63842421Syokota state->ks_flags |= COMPOSE; 63942421Syokota state->ks_composed_char = 0; 64042421Syokota } 64142421Syokota break; 64242421Syokota case 0xE0: 64342421Syokota case 0xE1: 64442421Syokota state->ks_prefix = scancode; 64542421Syokota goto next_code; 64642421Syokota } 64742421Syokota break; 64842421Syokota case 0xE0: /* 0xE0 prefix */ 64942421Syokota state->ks_prefix = 0; 65042421Syokota switch (keycode) { 65142421Syokota case 0x1C: /* right enter key */ 65242421Syokota keycode = 0x59; 65342421Syokota break; 65442421Syokota case 0x1D: /* right ctrl key */ 65542421Syokota keycode = 0x5A; 65642421Syokota break; 65742421Syokota case 0x35: /* keypad divide key */ 65842421Syokota keycode = 0x5B; 65942421Syokota break; 66042421Syokota case 0x37: /* print scrn key */ 66142421Syokota keycode = 0x5C; 66242421Syokota break; 66342421Syokota case 0x38: /* right alt key (alt gr) */ 66442421Syokota keycode = 0x5D; 66542421Syokota break; 66643337Syokota case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 66743337Syokota keycode = 0x68; 66843337Syokota break; 66942421Syokota case 0x47: /* grey home key */ 67042421Syokota keycode = 0x5E; 67142421Syokota break; 67242421Syokota case 0x48: /* grey up arrow key */ 67342421Syokota keycode = 0x5F; 67442421Syokota break; 67542421Syokota case 0x49: /* grey page up key */ 67642421Syokota keycode = 0x60; 67742421Syokota break; 67842421Syokota case 0x4B: /* grey left arrow key */ 67942421Syokota keycode = 0x61; 68042421Syokota break; 68142421Syokota case 0x4D: /* grey right arrow key */ 68242421Syokota keycode = 0x62; 68342421Syokota break; 68442421Syokota case 0x4F: /* grey end key */ 68542421Syokota keycode = 0x63; 68642421Syokota break; 68742421Syokota case 0x50: /* grey down arrow key */ 68842421Syokota keycode = 0x64; 68942421Syokota break; 69042421Syokota case 0x51: /* grey page down key */ 69142421Syokota keycode = 0x65; 69242421Syokota break; 69342421Syokota case 0x52: /* grey insert key */ 69442421Syokota keycode = 0x66; 69542421Syokota break; 69642421Syokota case 0x53: /* grey delete key */ 69742421Syokota keycode = 0x67; 69842421Syokota break; 69942421Syokota /* the following 3 are only used on the MS "Natural" keyboard */ 70042421Syokota case 0x5b: /* left Window key */ 70142421Syokota keycode = 0x69; 70242421Syokota break; 70342421Syokota case 0x5c: /* right Window key */ 70442421Syokota keycode = 0x6a; 70542421Syokota break; 70642421Syokota case 0x5d: /* menu key */ 70742421Syokota keycode = 0x6b; 70842421Syokota break; 709120875Sfjoe case 0x5e: /* power key */ 710120875Sfjoe keycode = 0x6d; 711120875Sfjoe break; 712120875Sfjoe case 0x5f: /* sleep key */ 713120875Sfjoe keycode = 0x6e; 714120875Sfjoe break; 715120875Sfjoe case 0x63: /* wake key */ 716120875Sfjoe keycode = 0x6f; 717120875Sfjoe break; 71842421Syokota default: /* ignore everything else */ 71942421Syokota goto next_code; 72042421Syokota } 72142421Syokota break; 72242421Syokota case 0xE1: /* 0xE1 prefix */ 72343337Syokota /* 72443337Syokota * The pause/break key on the 101 keyboard produces: 72543337Syokota * E1-1D-45 E1-9D-C5 72643337Syokota * Ctrl-pause/break produces: 72743337Syokota * E0-46 E0-C6 (See above.) 72843337Syokota */ 72942421Syokota state->ks_prefix = 0; 73042421Syokota if (keycode == 0x1D) 73142421Syokota state->ks_prefix = 0x1D; 73242421Syokota goto next_code; 73342421Syokota /* NOT REACHED */ 73442421Syokota case 0x1D: /* pause / break */ 73542421Syokota state->ks_prefix = 0; 73642421Syokota if (keycode != 0x45) 73743337Syokota goto next_code; 73842421Syokota keycode = 0x68; 73942421Syokota break; 74042421Syokota } 74142421Syokota 74243337Syokota if (kbd->kb_type == KB_84) { 74343337Syokota switch (keycode) { 74443337Syokota case 0x37: /* *(numpad)/print screen */ 74543337Syokota if (state->ks_flags & SHIFTS) 74643337Syokota keycode = 0x5c; /* print screen */ 74743337Syokota break; 74843337Syokota case 0x45: /* num lock/pause */ 74943337Syokota if (state->ks_flags & CTLS) 75043337Syokota keycode = 0x68; /* pause */ 75143337Syokota break; 75243337Syokota case 0x46: /* scroll lock/break */ 75343337Syokota if (state->ks_flags & CTLS) 75443337Syokota keycode = 0x6c; /* break */ 75543337Syokota break; 75643337Syokota } 75743337Syokota } else if (kbd->kb_type == KB_101) { 75843337Syokota switch (keycode) { 75943337Syokota case 0x5c: /* print screen */ 76043337Syokota if (state->ks_flags & ALTS) 76143337Syokota keycode = 0x54; /* sysrq */ 76243337Syokota break; 76343337Syokota case 0x68: /* pause/break */ 76443337Syokota if (state->ks_flags & CTLS) 76543337Syokota keycode = 0x6c; /* break */ 76643337Syokota break; 76743337Syokota } 76843337Syokota } 76943337Syokota 77042421Syokota /* return the key code in the K_CODE mode */ 77142421Syokota if (state->ks_mode == K_CODE) 77242421Syokota return (keycode | (scancode & 0x80)); 77342421Syokota 77442421Syokota /* compose a character code */ 77542421Syokota if (state->ks_flags & COMPOSE) { 77647293Syokota switch (keycode | (scancode & 0x80)) { 77742421Syokota /* key pressed, process it */ 77842421Syokota case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 77942421Syokota state->ks_composed_char *= 10; 78046765Syokota state->ks_composed_char += keycode - 0x40; 78142421Syokota if (state->ks_composed_char > UCHAR_MAX) 78242421Syokota return ERRKEY; 78342421Syokota goto next_code; 78442421Syokota case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 78542421Syokota state->ks_composed_char *= 10; 78646765Syokota state->ks_composed_char += keycode - 0x47; 78742421Syokota if (state->ks_composed_char > UCHAR_MAX) 78842421Syokota return ERRKEY; 78942421Syokota goto next_code; 79042421Syokota case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 79142421Syokota state->ks_composed_char *= 10; 79246765Syokota state->ks_composed_char += keycode - 0x4E; 79342421Syokota if (state->ks_composed_char > UCHAR_MAX) 79442421Syokota return ERRKEY; 79542421Syokota goto next_code; 79642421Syokota case 0x52: /* keypad 0 */ 79742421Syokota state->ks_composed_char *= 10; 79842421Syokota if (state->ks_composed_char > UCHAR_MAX) 79942421Syokota return ERRKEY; 80042421Syokota goto next_code; 80142421Syokota 80242421Syokota /* key released, no interest here */ 80342421Syokota case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 80442421Syokota case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 80542421Syokota case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 80642421Syokota case 0xD2: /* keypad 0 */ 80742421Syokota goto next_code; 80842421Syokota 80942421Syokota case 0x38: /* left alt key */ 81042421Syokota break; 81142421Syokota 81242421Syokota default: 81342421Syokota if (state->ks_composed_char > 0) { 81442421Syokota state->ks_flags &= ~COMPOSE; 81542421Syokota state->ks_composed_char = 0; 81642421Syokota return ERRKEY; 81742421Syokota } 81842421Syokota break; 81942421Syokota } 82042421Syokota } 82142421Syokota 82242421Syokota /* keycode to key action */ 82342421Syokota action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 82442421Syokota &state->ks_state, &state->ks_accents); 82542421Syokota if (action == NOKEY) 82642421Syokota goto next_code; 82742421Syokota else 82842421Syokota return action; 82942421Syokota} 83042421Syokota 83142421Syokota/* check if char is waiting */ 83242421Syokotastatic int 83342421Syokotaatkbd_check_char(keyboard_t *kbd) 83442421Syokota{ 83542421Syokota atkbd_state_t *state; 83642421Syokota 83742421Syokota if (!KBD_IS_ACTIVE(kbd)) 83842421Syokota return FALSE; 83942421Syokota state = (atkbd_state_t *)kbd->kb_data; 84042421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 84142421Syokota return TRUE; 84242421Syokota return kbdc_data_ready(state->kbdc); 84342421Syokota} 84442421Syokota 84542421Syokota/* some useful control functions */ 84642421Syokotastatic int 84742421Syokotaatkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 84842421Syokota{ 849147271Smarius /* translate LED_XXX bits into the device specific bits */ 85042421Syokota static u_char ledmap[8] = { 85142421Syokota 0, 4, 2, 6, 1, 5, 3, 7, 85242421Syokota }; 85342421Syokota atkbd_state_t *state = kbd->kb_data; 85442421Syokota int error; 85542421Syokota int s; 85642421Syokota int i; 857162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 858162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 859162711Sru int ival; 860162711Sru#endif 86142421Syokota 86242421Syokota s = spltty(); 86342421Syokota switch (cmd) { 86442421Syokota 86542421Syokota case KDGKBMODE: /* get keyboard mode */ 86642421Syokota *(int *)arg = state->ks_mode; 86742421Syokota break; 868162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 869162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 870162711Sru case _IO('K', 7): 871162711Sru ival = IOCPARM_IVAL(arg); 872162711Sru arg = (caddr_t)&ival; 873162711Sru /* FALLTHROUGH */ 874162711Sru#endif 87542421Syokota case KDSKBMODE: /* set keyboard mode */ 87642421Syokota switch (*(int *)arg) { 87742421Syokota case K_XLATE: 87842421Syokota if (state->ks_mode != K_XLATE) { 87942421Syokota /* make lock key state and LED state match */ 88042421Syokota state->ks_state &= ~LOCK_MASK; 88142421Syokota state->ks_state |= KBD_LED_VAL(kbd); 88242421Syokota } 883102412Scharnier /* FALLTHROUGH */ 88442421Syokota case K_RAW: 88542421Syokota case K_CODE: 88642421Syokota if (state->ks_mode != *(int *)arg) { 88742421Syokota atkbd_clear_state(kbd); 88842421Syokota state->ks_mode = *(int *)arg; 88942421Syokota } 89042421Syokota break; 89142421Syokota default: 89242421Syokota splx(s); 89342421Syokota return EINVAL; 89442421Syokota } 89542421Syokota break; 89642421Syokota 89742421Syokota case KDGETLED: /* get keyboard LED */ 89842421Syokota *(int *)arg = KBD_LED_VAL(kbd); 89942421Syokota break; 900162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 901162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 902162711Sru case _IO('K', 66): 903162711Sru ival = IOCPARM_IVAL(arg); 904162711Sru arg = (caddr_t)&ival; 905162711Sru /* FALLTHROUGH */ 906162711Sru#endif 90742421Syokota case KDSETLED: /* set keyboard LED */ 90842421Syokota /* NOTE: lock key state in ks_state won't be changed */ 90942421Syokota if (*(int *)arg & ~LOCK_MASK) { 91042421Syokota splx(s); 91142421Syokota return EINVAL; 91242421Syokota } 91342421Syokota i = *(int *)arg; 91442421Syokota /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 91561004Sache if (state->ks_mode == K_XLATE && 91661004Sache kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 91742421Syokota if (i & ALKED) 91842421Syokota i |= CLKED; 91942421Syokota else 92042421Syokota i &= ~CLKED; 92142421Syokota } 92242421Syokota if (KBD_HAS_DEVICE(kbd)) { 92342421Syokota error = write_kbd(state->kbdc, KBDC_SET_LEDS, 92442421Syokota ledmap[i & LED_MASK]); 92542421Syokota if (error) { 92642421Syokota splx(s); 92742421Syokota return error; 92842421Syokota } 92942421Syokota } 93042421Syokota KBD_LED_VAL(kbd) = *(int *)arg; 93142421Syokota break; 93242421Syokota 93342421Syokota case KDGKBSTATE: /* get lock key state */ 93442421Syokota *(int *)arg = state->ks_state & LOCK_MASK; 93542421Syokota break; 936162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 937162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 938162711Sru case _IO('K', 20): 939162711Sru ival = IOCPARM_IVAL(arg); 940162711Sru arg = (caddr_t)&ival; 941162711Sru /* FALLTHROUGH */ 942162711Sru#endif 94342421Syokota case KDSKBSTATE: /* set lock key state */ 94442421Syokota if (*(int *)arg & ~LOCK_MASK) { 94542421Syokota splx(s); 94642421Syokota return EINVAL; 94742421Syokota } 94842421Syokota state->ks_state &= ~LOCK_MASK; 94942421Syokota state->ks_state |= *(int *)arg; 95042421Syokota splx(s); 95142421Syokota /* set LEDs and quit */ 95242421Syokota return atkbd_ioctl(kbd, KDSETLED, arg); 95342421Syokota 95444628Syokota case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 95542421Syokota splx(s); 95642421Syokota if (!KBD_HAS_DEVICE(kbd)) 95742421Syokota return 0; 95844628Syokota i = typematic(((int *)arg)[0], ((int *)arg)[1]); 95954543Syokota error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); 96054543Syokota if (error == 0) { 96154543Syokota kbd->kb_delay1 = typematic_delay(i); 96254543Syokota kbd->kb_delay2 = typematic_rate(i); 96354543Syokota } 96454543Syokota return error; 96542421Syokota 966162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 967162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 968162711Sru case _IO('K', 67): 969162711Sru ival = IOCPARM_IVAL(arg); 970162711Sru arg = (caddr_t)&ival; 971162711Sru /* FALLTHROUGH */ 972162711Sru#endif 97344628Syokota case KDSETRAD: /* set keyboard repeat rate (old interface) */ 97444628Syokota splx(s); 97544628Syokota if (!KBD_HAS_DEVICE(kbd)) 97644628Syokota return 0; 97754543Syokota error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); 97854543Syokota if (error == 0) { 97954543Syokota kbd->kb_delay1 = typematic_delay(*(int *)arg); 98054543Syokota kbd->kb_delay2 = typematic_rate(*(int *)arg); 98154543Syokota } 98254543Syokota return error; 98344628Syokota 98442421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 98542421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 98642421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 98742421Syokota state->ks_accents = 0; 988102412Scharnier /* FALLTHROUGH */ 98942421Syokota default: 99042421Syokota splx(s); 99142421Syokota return genkbd_commonioctl(kbd, cmd, arg); 99242421Syokota } 99342421Syokota 99442421Syokota splx(s); 99542421Syokota return 0; 99642421Syokota} 99742421Syokota 99842421Syokota/* lock the access to the keyboard */ 99942421Syokotastatic int 100042421Syokotaatkbd_lock(keyboard_t *kbd, int lock) 100142421Syokota{ 100242421Syokota return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock); 100342421Syokota} 100442421Syokota 100542421Syokota/* clear the internal state of the keyboard */ 100642421Syokotastatic void 100742421Syokotaatkbd_clear_state(keyboard_t *kbd) 100842421Syokota{ 100942421Syokota atkbd_state_t *state; 101042421Syokota 101142421Syokota state = (atkbd_state_t *)kbd->kb_data; 101242421Syokota state->ks_flags = 0; 101344628Syokota state->ks_polling = 0; 101442421Syokota state->ks_state &= LOCK_MASK; /* preserve locking key state */ 101542421Syokota state->ks_accents = 0; 101642421Syokota state->ks_composed_char = 0; 101742421Syokota#if 0 101842421Syokota state->ks_prefix = 0; /* XXX */ 101942421Syokota#endif 102042421Syokota} 102142421Syokota 102242421Syokota/* save the internal state */ 102342421Syokotastatic int 102442421Syokotaatkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 102542421Syokota{ 102642421Syokota if (len == 0) 102742421Syokota return sizeof(atkbd_state_t); 102842421Syokota if (len < sizeof(atkbd_state_t)) 102942421Syokota return -1; 103042421Syokota bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t)); 103142421Syokota return 0; 103242421Syokota} 103342421Syokota 103442421Syokota/* set the internal state */ 103542421Syokotastatic int 103642421Syokotaatkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 103742421Syokota{ 103842421Syokota if (len < sizeof(atkbd_state_t)) 103942421Syokota return ENOMEM; 104042421Syokota if (((atkbd_state_t *)kbd->kb_data)->kbdc 104142421Syokota != ((atkbd_state_t *)buf)->kbdc) 104242421Syokota return ENOMEM; 104342421Syokota bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t)); 104442421Syokota return 0; 104542421Syokota} 104642421Syokota 104744628Syokotastatic int 104844628Syokotaatkbd_poll(keyboard_t *kbd, int on) 104944628Syokota{ 105044628Syokota atkbd_state_t *state; 105144628Syokota int s; 105244628Syokota 105344628Syokota state = (atkbd_state_t *)kbd->kb_data; 105444628Syokota s = spltty(); 105544628Syokota if (on) 105644628Syokota ++state->ks_polling; 105744628Syokota else 105844628Syokota --state->ks_polling; 105944628Syokota splx(s); 106044628Syokota return 0; 106144628Syokota} 106244628Syokota 1063147271Smariusstatic void 1064147271Smariusatkbd_shutdown_final(void *v) 1065147271Smarius{ 1066147271Smarius#ifdef __sparc64__ 1067147271Smarius keyboard_t *kbd = v; 1068147271Smarius KBDC kbdc = ((atkbd_state_t *)kbd->kb_data)->kbdc; 1069147271Smarius 1070147271Smarius /* 1071147271Smarius * Turn off the translation in preparation for handing the keyboard 1072147271Smarius * over to the OFW as the OBP driver doesn't use translation and 1073147271Smarius * also doesn't disable it itself resulting in a broken keymap at 1074147271Smarius * the boot prompt. Also disable the aux port and the interrupts as 1075147271Smarius * the OBP driver doesn't use them, i.e. polls the keyboard. Not 1076147271Smarius * disabling the interrupts doesn't cause real problems but the 1077147271Smarius * responsiveness is a bit better when they are turned off. 1078147271Smarius */ 1079147271Smarius send_kbd_command(kbdc, KBDC_DISABLE_KBD); 1080147271Smarius set_controller_command_byte(kbdc, 1081147271Smarius KBD_AUX_CONTROL_BITS | KBD_KBD_CONTROL_BITS | KBD_TRANSLATION, 1082147271Smarius KBD_DISABLE_AUX_PORT | KBD_DISABLE_KBD_INT | KBD_ENABLE_KBD_PORT); 1083147271Smarius send_kbd_command(kbdc, KBDC_ENABLE_KBD); 1084147271Smarius#endif 1085147271Smarius} 1086147271Smarius 108742421Syokota/* local functions */ 108842421Syokota 108942421Syokotastatic int 109055731Syokotaget_typematic(keyboard_t *kbd) 109155731Syokota{ 1092197501Sjkim#if defined(__i386__) || defined(__amd64__) 109355731Syokota /* 1094198251Sjkim * Only some systems allow us to retrieve the keyboard repeat 109555731Syokota * rate previously set via the BIOS... 109655731Syokota */ 1097197384Sdelphij x86regs_t regs; 1098197501Sjkim uint8_t *p; 109955731Syokota 1100222967Sdelphij /* 1101222967Sdelphij * Traditional entry points of int 0x15 and 0x16 are fixed 1102222967Sdelphij * and later BIOSes follow them. (U)EFI CSM specification 1103223341Sdelphij * also mandates these fixed entry points. 1104222967Sdelphij * 1105222967Sdelphij * Validate the entry points here before we proceed further. 1106222967Sdelphij * It's known that some recent laptops does not have the 1107222967Sdelphij * same entry point and hang on boot if we call it. 1108222967Sdelphij */ 1109222795Sjkim if (x86bios_get_intr(0x15) != 0xf000f859 || 1110222795Sjkim x86bios_get_intr(0x16) != 0xf000e82e) 1111198251Sjkim return (ENODEV); 1112198251Sjkim 1113197501Sjkim /* Is BIOS system configuration table supported? */ 1114198251Sjkim x86bios_init_regs(®s); 1115197501Sjkim regs.R_AH = 0xc0; 1116197466Sjkim x86bios_intr(®s, 0x15); 1117197504Sjkim if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0) 1118197501Sjkim return (ENODEV); 1119197501Sjkim 1120198251Sjkim /* Is int 0x16, function 0x09 supported? */ 1121197501Sjkim p = x86bios_offset((regs.R_ES << 4) + regs.R_BX); 1122197501Sjkim if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0) 1123197501Sjkim return (ENODEV); 1124197501Sjkim 1125198251Sjkim /* Is int 0x16, function 0x0306 supported? */ 1126198251Sjkim x86bios_init_regs(®s); 1127197501Sjkim regs.R_AH = 0x09; 1128197466Sjkim x86bios_intr(®s, 0x16); 1129197501Sjkim if ((regs.R_AL & 0x08) == 0) 1130197501Sjkim return (ENODEV); 1131197501Sjkim 1132198251Sjkim x86bios_init_regs(®s); 1133197384Sdelphij regs.R_AX = 0x0306; 1134197466Sjkim x86bios_intr(®s, 0x16); 1135197384Sdelphij kbd->kb_delay1 = typematic_delay(regs.R_BH << 5); 1136197384Sdelphij kbd->kb_delay2 = typematic_rate(regs.R_BL); 1137197501Sjkim return (0); 113855731Syokota#else 1139197501Sjkim return (ENODEV); 1140197384Sdelphij#endif /* __i386__ || __amd64__ */ 114155731Syokota} 114255731Syokota 114355731Syokotastatic int 114442421Syokotasetup_kbd_port(KBDC kbdc, int port, int intr) 114542421Syokota{ 114642421Syokota if (!set_controller_command_byte(kbdc, 114742421Syokota KBD_KBD_CONTROL_BITS, 114842421Syokota ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) 114942421Syokota | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT))) 115042421Syokota return 1; 115142421Syokota return 0; 115242421Syokota} 115342421Syokota 115442421Syokotastatic int 115542421Syokotaget_kbd_echo(KBDC kbdc) 115642421Syokota{ 115742421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 115842421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) 115942421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 116042421Syokota return ENXIO; 116142421Syokota 116242421Syokota /* see if something is present */ 116342421Syokota write_kbd_command(kbdc, KBDC_ECHO); 116442421Syokota if (read_kbd_data(kbdc) != KBD_ECHO) { 116542421Syokota empty_both_buffers(kbdc, 10); 116642421Syokota test_controller(kbdc); 116742421Syokota test_kbd_port(kbdc); 116842421Syokota return ENXIO; 116942421Syokota } 117042421Syokota 117142421Syokota /* enable the keyboard port and intr. */ 117242421Syokota if (setup_kbd_port(kbdc, TRUE, TRUE)) { 117342421Syokota /* 117442421Syokota * CONTROLLER ERROR 117542421Syokota * This is serious; the keyboard intr is left disabled! 117642421Syokota */ 117742421Syokota return ENXIO; 117842421Syokota } 117942421Syokota 118042421Syokota return 0; 118142421Syokota} 118242421Syokota 118342421Syokotastatic int 118442421Syokotaprobe_keyboard(KBDC kbdc, int flags) 118542421Syokota{ 118642421Syokota /* 118742421Syokota * Don't try to print anything in this function. The low-level 118842421Syokota * console may not have been initialized yet... 118942421Syokota */ 119042421Syokota int err; 119142421Syokota int c; 119242421Syokota int m; 119342421Syokota 119442421Syokota if (!kbdc_lock(kbdc, TRUE)) { 119542421Syokota /* driver error? */ 119642421Syokota return ENXIO; 119742421Syokota } 119842421Syokota 119957131Syokota /* temporarily block data transmission from the keyboard */ 120057131Syokota write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 120157131Syokota 120242421Syokota /* flush any noise in the buffer */ 120357131Syokota empty_both_buffers(kbdc, 100); 120442421Syokota 120542421Syokota /* save the current keyboard controller command byte */ 120642421Syokota m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; 120742421Syokota c = get_controller_command_byte(kbdc); 120842421Syokota if (c == -1) { 120942421Syokota /* CONTROLLER ERROR */ 121042421Syokota kbdc_set_device_mask(kbdc, m); 121142421Syokota kbdc_lock(kbdc, FALSE); 121242421Syokota return ENXIO; 121342421Syokota } 121442421Syokota 121542421Syokota /* 121642421Syokota * The keyboard may have been screwed up by the boot block. 121742421Syokota * We may just be able to recover from error by testing the controller 121842421Syokota * and the keyboard port. The controller command byte needs to be 121942421Syokota * saved before this recovery operation, as some controllers seem 122042421Syokota * to set the command byte to particular values. 122142421Syokota */ 122242421Syokota test_controller(kbdc); 1223138900Sjhb if (!(flags & KB_CONF_NO_PROBE_TEST)) 1224138900Sjhb test_kbd_port(kbdc); 122542421Syokota 122642421Syokota err = get_kbd_echo(kbdc); 122757902Syokota 122857902Syokota /* 122957902Syokota * Even if the keyboard doesn't seem to be present (err != 0), 123057902Syokota * we shall enable the keyboard port and interrupt so that 123157902Syokota * the driver will be operable when the keyboard is attached 123257902Syokota * to the system later. It is NOT recommended to hot-plug 123357902Syokota * the AT keyboard, but many people do so... 123457902Syokota */ 123557902Syokota kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 123657902Syokota setup_kbd_port(kbdc, TRUE, TRUE); 123757902Syokota#if 0 123842421Syokota if (err == 0) { 123942421Syokota kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 124042421Syokota } else { 124157131Syokota /* try to restore the command byte as before */ 124257131Syokota set_controller_command_byte(kbdc, 0xff, c); 124342421Syokota kbdc_set_device_mask(kbdc, m); 124442421Syokota } 124557902Syokota#endif 124642421Syokota 124742421Syokota kbdc_lock(kbdc, FALSE); 124842421Syokota return err; 124942421Syokota} 125042421Syokota 125142421Syokotastatic int 125242421Syokotainit_keyboard(KBDC kbdc, int *type, int flags) 125342421Syokota{ 125442421Syokota int codeset; 125542421Syokota int id; 125642421Syokota int c; 125742421Syokota 125842421Syokota if (!kbdc_lock(kbdc, TRUE)) { 125942421Syokota /* driver error? */ 126042421Syokota return EIO; 126142421Syokota } 126242421Syokota 126357131Syokota /* temporarily block data transmission from the keyboard */ 126457131Syokota write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 126557131Syokota 126642421Syokota /* save the current controller command byte */ 126754382Syokota empty_both_buffers(kbdc, 200); 126842421Syokota c = get_controller_command_byte(kbdc); 126942421Syokota if (c == -1) { 127042421Syokota /* CONTROLLER ERROR */ 127142421Syokota kbdc_lock(kbdc, FALSE); 127242421Syokota printf("atkbd: unable to get the current command byte value.\n"); 127342421Syokota return EIO; 127442421Syokota } 127542421Syokota if (bootverbose) 127642421Syokota printf("atkbd: the current kbd controller command byte %04x\n", 127742421Syokota c); 127842421Syokota#if 0 127942421Syokota /* override the keyboard lock switch */ 128042421Syokota c |= KBD_OVERRIDE_KBD_LOCK; 128142421Syokota#endif 128242421Syokota 128342421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 128442421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) { 128542421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 128642421Syokota printf("atkbd: unable to set the command byte.\n"); 128742421Syokota kbdc_lock(kbdc, FALSE); 128842421Syokota return EIO; 128942421Syokota } 129042421Syokota 129142421Syokota /* 129242421Syokota * Check if we have an XT keyboard before we attempt to reset it. 129342421Syokota * The procedure assumes that the keyboard and the controller have 129442421Syokota * been set up properly by BIOS and have not been messed up 129542421Syokota * during the boot process. 129642421Syokota */ 129742421Syokota codeset = -1; 129842421Syokota if (flags & KB_CONF_ALT_SCANCODESET) 129942421Syokota /* the user says there is a XT keyboard */ 130042421Syokota codeset = 1; 130142421Syokota#ifdef KBD_DETECT_XT_KEYBOARD 130242421Syokota else if ((c & KBD_TRANSLATION) == 0) { 130342421Syokota /* SET_SCANCODE_SET is not always supported; ignore error */ 130442421Syokota if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0) 130542421Syokota == KBD_ACK) 130642421Syokota codeset = read_kbd_data(kbdc); 130742421Syokota } 130842421Syokota if (bootverbose) 130942421Syokota printf("atkbd: scancode set %d\n", codeset); 131042421Syokota#endif /* KBD_DETECT_XT_KEYBOARD */ 131142421Syokota 131242421Syokota *type = KB_OTHER; 131342421Syokota id = get_kbd_id(kbdc); 131442421Syokota switch(id) { 131555730Syokota case 0x41ab: /* 101/102/... Enhanced */ 131655730Syokota case 0x83ab: /* ditto */ 131755730Syokota case 0x54ab: /* SpaceSaver */ 131855730Syokota case 0x84ab: /* ditto */ 131955730Syokota#if 0 132055730Syokota case 0x90ab: /* 'G' */ 132155730Syokota case 0x91ab: /* 'P' */ 132255730Syokota case 0x92ab: /* 'A' */ 132355730Syokota#endif 132442421Syokota *type = KB_101; 132542421Syokota break; 132642421Syokota case -1: /* AT 84 keyboard doesn't return ID */ 132742421Syokota *type = KB_84; 132842421Syokota break; 132942421Syokota default: 133042421Syokota break; 133142421Syokota } 133242421Syokota if (bootverbose) 133342421Syokota printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type); 133442421Syokota 133542421Syokota /* reset keyboard hardware */ 133642421Syokota if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { 133742421Syokota /* 133842421Syokota * KEYBOARD ERROR 133942421Syokota * Keyboard reset may fail either because the keyboard 134042421Syokota * doen't exist, or because the keyboard doesn't pass 134142421Syokota * the self-test, or the keyboard controller on the 134242421Syokota * motherboard and the keyboard somehow fail to shake hands. 134342421Syokota * It is just possible, particularly in the last case, 1344110398Scharnier * that the keyboard controller may be left in a hung state. 134542421Syokota * test_controller() and test_kbd_port() appear to bring 134642421Syokota * the keyboard controller back (I don't know why and how, 134742421Syokota * though.) 134842421Syokota */ 134942421Syokota empty_both_buffers(kbdc, 10); 135042421Syokota test_controller(kbdc); 135142421Syokota test_kbd_port(kbdc); 135242421Syokota /* 135342421Syokota * We could disable the keyboard port and interrupt... but, 135442421Syokota * the keyboard may still exist (see above). 135542421Syokota */ 135642421Syokota set_controller_command_byte(kbdc, 0xff, c); 135742421Syokota kbdc_lock(kbdc, FALSE); 135842421Syokota if (bootverbose) 135942421Syokota printf("atkbd: failed to reset the keyboard.\n"); 136042421Syokota return EIO; 136142421Syokota } 136242421Syokota 136342421Syokota /* 136494275Sphk * Allow us to set the XT_KEYBD flag so that keyboards 136542421Syokota * such as those on the IBM ThinkPad laptop computers can be used 136642421Syokota * with the standard console driver. 136742421Syokota */ 136842421Syokota if (codeset == 1) { 136942421Syokota if (send_kbd_command_and_data(kbdc, 137042421Syokota KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 137142421Syokota /* XT kbd doesn't need scan code translation */ 137242421Syokota c &= ~KBD_TRANSLATION; 137342421Syokota } else { 137442421Syokota /* 137542421Syokota * KEYBOARD ERROR 137642421Syokota * The XT kbd isn't usable unless the proper scan 137742421Syokota * code set is selected. 137842421Syokota */ 137942421Syokota set_controller_command_byte(kbdc, 0xff, c); 138042421Syokota kbdc_lock(kbdc, FALSE); 138142421Syokota printf("atkbd: unable to set the XT keyboard mode.\n"); 138242421Syokota return EIO; 138342421Syokota } 138442421Syokota } 138542421Syokota 1386158471Sjhb#if defined(__sparc64__) 138742831Syokota if (send_kbd_command_and_data( 138842831Syokota kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) { 138942831Syokota printf("atkbd: can't set translation.\n"); 139042831Syokota } 139142831Syokota c |= KBD_TRANSLATION; 139242831Syokota#endif 139342831Syokota 139442421Syokota /* enable the keyboard port and intr. */ 139542421Syokota if (!set_controller_command_byte(kbdc, 139642421Syokota KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 139742421Syokota (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 139842421Syokota | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 139942421Syokota /* 140042421Syokota * CONTROLLER ERROR 140142421Syokota * This is serious; we are left with the disabled 140242421Syokota * keyboard intr. 140342421Syokota */ 140442421Syokota set_controller_command_byte(kbdc, 0xff, c); 140542421Syokota kbdc_lock(kbdc, FALSE); 140642421Syokota printf("atkbd: unable to enable the keyboard port and intr.\n"); 140742421Syokota return EIO; 140842421Syokota } 140942421Syokota 141042421Syokota kbdc_lock(kbdc, FALSE); 141142421Syokota return 0; 141242421Syokota} 141342421Syokota 141442421Syokotastatic int 141542421Syokotawrite_kbd(KBDC kbdc, int command, int data) 141642421Syokota{ 141742421Syokota int s; 141842421Syokota 141942421Syokota /* prevent the timeout routine from polling the keyboard */ 142042421Syokota if (!kbdc_lock(kbdc, TRUE)) 142142421Syokota return EBUSY; 142242421Syokota 142342421Syokota /* disable the keyboard and mouse interrupt */ 142442421Syokota s = spltty(); 142542421Syokota#if 0 142642421Syokota c = get_controller_command_byte(kbdc); 142742421Syokota if ((c == -1) 142842421Syokota || !set_controller_command_byte(kbdc, 142942421Syokota kbdc_get_device_mask(kbdc), 143042421Syokota KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 143142421Syokota | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 143242421Syokota /* CONTROLLER ERROR */ 143342421Syokota kbdc_lock(kbdc, FALSE); 143442421Syokota splx(s); 143542421Syokota return EIO; 143642421Syokota } 143742421Syokota /* 143842421Syokota * Now that the keyboard controller is told not to generate 143942421Syokota * the keyboard and mouse interrupts, call `splx()' to allow 144042421Syokota * the other tty interrupts. The clock interrupt may also occur, 144142421Syokota * but the timeout routine (`scrn_timer()') will be blocked 144242421Syokota * by the lock flag set via `kbdc_lock()' 144342421Syokota */ 144442421Syokota splx(s); 144542421Syokota#endif 144642421Syokota 144742421Syokota if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) 144842421Syokota send_kbd_command(kbdc, KBDC_ENABLE_KBD); 144942421Syokota 145042421Syokota#if 0 145142421Syokota /* restore the interrupts */ 145242421Syokota if (!set_controller_command_byte(kbdc, 145342421Syokota kbdc_get_device_mask(kbdc), 145442421Syokota c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 145542421Syokota /* CONTROLLER ERROR */ 145642421Syokota } 145742421Syokota#else 145842421Syokota splx(s); 145942421Syokota#endif 146042421Syokota kbdc_lock(kbdc, FALSE); 146142421Syokota 146242421Syokota return 0; 146342421Syokota} 146442421Syokota 146542421Syokotastatic int 146642421Syokotaget_kbd_id(KBDC kbdc) 146742421Syokota{ 146842421Syokota int id1, id2; 146942421Syokota 147042421Syokota empty_both_buffers(kbdc, 10); 147142421Syokota id1 = id2 = -1; 147242421Syokota if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK) 147342421Syokota return -1; 147442421Syokota 147542421Syokota DELAY(10000); /* 10 msec delay */ 147642421Syokota id1 = read_kbd_data(kbdc); 147742421Syokota if (id1 != -1) 147842421Syokota id2 = read_kbd_data(kbdc); 147942421Syokota 148042421Syokota if ((id1 == -1) || (id2 == -1)) { 148142421Syokota empty_both_buffers(kbdc, 10); 148242421Syokota test_controller(kbdc); 148342421Syokota test_kbd_port(kbdc); 148442421Syokota return -1; 148542421Syokota } 148642421Syokota return ((id2 << 8) | id1); 148742421Syokota} 148842421Syokota 148954543Syokotastatic int delays[] = { 250, 500, 750, 1000 }; 149054543Syokotastatic int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 149154543Syokota 68, 76, 84, 92, 100, 110, 118, 126, 149254543Syokota 136, 152, 168, 184, 200, 220, 236, 252, 149354543Syokota 272, 304, 336, 368, 400, 440, 472, 504 }; 149454543Syokota 149544628Syokotastatic int 149654543Syokotatypematic_delay(int i) 149754543Syokota{ 149854543Syokota return delays[(i >> 5) & 3]; 149954543Syokota} 150054543Syokota 150154543Syokotastatic int 150254543Syokotatypematic_rate(int i) 150354543Syokota{ 150454543Syokota return rates[i & 0x1f]; 150554543Syokota} 150654543Syokota 150754543Syokotastatic int 150844628Syokotatypematic(int delay, int rate) 150944628Syokota{ 151044628Syokota int value; 151144628Syokota int i; 151244628Syokota 151344628Syokota for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { 151444628Syokota if (delay >= delays[i]) 151544628Syokota break; 151644628Syokota } 151744628Syokota value = i << 5; 151844628Syokota for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { 151944628Syokota if (rate >= rates[i]) 152044628Syokota break; 152144628Syokota } 152244628Syokota value |= i; 152344628Syokota return value; 152444628Syokota} 1525