atkbd.c revision 119418
1285612Sdelphij/*- 2285612Sdelphij * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3285612Sdelphij * All rights reserved. 4285612Sdelphij * 5285612Sdelphij * Redistribution and use in source and binary forms, with or without 6285612Sdelphij * modification, are permitted provided that the following conditions 7285612Sdelphij * are met: 8285612Sdelphij * 1. Redistributions of source code must retain the above copyright 9285612Sdelphij * notice, this list of conditions and the following disclaimer as 1054359Sroberto * the first lines of this file unmodified. 11285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 1254359Sroberto * notice, this list of conditions and the following disclaimer in the 1354359Sroberto * documentation and/or other materials provided with the distribution. 1454359Sroberto * 1554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1654359Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1782498Sroberto * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1854359Sroberto * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1954359Sroberto * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2082498Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2182498Sroberto * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22106163Sroberto * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23285612Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24106163Sroberto * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2582498Sroberto * 2682498Sroberto */ 2782498Sroberto 2882498Sroberto#include <sys/cdefs.h> 29285612Sdelphij__FBSDID("$FreeBSD: head/sys/dev/atkbdc/atkbd.c 119418 2003-08-24 17:55:58Z obrien $"); 30285612Sdelphij 31285612Sdelphij#include "opt_kbd.h" 3282498Sroberto#include "opt_atkbd.h" 33285612Sdelphij 34285612Sdelphij#include <sys/param.h> 3554359Sroberto#include <sys/systm.h> 36285612Sdelphij#include <sys/kernel.h> 37285612Sdelphij#include <sys/bus.h> 38285612Sdelphij#include <sys/proc.h> 39285612Sdelphij#include <sys/limits.h> 40285612Sdelphij#include <sys/malloc.h> 41285612Sdelphij 42285612Sdelphij#include <machine/bus.h> 43285612Sdelphij#include <machine/resource.h> 44285612Sdelphij 45285612Sdelphij#ifdef __i386__ 46182007Sroberto#include <machine/md_var.h> 47182007Sroberto#include <machine/psl.h> 48182007Sroberto#include <machine/vm86.h> 49182007Sroberto#include <machine/pc/bios.h> 50182007Sroberto 51182007Sroberto#include <vm/vm.h> 52285612Sdelphij#include <vm/pmap.h> 53285612Sdelphij#endif /* __i386__ */ 54285612Sdelphij 55182007Sroberto#include <sys/kbio.h> 56309008Sdelphij#include <dev/kbd/kbdreg.h> 57309008Sdelphij#include <dev/kbd/atkbdreg.h> 58309008Sdelphij#include <dev/kbd/atkbdcreg.h> 59309008Sdelphij 60309008Sdelphij#include <isa/isareg.h> 61309008Sdelphij 62294569Sdelphijstatic timeout_t atkbd_timeout; 63294569Sdelphij 64289997Sglebiusint 65289997Sglebiusatkbd_probe_unit(int unit, int ctlr, int irq, int flags) 66289997Sglebius{ 67289997Sglebius keyboard_switch_t *sw; 6882498Sroberto int args[2]; 69285612Sdelphij int error; 70285612Sdelphij 71285612Sdelphij sw = kbd_get_switch(ATKBD_DRIVER_NAME); 7254359Sroberto if (sw == NULL) 73289997Sglebius return ENXIO; 74289997Sglebius 75289997Sglebius args[0] = ctlr; 76289997Sglebius args[1] = irq; 77289997Sglebius error = (*sw->probe)(unit, args, flags); 78289997Sglebius if (error) 7954359Sroberto return error; 8054359Sroberto return 0; 8154359Sroberto} 8254359Sroberto 8354359Srobertoint 84285612Sdelphijatkbd_attach_unit(int unit, keyboard_t **kbd, int ctlr, int irq, int flags) 85285612Sdelphij{ 8654359Sroberto keyboard_switch_t *sw; 8754359Sroberto int args[2]; 8854359Sroberto int error; 89285612Sdelphij 90285612Sdelphij sw = kbd_get_switch(ATKBD_DRIVER_NAME); 91285612Sdelphij if (sw == NULL) 92285612Sdelphij return ENXIO; 93285612Sdelphij 9454359Sroberto /* reset, initialize and enable the device */ 9554359Sroberto args[0] = ctlr; 96285612Sdelphij args[1] = irq; 97285612Sdelphij *kbd = NULL; 98285612Sdelphij error = (*sw->probe)(unit, args, flags); 99285612Sdelphij if (error) 100285612Sdelphij return error; 101285612Sdelphij error = (*sw->init)(unit, kbd, args, flags); 102285612Sdelphij if (error) 103285612Sdelphij return error; 104285612Sdelphij (*sw->enable)(*kbd); 105285612Sdelphij 106285612Sdelphij#ifdef KBD_INSTALL_CDEV 107285612Sdelphij /* attach a virtual keyboard cdev */ 108285612Sdelphij error = kbd_attach(*kbd); 109285612Sdelphij if (error) 110285612Sdelphij return error; 111285612Sdelphij#endif 112285612Sdelphij 113285612Sdelphij /* 11454359Sroberto * This is a kludge to compensate for lost keyboard interrupts. 11554359Sroberto * A similar code used to be in syscons. See below. XXX 11654359Sroberto */ 11754359Sroberto atkbd_timeout(*kbd); 118285612Sdelphij 11954359Sroberto if (bootverbose) 12054359Sroberto (*sw->diag)(*kbd, bootverbose); 121285612Sdelphij return 0; 122285612Sdelphij} 123285612Sdelphij 124285612Sdelphijstatic void 125285612Sdelphijatkbd_timeout(void *arg) 126285612Sdelphij{ 127285612Sdelphij keyboard_t *kbd; 128285612Sdelphij int s; 129285612Sdelphij 130285612Sdelphij /* 131285612Sdelphij * The original text of the following comments are extracted 132285612Sdelphij * from syscons.c (1.287) 133285612Sdelphij * 134285612Sdelphij * With release 2.1 of the Xaccel server, the keyboard is left 135182007Sroberto * hanging pretty often. Apparently an interrupt from the 13654359Sroberto * keyboard is lost, and I don't know why (yet). 13754359Sroberto * This ugly hack calls the low-level interrupt routine if input 13854359Sroberto * is ready for the keyboard and conveniently hides the problem. XXX 13954359Sroberto * 14054359Sroberto * Try removing anything stuck in the keyboard controller; whether 14154359Sroberto * it's a keyboard scan code or mouse data. The low-level 14254359Sroberto * interrupt routine doesn't read the mouse data directly, 14354359Sroberto * but the keyboard controller driver will, as a side effect. 144285612Sdelphij */ 14582498Sroberto /* 14654359Sroberto * And here is bde's original comment about this: 14754359Sroberto * 14854359Sroberto * This is necessary to handle edge triggered interrupts - if we 149285612Sdelphij * returned when our IRQ is high due to unserviced input, then there 150285612Sdelphij * would be no more keyboard IRQs until the keyboard is reset by 151285612Sdelphij * external powers. 152330141Sdelphij * 153285612Sdelphij * The keyboard apparently unwedges the irq in most cases. 154330141Sdelphij */ 155285612Sdelphij s = spltty(); 15654359Sroberto kbd = (keyboard_t *)arg; 15754359Sroberto if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { 15854359Sroberto /* 15954359Sroberto * We have seen the lock flag is not set. Let's reset 16054359Sroberto * the flag early, otherwise the LED update routine fails 16182498Sroberto * which may want the lock during the interrupt routine. 162285612Sdelphij */ 163285612Sdelphij (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); 164285612Sdelphij if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) 165285612Sdelphij (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 166285612Sdelphij } 167285612Sdelphij splx(s); 168285612Sdelphij timeout(atkbd_timeout, arg, hz/10); 16982498Sroberto} 170285612Sdelphij 171285612Sdelphij/* LOW-LEVEL */ 17282498Sroberto 17382498Sroberto#define ATKBD_DEFAULT 0 174285612Sdelphij 175285612Sdelphijtypedef struct atkbd_state { 176285612Sdelphij KBDC kbdc; /* keyboard controller */ 177285612Sdelphij /* XXX: don't move this field; pcvt 17882498Sroberto * expects `kbdc' to be the first 17954359Sroberto * field in this structure. */ 18054359Sroberto int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 18154359Sroberto int ks_flags; /* flags */ 18254359Sroberto#define COMPOSE (1 << 0) 18354359Sroberto int ks_polling; 18454359Sroberto int ks_state; /* shift/lock key state */ 18554359Sroberto int ks_accents; /* accent key index (> 0) */ 18654359Sroberto u_int ks_composed_char; /* composed char code (> 0) */ 18754359Sroberto u_char ks_prefix; /* AT scan code prefix */ 18854359Sroberto} atkbd_state_t; 189285612Sdelphij 19054359Sroberto/* keyboard driver declaration */ 19154359Srobertostatic int atkbd_configure(int flags); 19254359Srobertostatic kbd_probe_t atkbd_probe; 193285612Sdelphijstatic kbd_init_t atkbd_init; 194285612Sdelphijstatic kbd_term_t atkbd_term; 195285612Sdelphijstatic kbd_intr_t atkbd_intr; 196285612Sdelphijstatic kbd_test_if_t atkbd_test_if; 197285612Sdelphijstatic kbd_enable_t atkbd_enable; 198285612Sdelphijstatic kbd_disable_t atkbd_disable; 199285612Sdelphijstatic kbd_read_t atkbd_read; 200285612Sdelphijstatic kbd_check_t atkbd_check; 201285612Sdelphijstatic kbd_read_char_t atkbd_read_char; 202285612Sdelphijstatic kbd_check_char_t atkbd_check_char; 203285612Sdelphijstatic kbd_ioctl_t atkbd_ioctl; 204285612Sdelphijstatic kbd_lock_t atkbd_lock; 20554359Srobertostatic kbd_clear_state_t atkbd_clear_state; 206285612Sdelphijstatic kbd_get_state_t atkbd_get_state; 20754359Srobertostatic kbd_set_state_t atkbd_set_state; 208285612Sdelphijstatic kbd_poll_mode_t atkbd_poll; 209285612Sdelphij 210285612Sdelphijstatic keyboard_switch_t atkbdsw = { 211285612Sdelphij atkbd_probe, 212285612Sdelphij atkbd_init, 213285612Sdelphij atkbd_term, 214285612Sdelphij atkbd_intr, 215285612Sdelphij atkbd_test_if, 216285612Sdelphij atkbd_enable, 217285612Sdelphij atkbd_disable, 218285612Sdelphij atkbd_read, 219285612Sdelphij atkbd_check, 22054359Sroberto atkbd_read_char, 221285612Sdelphij atkbd_check_char, 222285612Sdelphij atkbd_ioctl, 223285612Sdelphij atkbd_lock, 224285612Sdelphij atkbd_clear_state, 225285612Sdelphij atkbd_get_state, 226285612Sdelphij atkbd_set_state, 227285612Sdelphij genkbd_get_fkeystr, 228285612Sdelphij atkbd_poll, 229285612Sdelphij genkbd_diag, 230285612Sdelphij}; 231285612Sdelphij 232285612SdelphijKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); 233285612Sdelphij 234285612Sdelphij/* local functions */ 235285612Sdelphijstatic int get_typematic(keyboard_t *kbd); 236285612Sdelphijstatic int setup_kbd_port(KBDC kbdc, int port, int intr); 237285612Sdelphijstatic int get_kbd_echo(KBDC kbdc); 238285612Sdelphijstatic int probe_keyboard(KBDC kbdc, int flags); 239285612Sdelphijstatic int init_keyboard(KBDC kbdc, int *type, int flags); 240285612Sdelphijstatic int write_kbd(KBDC kbdc, int command, int data); 241285612Sdelphijstatic int get_kbd_id(KBDC kbdc); 242285612Sdelphijstatic int typematic(int delay, int rate); 243285612Sdelphijstatic int typematic_delay(int delay); 244285612Sdelphijstatic int typematic_rate(int rate); 245285612Sdelphij 246285612Sdelphij/* local variables */ 247285612Sdelphij 248285612Sdelphij/* the initial key map, accent map and fkey strings */ 249285612Sdelphij#ifdef ATKBD_DFLT_KEYMAP 250285612Sdelphij#define KBD_DFLT_KEYMAP 251285612Sdelphij#include "atkbdmap.h" 252285612Sdelphij#endif 253285612Sdelphij#include <dev/kbd/kbdtables.h> 254285612Sdelphij 255285612Sdelphij/* structures for the default keyboard */ 256285612Sdelphijstatic keyboard_t default_kbd; 257285612Sdelphijstatic atkbd_state_t default_kbd_state; 258285612Sdelphijstatic keymap_t default_keymap; 259285612Sdelphijstatic accentmap_t default_accentmap; 260285612Sdelphijstatic fkeytab_t default_fkeytab[NUM_FKEYS]; 261285612Sdelphij 262285612Sdelphij/* 263285612Sdelphij * The back door to the keyboard driver! 264285612Sdelphij * This function is called by the console driver, via the kbdio module, 265285612Sdelphij * to tickle keyboard drivers when the low-level console is being initialized. 266285612Sdelphij * Almost nothing in the kernel has been initialied yet. Try to probe 267285612Sdelphij * keyboards if possible. 268285612Sdelphij * NOTE: because of the way the low-level console is initialized, this routine 269285612Sdelphij * may be called more than once!! 270285612Sdelphij */ 271285612Sdelphijstatic int 272285612Sdelphijatkbd_configure(int flags) 273285612Sdelphij{ 274285612Sdelphij keyboard_t *kbd; 275285612Sdelphij int arg[2]; 276285612Sdelphij int i; 277285612Sdelphij 278285612Sdelphij /* probe the keyboard controller */ 279285612Sdelphij atkbdc_configure(); 280285612Sdelphij 281285612Sdelphij /* if the driver is disabled, unregister the keyboard if any */ 282285612Sdelphij if (resource_disabled("atkbd", ATKBD_DEFAULT)) { 283285612Sdelphij i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT); 284285612Sdelphij if (i >= 0) { 285285612Sdelphij kbd = kbd_get_keyboard(i); 286285612Sdelphij kbd_unregister(kbd); 287285612Sdelphij kbd->kb_flags &= ~KB_REGISTERED; 288285612Sdelphij } 289285612Sdelphij return 0; 290285612Sdelphij } 291285612Sdelphij 292285612Sdelphij /* XXX: a kludge to obtain the device configuration flags */ 293285612Sdelphij if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0) 294285612Sdelphij flags |= i; 295285612Sdelphij 296285612Sdelphij /* probe the default keyboard */ 297285612Sdelphij arg[0] = -1; 298285612Sdelphij arg[1] = -1; 299285612Sdelphij kbd = NULL; 300285612Sdelphij if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) 301285612Sdelphij return 0; 302285612Sdelphij if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) 303285612Sdelphij return 0; 304285612Sdelphij 305285612Sdelphij /* return the number of found keyboards */ 306285612Sdelphij return 1; 307285612Sdelphij} 308285612Sdelphij 309285612Sdelphij/* low-level functions */ 310285612Sdelphij 311285612Sdelphij/* detect a keyboard */ 312285612Sdelphijstatic int 313285612Sdelphijatkbd_probe(int unit, void *arg, int flags) 314285612Sdelphij{ 315330141Sdelphij KBDC kbdc; 316285612Sdelphij int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 317285612Sdelphij 318285612Sdelphij /* XXX */ 319285612Sdelphij if (unit == ATKBD_DEFAULT) { 320285612Sdelphij if (KBD_IS_PROBED(&default_kbd)) 321285612Sdelphij return 0; 322285612Sdelphij } 323285612Sdelphij 324285612Sdelphij kbdc = atkbdc_open(data[0]); 325285612Sdelphij if (kbdc == NULL) 326285612Sdelphij return ENXIO; 327285612Sdelphij if (probe_keyboard(kbdc, flags)) { 328285612Sdelphij if (flags & KB_CONF_FAIL_IF_NO_KBD) 329285612Sdelphij return ENXIO; 330285612Sdelphij } 331285612Sdelphij return 0; 332285612Sdelphij} 333285612Sdelphij 334285612Sdelphij/* reset and initialize the device */ 335285612Sdelphijstatic int 336285612Sdelphijatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 337285612Sdelphij{ 338285612Sdelphij keyboard_t *kbd; 339285612Sdelphij atkbd_state_t *state; 340285612Sdelphij keymap_t *keymap; 341285612Sdelphij accentmap_t *accmap; 342285612Sdelphij fkeytab_t *fkeymap; 343285612Sdelphij int fkeymap_size; 344285612Sdelphij int delay[2]; 345285612Sdelphij int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ 346285612Sdelphij 347285612Sdelphij /* XXX */ 348285612Sdelphij if (unit == ATKBD_DEFAULT) { 349285612Sdelphij *kbdp = kbd = &default_kbd; 350285612Sdelphij if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) 351285612Sdelphij return 0; 352285612Sdelphij state = &default_kbd_state; 353285612Sdelphij keymap = &default_keymap; 354182007Sroberto accmap = &default_accentmap; 355182007Sroberto fkeymap = default_fkeytab; 356182007Sroberto fkeymap_size = 357182007Sroberto sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 358285612Sdelphij } else if (*kbdp == NULL) { 35954359Sroberto *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO); 360285612Sdelphij state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO); 361285612Sdelphij keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); 362285612Sdelphij accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); 363285612Sdelphij fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); 364285612Sdelphij fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 365316069Sdelphij if ((kbd == NULL) || (state == NULL) || (keymap == NULL) 366316069Sdelphij || (accmap == NULL) || (fkeymap == NULL)) { 367338531Sdelphij if (state != NULL) 368316069Sdelphij free(state, M_DEVBUF); 369330141Sdelphij if (keymap != NULL) 370285612Sdelphij free(keymap, M_DEVBUF); 371285612Sdelphij if (accmap != NULL) 372285612Sdelphij free(accmap, M_DEVBUF); 373285612Sdelphij if (fkeymap != NULL) 374285612Sdelphij free(fkeymap, M_DEVBUF); 375285612Sdelphij if (kbd != NULL) 376316069Sdelphij free(kbd, M_DEVBUF); 377316069Sdelphij return ENOMEM; 378316069Sdelphij } 379316069Sdelphij } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 380316069Sdelphij return 0; 381316069Sdelphij } else { 382316069Sdelphij kbd = *kbdp; 383316069Sdelphij state = (atkbd_state_t *)kbd->kb_data; 384316069Sdelphij bzero(state, sizeof(*state)); 385338531Sdelphij keymap = kbd->kb_keymap; 386316069Sdelphij accmap = kbd->kb_accentmap; 387316069Sdelphij fkeymap = kbd->kb_fkeytab; 388316069Sdelphij fkeymap_size = kbd->kb_fkeytab_size; 389316069Sdelphij } 390316069Sdelphij 391285612Sdelphij if (!KBD_IS_PROBED(kbd)) { 392338531Sdelphij state->kbdc = atkbdc_open(data[0]); 393285612Sdelphij if (state->kbdc == NULL) 394285612Sdelphij return ENXIO; 39554359Sroberto kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 396285612Sdelphij 0, 0); 397285612Sdelphij bcopy(&key_map, keymap, sizeof(key_map)); 398285612Sdelphij bcopy(&accent_map, accmap, sizeof(accent_map)); 399285612Sdelphij bcopy(fkey_tab, fkeymap, 400285612Sdelphij imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 40154359Sroberto kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 40254359Sroberto kbd->kb_data = (void *)state; 403285612Sdelphij 404285612Sdelphij if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ 405285612Sdelphij if (flags & KB_CONF_FAIL_IF_NO_KBD) 40654359Sroberto return ENXIO; 407285612Sdelphij } else { 408285612Sdelphij KBD_FOUND_DEVICE(kbd); 409285612Sdelphij } 410285612Sdelphij atkbd_clear_state(kbd); 411285612Sdelphij state->ks_mode = K_XLATE; 412285612Sdelphij /* 413285612Sdelphij * FIXME: set the initial value for lock keys in ks_state 414285612Sdelphij * according to the BIOS data? 415285612Sdelphij */ 416285612Sdelphij KBD_PROBE_DONE(kbd); 41754359Sroberto } 418285612Sdelphij if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 41954359Sroberto kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 420285612Sdelphij if (KBD_HAS_DEVICE(kbd) 421285612Sdelphij && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 422285612Sdelphij && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { 423285612Sdelphij kbd_unregister(kbd); 42454359Sroberto return ENXIO; 42554359Sroberto } 426285612Sdelphij atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 427285612Sdelphij get_typematic(kbd); 428285612Sdelphij delay[0] = kbd->kb_delay1; 429285612Sdelphij delay[1] = kbd->kb_delay2; 430285612Sdelphij atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 431285612Sdelphij KBD_INIT_DONE(kbd); 432285612Sdelphij } 433285612Sdelphij if (!KBD_IS_CONFIGURED(kbd)) { 434285612Sdelphij if (kbd_register(kbd) < 0) 435285612Sdelphij return ENXIO; 436285612Sdelphij KBD_CONFIG_DONE(kbd); 437285612Sdelphij } 438285612Sdelphij 439285612Sdelphij return 0; 440285612Sdelphij} 441285612Sdelphij 442285612Sdelphij/* finish using this keyboard */ 443285612Sdelphijstatic int 44454359Srobertoatkbd_term(keyboard_t *kbd) 44554359Sroberto{ 44654359Sroberto kbd_unregister(kbd); 447285612Sdelphij return 0; 448285612Sdelphij} 449285612Sdelphij 450285612Sdelphij/* keyboard interrupt routine */ 45154359Srobertostatic int 45254359Srobertoatkbd_intr(keyboard_t *kbd, void *arg) 453285612Sdelphij{ 454285612Sdelphij atkbd_state_t *state; 455285612Sdelphij int delay[2]; 45654359Sroberto int c; 457285612Sdelphij 458285612Sdelphij if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 45954359Sroberto /* let the callback function to process the input */ 460285612Sdelphij (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 461285612Sdelphij kbd->kb_callback.kc_arg); 462285612Sdelphij } else { 463285612Sdelphij /* read and discard the input; no one is waiting for input */ 464285612Sdelphij do { 465285612Sdelphij c = atkbd_read_char(kbd, FALSE); 466285612Sdelphij } while (c != NOKEY); 467285612Sdelphij 468285612Sdelphij if (!KBD_HAS_DEVICE(kbd)) { 469285612Sdelphij /* 470285612Sdelphij * The keyboard was not detected before; 471285612Sdelphij * it must have been reconnected! 472285612Sdelphij */ 473285612Sdelphij state = (atkbd_state_t *)kbd->kb_data; 474285612Sdelphij init_keyboard(state->kbdc, &kbd->kb_type, 475285612Sdelphij kbd->kb_config); 476285612Sdelphij atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 477285612Sdelphij get_typematic(kbd); 478285612Sdelphij delay[0] = kbd->kb_delay1; 479285612Sdelphij delay[1] = kbd->kb_delay2; 480285612Sdelphij atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 481285612Sdelphij KBD_FOUND_DEVICE(kbd); 482285612Sdelphij } 48354359Sroberto } 484285612Sdelphij return 0; 485285612Sdelphij} 486285612Sdelphij 487285612Sdelphij/* test the interface to the device */ 488285612Sdelphijstatic int 48954359Srobertoatkbd_test_if(keyboard_t *kbd) 490285612Sdelphij{ 49154359Sroberto int error; 49254359Sroberto int s; 493285612Sdelphij 494285612Sdelphij error = 0; 495285612Sdelphij empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10); 496285612Sdelphij s = spltty(); 497285612Sdelphij if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc)) 498285612Sdelphij error = EIO; 49954359Sroberto else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0) 50054359Sroberto error = EIO; 501285612Sdelphij splx(s); 502285612Sdelphij 50354359Sroberto return error; 504285612Sdelphij} 505285612Sdelphij 506285612Sdelphij/* 507285612Sdelphij * Enable the access to the device; until this function is called, 508285612Sdelphij * the client cannot read from the keyboard. 509285612Sdelphij */ 510285612Sdelphijstatic int 511285612Sdelphijatkbd_enable(keyboard_t *kbd) 512285612Sdelphij{ 513285612Sdelphij int s; 514285612Sdelphij 515285612Sdelphij s = spltty(); 516285612Sdelphij KBD_ACTIVATE(kbd); 517285612Sdelphij splx(s); 518285612Sdelphij return 0; 519285612Sdelphij} 520285612Sdelphij 521285612Sdelphij/* disallow the access to the device */ 522285612Sdelphijstatic int 523285612Sdelphijatkbd_disable(keyboard_t *kbd) 524285612Sdelphij{ 525285612Sdelphij int s; 526285612Sdelphij 527285612Sdelphij s = spltty(); 528285612Sdelphij KBD_DEACTIVATE(kbd); 529285612Sdelphij splx(s); 530285612Sdelphij return 0; 531285612Sdelphij} 532285612Sdelphij 533285612Sdelphij/* read one byte from the keyboard if it's allowed */ 534330141Sdelphijstatic int 535285612Sdelphijatkbd_read(keyboard_t *kbd, int wait) 536285612Sdelphij{ 537285612Sdelphij int c; 538285612Sdelphij 539285612Sdelphij if (wait) 540285612Sdelphij c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc); 541285612Sdelphij else 542285612Sdelphij c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc); 543285612Sdelphij if (c != -1) 544285612Sdelphij ++kbd->kb_count; 545285612Sdelphij return (KBD_IS_ACTIVE(kbd) ? c : -1); 546285612Sdelphij} 547285612Sdelphij 548285612Sdelphij/* check if data is waiting */ 549285612Sdelphijstatic int 550285612Sdelphijatkbd_check(keyboard_t *kbd) 551285612Sdelphij{ 552285612Sdelphij if (!KBD_IS_ACTIVE(kbd)) 553285612Sdelphij return FALSE; 554285612Sdelphij return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc); 555285612Sdelphij} 556285612Sdelphij 557285612Sdelphij/* read char from the keyboard */ 55854359Srobertostatic u_int 55954359Srobertoatkbd_read_char(keyboard_t *kbd, int wait) 560330141Sdelphij{ 561330141Sdelphij atkbd_state_t *state; 562330141Sdelphij u_int action; 563330141Sdelphij int scancode; 564285612Sdelphij int keycode; 565285612Sdelphij 566285612Sdelphij state = (atkbd_state_t *)kbd->kb_data; 567285612Sdelphijnext_code: 568285612Sdelphij /* do we have a composed char to return? */ 569285612Sdelphij if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 570285612Sdelphij action = state->ks_composed_char; 571285612Sdelphij state->ks_composed_char = 0; 572285612Sdelphij if (action > UCHAR_MAX) 573285612Sdelphij return ERRKEY; 574285612Sdelphij return action; 575285612Sdelphij } 576285612Sdelphij 577285612Sdelphij /* see if there is something in the keyboard port */ 578285612Sdelphij if (wait) { 579285612Sdelphij do { 580285612Sdelphij scancode = read_kbd_data(state->kbdc); 581285612Sdelphij } while (scancode == -1); 582285612Sdelphij } else { 583285612Sdelphij scancode = read_kbd_data_no_wait(state->kbdc); 584285612Sdelphij if (scancode == -1) 585285612Sdelphij return NOKEY; 586285612Sdelphij } 587285612Sdelphij ++kbd->kb_count; 588285612Sdelphij 589285612Sdelphij#if KBDIO_DEBUG >= 10 590285612Sdelphij printf("atkbd_read_char(): scancode:0x%x\n", scancode); 591285612Sdelphij#endif 592285612Sdelphij 593285612Sdelphij /* return the byte as is for the K_RAW mode */ 594285612Sdelphij if (state->ks_mode == K_RAW) 595285612Sdelphij return scancode; 596285612Sdelphij 597285612Sdelphij /* translate the scan code into a keycode */ 598285612Sdelphij keycode = scancode & 0x7F; 59954359Sroberto switch (state->ks_prefix) { 60054359Sroberto case 0x00: /* normal scancode */ 601285612Sdelphij switch(scancode) { 602285612Sdelphij case 0xB8: /* left alt (compose key) released */ 603285612Sdelphij if (state->ks_flags & COMPOSE) { 604285612Sdelphij state->ks_flags &= ~COMPOSE; 605285612Sdelphij if (state->ks_composed_char > UCHAR_MAX) 606285612Sdelphij state->ks_composed_char = 0; 607285612Sdelphij } 60854359Sroberto break; 609285612Sdelphij case 0x38: /* left alt (compose key) pressed */ 610285612Sdelphij if (!(state->ks_flags & COMPOSE)) { 61154359Sroberto state->ks_flags |= COMPOSE; 612285612Sdelphij state->ks_composed_char = 0; 613285612Sdelphij } 614285612Sdelphij break; 615285612Sdelphij case 0xE0: 616285612Sdelphij case 0xE1: 617285612Sdelphij state->ks_prefix = scancode; 618285612Sdelphij goto next_code; 61954359Sroberto } 620285612Sdelphij break; 621285612Sdelphij case 0xE0: /* 0xE0 prefix */ 622285612Sdelphij state->ks_prefix = 0; 623285612Sdelphij switch (keycode) { 624285612Sdelphij case 0x1C: /* right enter key */ 625285612Sdelphij keycode = 0x59; 626285612Sdelphij break; 627285612Sdelphij case 0x1D: /* right ctrl key */ 628285612Sdelphij keycode = 0x5A; 629285612Sdelphij break; 630285612Sdelphij case 0x35: /* keypad divide key */ 631285612Sdelphij keycode = 0x5B; 632285612Sdelphij break; 633285612Sdelphij case 0x37: /* print scrn key */ 634285612Sdelphij keycode = 0x5C; 635285612Sdelphij break; 636285612Sdelphij case 0x38: /* right alt key (alt gr) */ 637285612Sdelphij keycode = 0x5D; 638285612Sdelphij break; 639285612Sdelphij case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 640285612Sdelphij keycode = 0x68; 64154359Sroberto break; 642285612Sdelphij case 0x47: /* grey home key */ 643285612Sdelphij keycode = 0x5E; 644285612Sdelphij break; 645285612Sdelphij case 0x48: /* grey up arrow key */ 64654359Sroberto keycode = 0x5F; 647285612Sdelphij break; 648285612Sdelphij case 0x49: /* grey page up key */ 649285612Sdelphij keycode = 0x60; 650285612Sdelphij break; 651285612Sdelphij case 0x4B: /* grey left arrow key */ 652285612Sdelphij keycode = 0x61; 653285612Sdelphij break; 654285612Sdelphij case 0x4D: /* grey right arrow key */ 655285612Sdelphij keycode = 0x62; 65654359Sroberto break; 657285612Sdelphij case 0x4F: /* grey end key */ 658285612Sdelphij keycode = 0x63; 659285612Sdelphij break; 660285612Sdelphij case 0x50: /* grey down arrow key */ 661285612Sdelphij keycode = 0x64; 662285612Sdelphij break; 663285612Sdelphij case 0x51: /* grey page down key */ 664285612Sdelphij keycode = 0x65; 665285612Sdelphij break; 66654359Sroberto case 0x52: /* grey insert key */ 667285612Sdelphij keycode = 0x66; 668285612Sdelphij break; 66954359Sroberto case 0x53: /* grey delete key */ 670285612Sdelphij keycode = 0x67; 671285612Sdelphij break; 672285612Sdelphij /* the following 3 are only used on the MS "Natural" keyboard */ 673285612Sdelphij case 0x5b: /* left Window key */ 674285612Sdelphij keycode = 0x69; 675285612Sdelphij break; 676285612Sdelphij case 0x5c: /* right Window key */ 677285612Sdelphij keycode = 0x6a; 678285612Sdelphij break; 679285612Sdelphij case 0x5d: /* menu key */ 680285612Sdelphij keycode = 0x6b; 681285612Sdelphij break; 682285612Sdelphij default: /* ignore everything else */ 683285612Sdelphij goto next_code; 684285612Sdelphij } 685285612Sdelphij break; 686285612Sdelphij case 0xE1: /* 0xE1 prefix */ 687285612Sdelphij /* 688285612Sdelphij * The pause/break key on the 101 keyboard produces: 689285612Sdelphij * E1-1D-45 E1-9D-C5 690285612Sdelphij * Ctrl-pause/break produces: 691285612Sdelphij * E0-46 E0-C6 (See above.) 69254359Sroberto */ 693285612Sdelphij state->ks_prefix = 0; 69454359Sroberto if (keycode == 0x1D) 69554359Sroberto state->ks_prefix = 0x1D; 696285612Sdelphij goto next_code; 697285612Sdelphij /* NOT REACHED */ 698260639Sdelphij case 0x1D: /* pause / break */ 699285612Sdelphij state->ks_prefix = 0; 700285612Sdelphij if (keycode != 0x45) 701285612Sdelphij goto next_code; 702285612Sdelphij keycode = 0x68; 703285612Sdelphij break; 704285612Sdelphij } 705285612Sdelphij 706285612Sdelphij if (kbd->kb_type == KB_84) { 707285612Sdelphij switch (keycode) { 708285612Sdelphij case 0x37: /* *(numpad)/print screen */ 709285612Sdelphij if (state->ks_flags & SHIFTS) 710285612Sdelphij keycode = 0x5c; /* print screen */ 711285612Sdelphij break; 712285612Sdelphij case 0x45: /* num lock/pause */ 713285612Sdelphij if (state->ks_flags & CTLS) 714285612Sdelphij keycode = 0x68; /* pause */ 715285612Sdelphij break; 716285612Sdelphij case 0x46: /* scroll lock/break */ 717285612Sdelphij if (state->ks_flags & CTLS) 718285612Sdelphij keycode = 0x6c; /* break */ 719285612Sdelphij break; 720285612Sdelphij } 721285612Sdelphij } else if (kbd->kb_type == KB_101) { 722285612Sdelphij switch (keycode) { 723285612Sdelphij case 0x5c: /* print screen */ 724285612Sdelphij if (state->ks_flags & ALTS) 725285612Sdelphij keycode = 0x54; /* sysrq */ 726285612Sdelphij break; 727285612Sdelphij case 0x68: /* pause/break */ 728285612Sdelphij if (state->ks_flags & CTLS) 729285612Sdelphij keycode = 0x6c; /* break */ 730285612Sdelphij break; 731330141Sdelphij } 732330141Sdelphij } 733330141Sdelphij 734330141Sdelphij /* return the key code in the K_CODE mode */ 735330141Sdelphij if (state->ks_mode == K_CODE) 736330141Sdelphij return (keycode | (scancode & 0x80)); 737330141Sdelphij 738330141Sdelphij /* compose a character code */ 739330141Sdelphij if (state->ks_flags & COMPOSE) { 740330141Sdelphij switch (keycode | (scancode & 0x80)) { 741330141Sdelphij /* key pressed, process it */ 742330141Sdelphij case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 743330141Sdelphij state->ks_composed_char *= 10; 744330141Sdelphij state->ks_composed_char += keycode - 0x40; 745338531Sdelphij if (state->ks_composed_char > UCHAR_MAX) 746285612Sdelphij return ERRKEY; 747285612Sdelphij goto next_code; 748285612Sdelphij case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 749285612Sdelphij state->ks_composed_char *= 10; 750285612Sdelphij state->ks_composed_char += keycode - 0x47; 751285612Sdelphij if (state->ks_composed_char > UCHAR_MAX) 752285612Sdelphij return ERRKEY; 753285612Sdelphij goto next_code; 754285612Sdelphij case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 755285612Sdelphij state->ks_composed_char *= 10; 756285612Sdelphij state->ks_composed_char += keycode - 0x4E; 757285612Sdelphij if (state->ks_composed_char > UCHAR_MAX) 758285612Sdelphij return ERRKEY; 759285612Sdelphij goto next_code; 760285612Sdelphij case 0x52: /* keypad 0 */ 761285612Sdelphij state->ks_composed_char *= 10; 762285612Sdelphij if (state->ks_composed_char > UCHAR_MAX) 763285612Sdelphij return ERRKEY; 764285612Sdelphij goto next_code; 765285612Sdelphij 766285612Sdelphij /* key released, no interest here */ 767285612Sdelphij case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 768285612Sdelphij case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 769285612Sdelphij case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 770285612Sdelphij case 0xD2: /* keypad 0 */ 771285612Sdelphij goto next_code; 772285612Sdelphij 773285612Sdelphij case 0x38: /* left alt key */ 774285612Sdelphij break; 775285612Sdelphij 776285612Sdelphij default: 777285612Sdelphij if (state->ks_composed_char > 0) { 778285612Sdelphij state->ks_flags &= ~COMPOSE; 779285612Sdelphij state->ks_composed_char = 0; 780285612Sdelphij return ERRKEY; 781285612Sdelphij } 782285612Sdelphij break; 783285612Sdelphij } 784285612Sdelphij } 785285612Sdelphij 786285612Sdelphij /* keycode to key action */ 787285612Sdelphij action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 788285612Sdelphij &state->ks_state, &state->ks_accents); 789285612Sdelphij if (action == NOKEY) 790285612Sdelphij goto next_code; 791285612Sdelphij else 792182007Sroberto return action; 793285612Sdelphij} 794285612Sdelphij 795285612Sdelphij/* check if char is waiting */ 79654359Srobertostatic int 797285612Sdelphijatkbd_check_char(keyboard_t *kbd) 798285612Sdelphij{ 79982498Sroberto atkbd_state_t *state; 800285612Sdelphij 801285612Sdelphij if (!KBD_IS_ACTIVE(kbd)) 802285612Sdelphij return FALSE; 803285612Sdelphij state = (atkbd_state_t *)kbd->kb_data; 80482498Sroberto if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 805285612Sdelphij return TRUE; 80654359Sroberto return kbdc_data_ready(state->kbdc); 807285612Sdelphij} 808285612Sdelphij 809285612Sdelphij/* some useful control functions */ 810285612Sdelphijstatic int 811285612Sdelphijatkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 812285612Sdelphij{ 813285612Sdelphij /* trasnlate LED_XXX bits into the device specific bits */ 814285612Sdelphij static u_char ledmap[8] = { 815285612Sdelphij 0, 4, 2, 6, 1, 5, 3, 7, 816285612Sdelphij }; 81754359Sroberto atkbd_state_t *state = kbd->kb_data; 818285612Sdelphij int error; 819285612Sdelphij int s; 82054359Sroberto int i; 821285612Sdelphij 822285612Sdelphij s = spltty(); 82354359Sroberto switch (cmd) { 824285612Sdelphij 825285612Sdelphij case KDGKBMODE: /* get keyboard mode */ 826132451Sroberto *(int *)arg = state->ks_mode; 827285612Sdelphij break; 828285612Sdelphij case KDSKBMODE: /* set keyboard mode */ 82954359Sroberto switch (*(int *)arg) { 830285612Sdelphij case K_XLATE: 831285612Sdelphij if (state->ks_mode != K_XLATE) { 832285612Sdelphij /* make lock key state and LED state match */ 833285612Sdelphij state->ks_state &= ~LOCK_MASK; 834285612Sdelphij state->ks_state |= KBD_LED_VAL(kbd); 835285612Sdelphij } 836285612Sdelphij /* FALLTHROUGH */ 837285612Sdelphij case K_RAW: 838285612Sdelphij case K_CODE: 839285612Sdelphij if (state->ks_mode != *(int *)arg) { 840285612Sdelphij atkbd_clear_state(kbd); 841285612Sdelphij state->ks_mode = *(int *)arg; 842285612Sdelphij } 843285612Sdelphij break; 844285612Sdelphij default: 845285612Sdelphij splx(s); 846285612Sdelphij return EINVAL; 847285612Sdelphij } 848285612Sdelphij break; 849285612Sdelphij 850285612Sdelphij case KDGETLED: /* get keyboard LED */ 851285612Sdelphij *(int *)arg = KBD_LED_VAL(kbd); 852285612Sdelphij break; 853285612Sdelphij case KDSETLED: /* set keyboard LED */ 854285612Sdelphij /* NOTE: lock key state in ks_state won't be changed */ 855285612Sdelphij if (*(int *)arg & ~LOCK_MASK) { 856285612Sdelphij splx(s); 857285612Sdelphij return EINVAL; 858285612Sdelphij } 859285612Sdelphij i = *(int *)arg; 860285612Sdelphij /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 861285612Sdelphij if (state->ks_mode == K_XLATE && 862285612Sdelphij kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 863285612Sdelphij if (i & ALKED) 86454359Sroberto i |= CLKED; 865285612Sdelphij else 866285612Sdelphij i &= ~CLKED; 867285612Sdelphij } 868285612Sdelphij if (KBD_HAS_DEVICE(kbd)) { 86954359Sroberto error = write_kbd(state->kbdc, KBDC_SET_LEDS, 870285612Sdelphij ledmap[i & LED_MASK]); 871285612Sdelphij if (error) { 872285612Sdelphij splx(s); 873285612Sdelphij return error; 874285612Sdelphij } 875285612Sdelphij } 876285612Sdelphij KBD_LED_VAL(kbd) = *(int *)arg; 877285612Sdelphij break; 878285612Sdelphij 879285612Sdelphij case KDGKBSTATE: /* get lock key state */ 880285612Sdelphij *(int *)arg = state->ks_state & LOCK_MASK; 881285612Sdelphij break; 88254359Sroberto case KDSKBSTATE: /* set lock key state */ 883285612Sdelphij if (*(int *)arg & ~LOCK_MASK) { 884285612Sdelphij splx(s); 885285612Sdelphij return EINVAL; 886285612Sdelphij } 887285612Sdelphij state->ks_state &= ~LOCK_MASK; 888285612Sdelphij state->ks_state |= *(int *)arg; 889285612Sdelphij splx(s); 890285612Sdelphij /* set LEDs and quit */ 891285612Sdelphij return atkbd_ioctl(kbd, KDSETLED, arg); 892285612Sdelphij 893285612Sdelphij case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 894285612Sdelphij splx(s); 895285612Sdelphij if (!KBD_HAS_DEVICE(kbd)) 896285612Sdelphij return 0; 897285612Sdelphij i = typematic(((int *)arg)[0], ((int *)arg)[1]); 898285612Sdelphij error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); 899285612Sdelphij if (error == 0) { 900285612Sdelphij kbd->kb_delay1 = typematic_delay(i); 901285612Sdelphij kbd->kb_delay2 = typematic_rate(i); 902285612Sdelphij } 903285612Sdelphij return error; 904285612Sdelphij 905285612Sdelphij case KDSETRAD: /* set keyboard repeat rate (old interface) */ 906285612Sdelphij splx(s); 907285612Sdelphij if (!KBD_HAS_DEVICE(kbd)) 908285612Sdelphij return 0; 909285612Sdelphij error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); 910285612Sdelphij if (error == 0) { 911285612Sdelphij kbd->kb_delay1 = typematic_delay(*(int *)arg); 912285612Sdelphij kbd->kb_delay2 = typematic_rate(*(int *)arg); 913285612Sdelphij } 914285612Sdelphij return error; 915285612Sdelphij 916285612Sdelphij case PIO_KEYMAP: /* set keyboard translation table */ 917285612Sdelphij case PIO_KEYMAPENT: /* set keyboard translation table entry */ 918285612Sdelphij case PIO_DEADKEYMAP: /* set accent key translation table */ 919285612Sdelphij state->ks_accents = 0; 920285612Sdelphij /* FALLTHROUGH */ 921285612Sdelphij default: 922285612Sdelphij splx(s); 923285612Sdelphij return genkbd_commonioctl(kbd, cmd, arg); 924285612Sdelphij } 925285612Sdelphij 926285612Sdelphij splx(s); 927285612Sdelphij return 0; 928285612Sdelphij} 929285612Sdelphij 930285612Sdelphij/* lock the access to the keyboard */ 931330141Sdelphijstatic int 932285612Sdelphijatkbd_lock(keyboard_t *kbd, int lock) 933285612Sdelphij{ 934285612Sdelphij return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock); 935330141Sdelphij} 936330141Sdelphij 937330141Sdelphij/* clear the internal state of the keyboard */ 938330141Sdelphijstatic void 939285612Sdelphijatkbd_clear_state(keyboard_t *kbd) 940285612Sdelphij{ 941338531Sdelphij atkbd_state_t *state; 942330141Sdelphij 943285612Sdelphij state = (atkbd_state_t *)kbd->kb_data; 944330141Sdelphij state->ks_flags = 0; 945330141Sdelphij state->ks_polling = 0; 946330141Sdelphij state->ks_state &= LOCK_MASK; /* preserve locking key state */ 947330141Sdelphij state->ks_accents = 0; 948330141Sdelphij state->ks_composed_char = 0; 949330141Sdelphij#if 0 950330141Sdelphij state->ks_prefix = 0; /* XXX */ 951330141Sdelphij#endif 952330141Sdelphij} 953330141Sdelphij 954330141Sdelphij/* save the internal state */ 955330141Sdelphijstatic int 956330141Sdelphijatkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 957330141Sdelphij{ 958330141Sdelphij if (len == 0) 959330141Sdelphij return sizeof(atkbd_state_t); 960330141Sdelphij if (len < sizeof(atkbd_state_t)) 961330141Sdelphij return -1; 962330141Sdelphij bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t)); 963330141Sdelphij return 0; 964285612Sdelphij} 965285612Sdelphij 966330141Sdelphij/* set the internal state */ 967285612Sdelphijstatic int 968285612Sdelphijatkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 969330141Sdelphij{ 970330141Sdelphij if (len < sizeof(atkbd_state_t)) 971330141Sdelphij return ENOMEM; 972330141Sdelphij if (((atkbd_state_t *)kbd->kb_data)->kbdc 973330141Sdelphij != ((atkbd_state_t *)buf)->kbdc) 974285612Sdelphij return ENOMEM; 975285612Sdelphij bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t)); 976285612Sdelphij return 0; 977285612Sdelphij} 978285612Sdelphij 979285612Sdelphijstatic int 980285612Sdelphijatkbd_poll(keyboard_t *kbd, int on) 981285612Sdelphij{ 982285612Sdelphij atkbd_state_t *state; 983285612Sdelphij int s; 984285612Sdelphij 985285612Sdelphij state = (atkbd_state_t *)kbd->kb_data; 986285612Sdelphij s = spltty(); 987285612Sdelphij if (on) 988285612Sdelphij ++state->ks_polling; 989285612Sdelphij else 990285612Sdelphij --state->ks_polling; 991285612Sdelphij splx(s); 992285612Sdelphij return 0; 993285612Sdelphij} 994285612Sdelphij 995285612Sdelphij/* local functions */ 996285612Sdelphij 997285612Sdelphijstatic int 998285612Sdelphijget_typematic(keyboard_t *kbd) 999285612Sdelphij{ 1000285612Sdelphij#ifdef __i386__ 1001285612Sdelphij /* 1002285612Sdelphij * Only some systems allow us to retrieve the keyboard repeat 1003285612Sdelphij * rate previously set via the BIOS... 1004285612Sdelphij */ 1005285612Sdelphij struct vm86frame vmf; 1006285612Sdelphij u_int32_t p; 1007285612Sdelphij 1008285612Sdelphij bzero(&vmf, sizeof(vmf)); 1009285612Sdelphij vmf.vmf_ax = 0xc000; 1010285612Sdelphij vm86_intcall(0x15, &vmf); 1011285612Sdelphij if ((vmf.vmf_eflags & PSL_C) || vmf.vmf_ah) 1012285612Sdelphij return ENODEV; 1013285612Sdelphij p = BIOS_PADDRTOVADDR(((u_int32_t)vmf.vmf_es << 4) + vmf.vmf_bx); 1014285612Sdelphij if ((readb(p + 6) & 0x40) == 0) /* int 16, function 0x09 supported? */ 1015285612Sdelphij return ENODEV; 1016285612Sdelphij vmf.vmf_ax = 0x0900; 1017285612Sdelphij vm86_intcall(0x16, &vmf); 1018285612Sdelphij if ((vmf.vmf_al & 0x08) == 0) /* int 16, function 0x0306 supported? */ 1019285612Sdelphij return ENODEV; 1020285612Sdelphij vmf.vmf_ax = 0x0306; 1021285612Sdelphij vm86_intcall(0x16, &vmf); 1022285612Sdelphij kbd->kb_delay1 = typematic_delay(vmf.vmf_bh << 5); 1023285612Sdelphij kbd->kb_delay2 = typematic_rate(vmf.vmf_bl); 1024285612Sdelphij return 0; 1025285612Sdelphij#else 1026285612Sdelphij return ENODEV; 1027285612Sdelphij#endif /* __i386__ */ 1028132451Sroberto} 1029285612Sdelphij 1030285612Sdelphijstatic int 1031182007Srobertosetup_kbd_port(KBDC kbdc, int port, int intr) 1032182007Sroberto{ 1033285612Sdelphij if (!set_controller_command_byte(kbdc, 1034285612Sdelphij KBD_KBD_CONTROL_BITS, 1035285612Sdelphij ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) 1036285612Sdelphij | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT))) 1037285612Sdelphij return 1; 1038285612Sdelphij return 0; 1039285612Sdelphij} 1040285612Sdelphij 104154359Srobertostatic int 1042285612Sdelphijget_kbd_echo(KBDC kbdc) 1043285612Sdelphij{ 1044285612Sdelphij /* enable the keyboard port, but disable the keyboard intr. */ 1045285612Sdelphij if (setup_kbd_port(kbdc, TRUE, FALSE)) 1046285612Sdelphij /* CONTROLLER ERROR: there is very little we can do... */ 1047285612Sdelphij return ENXIO; 1048285612Sdelphij 1049285612Sdelphij /* see if something is present */ 105054359Sroberto write_kbd_command(kbdc, KBDC_ECHO); 1051285612Sdelphij if (read_kbd_data(kbdc) != KBD_ECHO) { 1052285612Sdelphij empty_both_buffers(kbdc, 10); 1053285612Sdelphij test_controller(kbdc); 105454359Sroberto test_kbd_port(kbdc); 105554359Sroberto return ENXIO; 1056182007Sroberto } 1057285612Sdelphij 1058285612Sdelphij /* enable the keyboard port and intr. */ 1059285612Sdelphij if (setup_kbd_port(kbdc, TRUE, TRUE)) { 1060285612Sdelphij /* 1061285612Sdelphij * CONTROLLER ERROR 1062285612Sdelphij * This is serious; the keyboard intr is left disabled! 1063285612Sdelphij */ 1064285612Sdelphij return ENXIO; 1065285612Sdelphij } 106654359Sroberto 1067285612Sdelphij return 0; 1068285612Sdelphij} 1069285612Sdelphij 1070285612Sdelphijstatic int 1071285612Sdelphijprobe_keyboard(KBDC kbdc, int flags) 1072285612Sdelphij{ 1073285612Sdelphij /* 1074285612Sdelphij * Don't try to print anything in this function. The low-level 1075285612Sdelphij * console may not have been initialized yet... 1076182007Sroberto */ 1077285612Sdelphij int err; 1078285612Sdelphij int c; 107954359Sroberto int m; 1080182007Sroberto 1081285612Sdelphij if (!kbdc_lock(kbdc, TRUE)) { 1082285612Sdelphij /* driver error? */ 1083285612Sdelphij return ENXIO; 1084285612Sdelphij } 1085285612Sdelphij 1086285612Sdelphij /* temporarily block data transmission from the keyboard */ 1087285612Sdelphij write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 1088285612Sdelphij 1089182007Sroberto /* flush any noise in the buffer */ 1090285612Sdelphij empty_both_buffers(kbdc, 100); 1091285612Sdelphij 1092285612Sdelphij /* save the current keyboard controller command byte */ 1093285612Sdelphij m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; 1094285612Sdelphij c = get_controller_command_byte(kbdc); 1095285612Sdelphij if (c == -1) { 109654359Sroberto /* CONTROLLER ERROR */ 1097285612Sdelphij kbdc_set_device_mask(kbdc, m); 1098285612Sdelphij kbdc_lock(kbdc, FALSE); 109954359Sroberto return ENXIO; 1100285612Sdelphij } 1101285612Sdelphij 110254359Sroberto /* 1103330141Sdelphij * The keyboard may have been screwed up by the boot block. 1104330141Sdelphij * We may just be able to recover from error by testing the controller 1105330141Sdelphij * and the keyboard port. The controller command byte needs to be 1106330141Sdelphij * saved before this recovery operation, as some controllers seem 1107330141Sdelphij * to set the command byte to particular values. 1108330141Sdelphij */ 1109330141Sdelphij test_controller(kbdc); 1110330141Sdelphij test_kbd_port(kbdc); 111154359Sroberto 1112330141Sdelphij err = get_kbd_echo(kbdc); 1113330141Sdelphij 1114330141Sdelphij /* 1115330141Sdelphij * Even if the keyboard doesn't seem to be present (err != 0), 1116330141Sdelphij * we shall enable the keyboard port and interrupt so that 1117330141Sdelphij * the driver will be operable when the keyboard is attached 1118330141Sdelphij * to the system later. It is NOT recommended to hot-plug 1119330141Sdelphij * the AT keyboard, but many people do so... 1120330141Sdelphij */ 1121330141Sdelphij kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 1122330141Sdelphij setup_kbd_port(kbdc, TRUE, TRUE); 1123330141Sdelphij#if 0 1124330141Sdelphij if (err == 0) { 1125330141Sdelphij kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 1126285612Sdelphij } else { 1127285612Sdelphij /* try to restore the command byte as before */ 1128285612Sdelphij set_controller_command_byte(kbdc, 0xff, c); 112954359Sroberto kbdc_set_device_mask(kbdc, m); 1130330141Sdelphij } 1131330141Sdelphij#endif 1132330141Sdelphij 1133330141Sdelphij kbdc_lock(kbdc, FALSE); 1134330141Sdelphij return err; 1135330141Sdelphij} 1136330141Sdelphij 1137330141Sdelphijstatic int 1138330141Sdelphijinit_keyboard(KBDC kbdc, int *type, int flags) 1139330141Sdelphij{ 1140330141Sdelphij int codeset; 1141330141Sdelphij int id; 1142285612Sdelphij int c; 1143285612Sdelphij 1144285612Sdelphij if (!kbdc_lock(kbdc, TRUE)) { 1145285612Sdelphij /* driver error? */ 1146285612Sdelphij return EIO; 1147285612Sdelphij } 1148285612Sdelphij 114982498Sroberto /* temporarily block data transmission from the keyboard */ 1150285612Sdelphij write_controller_command(kbdc, KBDC_DISABLE_KBD_PORT); 1151285612Sdelphij 1152285612Sdelphij /* save the current controller command byte */ 1153285612Sdelphij empty_both_buffers(kbdc, 200); 115482498Sroberto c = get_controller_command_byte(kbdc); 1155285612Sdelphij if (c == -1) { 1156285612Sdelphij /* CONTROLLER ERROR */ 115754359Sroberto kbdc_lock(kbdc, FALSE); 1158285612Sdelphij printf("atkbd: unable to get the current command byte value.\n"); 1159285612Sdelphij return EIO; 1160285612Sdelphij } 1161285612Sdelphij if (bootverbose) 1162285612Sdelphij printf("atkbd: the current kbd controller command byte %04x\n", 1163285612Sdelphij c); 1164285612Sdelphij#if 0 1165285612Sdelphij /* override the keyboard lock switch */ 1166285612Sdelphij c |= KBD_OVERRIDE_KBD_LOCK; 1167285612Sdelphij#endif 1168285612Sdelphij 1169285612Sdelphij /* enable the keyboard port, but disable the keyboard intr. */ 1170285612Sdelphij if (setup_kbd_port(kbdc, TRUE, FALSE)) { 1171285612Sdelphij /* CONTROLLER ERROR: there is very little we can do... */ 1172285612Sdelphij printf("atkbd: unable to set the command byte.\n"); 1173285612Sdelphij kbdc_lock(kbdc, FALSE); 1174285612Sdelphij return EIO; 1175285612Sdelphij } 1176285612Sdelphij 1177285612Sdelphij /* 1178285612Sdelphij * Check if we have an XT keyboard before we attempt to reset it. 1179285612Sdelphij * The procedure assumes that the keyboard and the controller have 1180285612Sdelphij * been set up properly by BIOS and have not been messed up 1181285612Sdelphij * during the boot process. 1182285612Sdelphij */ 1183285612Sdelphij codeset = -1; 1184285612Sdelphij if (flags & KB_CONF_ALT_SCANCODESET) 1185285612Sdelphij /* the user says there is a XT keyboard */ 1186285612Sdelphij codeset = 1; 1187285612Sdelphij#ifdef KBD_DETECT_XT_KEYBOARD 1188285612Sdelphij else if ((c & KBD_TRANSLATION) == 0) { 1189285612Sdelphij /* SET_SCANCODE_SET is not always supported; ignore error */ 1190285612Sdelphij if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0) 1191285612Sdelphij == KBD_ACK) 1192285612Sdelphij codeset = read_kbd_data(kbdc); 1193285612Sdelphij } 1194285612Sdelphij if (bootverbose) 1195285612Sdelphij printf("atkbd: scancode set %d\n", codeset); 1196285612Sdelphij#endif /* KBD_DETECT_XT_KEYBOARD */ 1197285612Sdelphij 1198285612Sdelphij *type = KB_OTHER; 1199285612Sdelphij id = get_kbd_id(kbdc); 1200285612Sdelphij switch(id) { 1201285612Sdelphij case 0x41ab: /* 101/102/... Enhanced */ 1202285612Sdelphij case 0x83ab: /* ditto */ 1203285612Sdelphij case 0x54ab: /* SpaceSaver */ 1204285612Sdelphij case 0x84ab: /* ditto */ 1205285612Sdelphij#if 0 1206285612Sdelphij case 0x90ab: /* 'G' */ 1207285612Sdelphij case 0x91ab: /* 'P' */ 1208285612Sdelphij case 0x92ab: /* 'A' */ 1209285612Sdelphij#endif 1210285612Sdelphij *type = KB_101; 1211285612Sdelphij break; 1212285612Sdelphij case -1: /* AT 84 keyboard doesn't return ID */ 1213285612Sdelphij *type = KB_84; 1214285612Sdelphij break; 1215285612Sdelphij default: 1216285612Sdelphij break; 1217285612Sdelphij } 1218285612Sdelphij if (bootverbose) 1219285612Sdelphij printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type); 1220285612Sdelphij 1221285612Sdelphij /* reset keyboard hardware */ 1222285612Sdelphij if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { 1223285612Sdelphij /* 1224285612Sdelphij * KEYBOARD ERROR 1225285612Sdelphij * Keyboard reset may fail either because the keyboard 1226285612Sdelphij * doen't exist, or because the keyboard doesn't pass 1227285612Sdelphij * the self-test, or the keyboard controller on the 1228285612Sdelphij * motherboard and the keyboard somehow fail to shake hands. 1229285612Sdelphij * It is just possible, particularly in the last case, 1230285612Sdelphij * that the keyboard controller may be left in a hung state. 1231285612Sdelphij * test_controller() and test_kbd_port() appear to bring 1232285612Sdelphij * the keyboard controller back (I don't know why and how, 1233285612Sdelphij * though.) 1234285612Sdelphij */ 1235285612Sdelphij empty_both_buffers(kbdc, 10); 1236285612Sdelphij test_controller(kbdc); 1237285612Sdelphij test_kbd_port(kbdc); 1238285612Sdelphij /* 1239285612Sdelphij * We could disable the keyboard port and interrupt... but, 1240285612Sdelphij * the keyboard may still exist (see above). 1241285612Sdelphij */ 1242285612Sdelphij set_controller_command_byte(kbdc, 0xff, c); 1243285612Sdelphij kbdc_lock(kbdc, FALSE); 1244285612Sdelphij if (bootverbose) 1245285612Sdelphij printf("atkbd: failed to reset the keyboard.\n"); 1246285612Sdelphij return EIO; 1247285612Sdelphij } 1248285612Sdelphij 1249285612Sdelphij /* 1250285612Sdelphij * Allow us to set the XT_KEYBD flag so that keyboards 1251285612Sdelphij * such as those on the IBM ThinkPad laptop computers can be used 1252285612Sdelphij * with the standard console driver. 1253285612Sdelphij */ 1254285612Sdelphij if (codeset == 1) { 1255285612Sdelphij if (send_kbd_command_and_data(kbdc, 1256285612Sdelphij KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 1257285612Sdelphij /* XT kbd doesn't need scan code translation */ 1258285612Sdelphij c &= ~KBD_TRANSLATION; 1259285612Sdelphij } else { 1260285612Sdelphij /* 1261285612Sdelphij * KEYBOARD ERROR 1262285612Sdelphij * The XT kbd isn't usable unless the proper scan 1263285612Sdelphij * code set is selected. 1264285612Sdelphij */ 1265285612Sdelphij set_controller_command_byte(kbdc, 0xff, c); 1266285612Sdelphij kbdc_lock(kbdc, FALSE); 1267289997Sglebius printf("atkbd: unable to set the XT keyboard mode.\n"); 1268289997Sglebius return EIO; 1269285612Sdelphij } 1270285612Sdelphij } 1271285612Sdelphij 1272285612Sdelphij#ifdef __alpha__ 1273285612Sdelphij if (send_kbd_command_and_data( 1274285612Sdelphij kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) { 1275285612Sdelphij printf("atkbd: can't set translation.\n"); 1276285612Sdelphij 1277285612Sdelphij } 1278285612Sdelphij c |= KBD_TRANSLATION; 1279285612Sdelphij#endif 1280285612Sdelphij 1281285612Sdelphij /* enable the keyboard port and intr. */ 1282285612Sdelphij if (!set_controller_command_byte(kbdc, 1283285612Sdelphij KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 1284289997Sglebius (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 1285285612Sdelphij | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 1286285612Sdelphij /* 1287285612Sdelphij * CONTROLLER ERROR 1288285612Sdelphij * This is serious; we are left with the disabled 1289285612Sdelphij * keyboard intr. 1290285612Sdelphij */ 1291285612Sdelphij set_controller_command_byte(kbdc, 0xff, c); 1292285612Sdelphij kbdc_lock(kbdc, FALSE); 1293285612Sdelphij printf("atkbd: unable to enable the keyboard port and intr.\n"); 1294285612Sdelphij return EIO; 1295285612Sdelphij } 1296285612Sdelphij 1297285612Sdelphij kbdc_lock(kbdc, FALSE); 1298285612Sdelphij return 0; 1299285612Sdelphij} 1300285612Sdelphij 1301285612Sdelphijstatic int 1302285612Sdelphijwrite_kbd(KBDC kbdc, int command, int data) 1303285612Sdelphij{ 1304285612Sdelphij int s; 1305285612Sdelphij 1306285612Sdelphij /* prevent the timeout routine from polling the keyboard */ 1307285612Sdelphij if (!kbdc_lock(kbdc, TRUE)) 1308285612Sdelphij return EBUSY; 1309285612Sdelphij 1310285612Sdelphij /* disable the keyboard and mouse interrupt */ 1311285612Sdelphij s = spltty(); 1312285612Sdelphij#if 0 1313285612Sdelphij c = get_controller_command_byte(kbdc); 1314285612Sdelphij if ((c == -1) 1315285612Sdelphij || !set_controller_command_byte(kbdc, 1316285612Sdelphij kbdc_get_device_mask(kbdc), 1317285612Sdelphij KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 1318285612Sdelphij | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1319285612Sdelphij /* CONTROLLER ERROR */ 1320285612Sdelphij kbdc_lock(kbdc, FALSE); 1321285612Sdelphij splx(s); 1322285612Sdelphij return EIO; 1323285612Sdelphij } 1324285612Sdelphij /* 132554359Sroberto * Now that the keyboard controller is told not to generate 1326285612Sdelphij * the keyboard and mouse interrupts, call `splx()' to allow 132754359Sroberto * the other tty interrupts. The clock interrupt may also occur, 1328285612Sdelphij * but the timeout routine (`scrn_timer()') will be blocked 1329285612Sdelphij * by the lock flag set via `kbdc_lock()' 1330285612Sdelphij */ 133154359Sroberto splx(s); 1332285612Sdelphij#endif 1333285612Sdelphij 1334285612Sdelphij if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) 1335285612Sdelphij send_kbd_command(kbdc, KBDC_ENABLE_KBD); 133654359Sroberto 1337285612Sdelphij#if 0 1338285612Sdelphij /* restore the interrupts */ 1339285612Sdelphij if (!set_controller_command_byte(kbdc, 1340285612Sdelphij kbdc_get_device_mask(kbdc), 1341285612Sdelphij c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 1342285612Sdelphij /* CONTROLLER ERROR */ 1343285612Sdelphij } 1344285612Sdelphij#else 1345285612Sdelphij splx(s); 1346285612Sdelphij#endif 1347285612Sdelphij kbdc_lock(kbdc, FALSE); 134854359Sroberto 134954359Sroberto return 0; 135054359Sroberto} 1351285612Sdelphij 1352285612Sdelphijstatic int 1353285612Sdelphijget_kbd_id(KBDC kbdc) 1354285612Sdelphij{ 1355285612Sdelphij int id1, id2; 1356285612Sdelphij 1357285612Sdelphij empty_both_buffers(kbdc, 10); 1358182007Sroberto id1 = id2 = -1; 1359285612Sdelphij if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK) 1360285612Sdelphij return -1; 1361182007Sroberto 136254359Sroberto DELAY(10000); /* 10 msec delay */ 1363132451Sroberto id1 = read_kbd_data(kbdc); 1364285612Sdelphij if (id1 != -1) 1365316069Sdelphij id2 = read_kbd_data(kbdc); 1366316069Sdelphij 1367316069Sdelphij if ((id1 == -1) || (id2 == -1)) { 1368316069Sdelphij empty_both_buffers(kbdc, 10); 1369285612Sdelphij test_controller(kbdc); 1370285612Sdelphij test_kbd_port(kbdc); 1371285612Sdelphij return -1; 1372285612Sdelphij } 1373285612Sdelphij return ((id2 << 8) | id1); 1374285612Sdelphij} 1375132451Sroberto 1376285612Sdelphijstatic int delays[] = { 250, 500, 750, 1000 }; 1377316069Sdelphijstatic int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 1378316069Sdelphij 68, 76, 84, 92, 100, 110, 118, 126, 1379316069Sdelphij 136, 152, 168, 184, 200, 220, 236, 252, 1380316069Sdelphij 272, 304, 336, 368, 400, 440, 472, 504 }; 1381316069Sdelphij 1382316069Sdelphijstatic int 138354359Srobertotypematic_delay(int i) 138454359Sroberto{ 1385285612Sdelphij return delays[(i >> 5) & 3]; 1386285612Sdelphij} 1387285612Sdelphij 1388285612Sdelphijstatic int 1389285612Sdelphijtypematic_rate(int i) 1390285612Sdelphij{ 1391285612Sdelphij return rates[i & 0x1f]; 139254359Sroberto} 1393132451Sroberto 139454359Srobertostatic int 1395285612Sdelphijtypematic(int delay, int rate) 1396285612Sdelphij{ 1397285612Sdelphij int value; 1398285612Sdelphij int i; 1399285612Sdelphij 1400285612Sdelphij for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { 1401285612Sdelphij if (delay >= delays[i]) 140254359Sroberto break; 140354359Sroberto } 140454359Sroberto value = i << 5; 1405285612Sdelphij for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { 1406285612Sdelphij if (rate >= rates[i]) 1407285612Sdelphij break; 140882498Sroberto } 1409285612Sdelphij value |= i; 1410285612Sdelphij return value; 1411285612Sdelphij} 1412285612Sdelphij