atkbd.c revision 46764
1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3191783Srmacklem * All rights reserved. 4191783Srmacklem * 5191783Srmacklem * Redistribution and use in source and binary forms, with or without 6191783Srmacklem * modification, are permitted provided that the following conditions 7191783Srmacklem * are met: 8191783Srmacklem * 1. Redistributions of source code must retain the above copyright 9191783Srmacklem * notice, this list of conditions and the following disclaimer as 10191783Srmacklem * the first lines of this file unmodified. 11191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer in the 13191783Srmacklem * documentation and/or other materials provided with the distribution. 14191783Srmacklem * 15191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16191783Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17191783Srmacklem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18191783Srmacklem * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19191783Srmacklem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20191783Srmacklem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21191783Srmacklem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22191783Srmacklem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23191783Srmacklem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24191783Srmacklem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25191783Srmacklem * 26191783Srmacklem * $Id: atkbd.c,v 1.6 1999/04/16 21:21:55 peter Exp $ 27191783Srmacklem */ 28191783Srmacklem 29191783Srmacklem#include "atkbd.h" 30191783Srmacklem#include "opt_kbd.h" 31191783Srmacklem#include "opt_atkbd.h" 32191783Srmacklem#include "opt_devfs.h" 33191783Srmacklem 34191783Srmacklem#if NATKBD > 0 35191783Srmacklem 36191783Srmacklem#include <sys/param.h> 37191783Srmacklem#include <sys/systm.h> 38191783Srmacklem#include <sys/kernel.h> 39191783Srmacklem#include <sys/conf.h> 40191783Srmacklem#include <sys/proc.h> 41191783Srmacklem#include <sys/tty.h> 42191783Srmacklem#include <sys/fcntl.h> 43191783Srmacklem#include <sys/malloc.h> 44191783Srmacklem 45192503Srmacklem#include <dev/kbd/kbdreg.h> 46192503Srmacklem#include <dev/kbd/atkbdreg.h> 47191783Srmacklem#include <dev/kbd/atkbdcreg.h> 48191783Srmacklem 49191783Srmacklem#if 1 50191783Srmacklem 51191783Srmacklem#include <sys/bus.h> 52191783Srmacklem#include <isa/isareg.h> 53191783Srmacklem 54191783Srmacklemextern devclass_t atkbd_devclass; 55191783Srmacklem 56191783Srmacklem#define ATKBD_SOFTC(unit) \ 57191783Srmacklem ((atkbd_softc_t *)devclass_get_softc(atkbd_devclass, unit)) 58191783Srmacklem 59191783Srmacklem#else /* __i386__ */ 60191783Srmacklem 61192503Srmacklem#include <i386/isa/isa.h> 62191783Srmacklem#include <i386/isa/isa_device.h> 63192255Srmacklem 64192255Srmacklemextern struct isa_driver atkbddriver; /* XXX: a kludge; see below */ 65191783Srmacklem 66191783Srmacklemstatic atkbd_softc_t *atkbd_softc[NATKBD]; 67191783Srmacklem 68191783Srmacklem#define ATKBD_SOFTC(unit) \ 69191783Srmacklem (((unit) >= NATKBD) ? NULL : atkbd_softc[(unit)]) 70192255Srmacklem 71192255Srmacklem#endif /* __i386__ */ 72191783Srmacklem 73192255Srmacklemstatic timeout_t atkbd_timeout; 74192255Srmacklem 75192255Srmacklem#ifdef KBD_INSTALL_CDEV 76192255Srmacklem 77192255Srmacklemstatic d_open_t atkbdopen; 78192255Srmacklemstatic d_close_t atkbdclose; 79192255Srmacklemstatic d_read_t atkbdread; 80192255Srmacklemstatic d_ioctl_t atkbdioctl; 81192255Srmacklemstatic d_poll_t atkbdpoll; 82192255Srmacklem 83191783Srmacklemstatic struct cdevsw atkbd_cdevsw = { 84191783Srmacklem atkbdopen, atkbdclose, atkbdread, nowrite, 85191783Srmacklem atkbdioctl, nostop, nullreset, nodevtotty, 86191783Srmacklem atkbdpoll, nommap, NULL, ATKBD_DRIVER_NAME, 87191783Srmacklem NULL, -1, 88191783Srmacklem}; 89191783Srmacklem 90191783Srmacklem#endif /* KBD_INSTALL_CDEV */ 91191783Srmacklem 92191783Srmacklem#if 0 93191783Srmacklem#ifdef __i386__ 94191783Srmacklem 95191783Srmacklematkbd_softc_t 96191783Srmacklem*atkbd_get_softc(int unit) 97191783Srmacklem{ 98191783Srmacklem atkbd_softc_t *sc; 99191783Srmacklem 100191783Srmacklem if (unit >= sizeof(atkbd_softc)/sizeof(atkbd_softc[0])) 101191783Srmacklem return NULL; 102191783Srmacklem sc = atkbd_softc[unit]; 103191783Srmacklem if (sc == NULL) { 104191783Srmacklem sc = atkbd_softc[unit] 105191783Srmacklem = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 106191783Srmacklem if (sc == NULL) 107191783Srmacklem return NULL; 108191783Srmacklem bzero(sc, sizeof(*sc)); 109191783Srmacklem } 110191783Srmacklem return sc; 111191783Srmacklem} 112191783Srmacklem 113191783Srmacklem#endif /* __i386__ */ 114191783Srmacklem#endif 115191783Srmacklem 116191783Srmacklemint 117191783Srmacklematkbd_probe_unit(int unit, int port, int irq, int flags) 118191783Srmacklem{ 119191783Srmacklem keyboard_switch_t *sw; 120191783Srmacklem int args[2]; 121191783Srmacklem int error; 122191783Srmacklem 123191783Srmacklem sw = kbd_get_switch(ATKBD_DRIVER_NAME); 124191783Srmacklem if (sw == NULL) 125191783Srmacklem return ENXIO; 126191783Srmacklem 127191783Srmacklem args[0] = port; 128191783Srmacklem args[1] = irq; 129191783Srmacklem error = (*sw->probe)(unit, args, flags); 130191783Srmacklem if (error) 131191783Srmacklem return error; 132191783Srmacklem return 0; 133191783Srmacklem} 134200999Srmacklem 135200999Srmacklemint 136200999Srmacklematkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags) 137191783Srmacklem{ 138191783Srmacklem keyboard_switch_t *sw; 139191783Srmacklem int args[2]; 140191783Srmacklem int error; 141191783Srmacklem 142200999Srmacklem if (sc->flags & ATKBD_ATTACHED) 143200999Srmacklem return 0; 144200999Srmacklem 145191783Srmacklem sw = kbd_get_switch(ATKBD_DRIVER_NAME); 146191783Srmacklem if (sw == NULL) 147191783Srmacklem return ENXIO; 148191783Srmacklem 149191783Srmacklem /* reset, initialize and enable the device */ 150191783Srmacklem args[0] = port; 151191783Srmacklem args[1] = irq; 152191783Srmacklem sc->kbd = NULL; 153191783Srmacklem error = (*sw->probe)(unit, args, flags); 154191783Srmacklem if (error) 155191783Srmacklem return error; 156191783Srmacklem error = (*sw->init)(unit, &sc->kbd, args, flags); 157200999Srmacklem if (error) 158191783Srmacklem return error; 159191783Srmacklem (*sw->enable)(sc->kbd); 160191783Srmacklem 161191783Srmacklem#ifdef KBD_INSTALL_CDEV 162191783Srmacklem /* attach a virtual keyboard cdev */ 163191783Srmacklem error = kbd_attach(makedev(0, ATKBD_MKMINOR(unit)), sc->kbd, 164191783Srmacklem &atkbd_cdevsw); 165191783Srmacklem if (error) 166191783Srmacklem return error; 167191783Srmacklem#endif 168191783Srmacklem 169191783Srmacklem /* 170191783Srmacklem * This is a kludge to compensate for lost keyboard interrupts. 171191783Srmacklem * A similar code used to be in syscons. See below. XXX 172191783Srmacklem */ 173191783Srmacklem atkbd_timeout(sc->kbd); 174191783Srmacklem 175191783Srmacklem if (bootverbose) 176191783Srmacklem (*sw->diag)(sc->kbd, bootverbose); 177191783Srmacklem 178191783Srmacklem sc->flags |= ATKBD_ATTACHED; 179191783Srmacklem return 0; 180191783Srmacklem} 181200999Srmacklem 182200999Srmacklemstatic void 183200999Srmacklematkbd_timeout(void *arg) 184200999Srmacklem{ 185200999Srmacklem keyboard_t *kbd; 186200999Srmacklem int s; 187200999Srmacklem 188200999Srmacklem /* The following comments are extracted from syscons.c (1.287) */ 189200999Srmacklem /* 190200999Srmacklem * With release 2.1 of the Xaccel server, the keyboard is left 191200999Srmacklem * hanging pretty often. Apparently an interrupt from the 192200999Srmacklem * keyboard is lost, and I don't know why (yet). 193200999Srmacklem * This ugly hack calls scintr if input is ready for the keyboard 194200999Srmacklem * and conveniently hides the problem. XXX 195200999Srmacklem */ 196200999Srmacklem /* 197200999Srmacklem * Try removing anything stuck in the keyboard controller; whether 198191783Srmacklem * it's a keyboard scan code or mouse data. `scintr()' doesn't 199191783Srmacklem * read the mouse data directly, but `kbdio' routines will, as a 200191783Srmacklem * side effect. 201191783Srmacklem */ 202191783Srmacklem s = spltty(); 203191783Srmacklem kbd = (keyboard_t *)arg; 204191783Srmacklem if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { 205191783Srmacklem /* 206191783Srmacklem * We have seen the lock flag is not set. Let's reset 207191783Srmacklem * the flag early, otherwise the LED update routine fails 208191783Srmacklem * which may want the lock during the interrupt routine. 209191783Srmacklem */ 210191783Srmacklem (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); 211191783Srmacklem if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) 212191783Srmacklem (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 213191783Srmacklem } 214191783Srmacklem splx(s); 215191783Srmacklem timeout(atkbd_timeout, arg, hz/10); 216191783Srmacklem} 217191783Srmacklem 218191783Srmacklem/* cdev driver functions */ 219191783Srmacklem 220191783Srmacklem#ifdef KBD_INSTALL_CDEV 221191783Srmacklem 222191783Srmacklemstatic int 223191783Srmacklematkbdopen(dev_t dev, int flag, int mode, struct proc *p) 224191783Srmacklem{ 225191783Srmacklem atkbd_softc_t *sc; 226191783Srmacklem 227191783Srmacklem sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 228191783Srmacklem if (sc == NULL) 229191783Srmacklem return ENXIO; 230191783Srmacklem if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC)) 231191783Srmacklem return ENODEV; 232191783Srmacklem 233191783Srmacklem /* FIXME: set the initial input mode (K_XLATE?) and lock state? */ 234191783Srmacklem return genkbdopen(&sc->gensc, sc->kbd, flag, mode, p); 235191783Srmacklem} 236191783Srmacklem 237191783Srmacklemstatic int 238191783Srmacklematkbdclose(dev_t dev, int flag, int mode, struct proc *p) 239191783Srmacklem{ 240191783Srmacklem atkbd_softc_t *sc; 241191783Srmacklem 242191783Srmacklem sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 243191783Srmacklem return genkbdclose(&sc->gensc, sc->kbd, flag, mode, p); 244191783Srmacklem} 245191783Srmacklem 246191783Srmacklemstatic int 247191783Srmacklematkbdread(dev_t dev, struct uio *uio, int flag) 248191783Srmacklem{ 249191783Srmacklem atkbd_softc_t *sc; 250191783Srmacklem 251191783Srmacklem sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 252191783Srmacklem return genkbdread(&sc->gensc, sc->kbd, uio, flag); 253191783Srmacklem} 254191783Srmacklem 255191783Srmacklemstatic int 256191783Srmacklematkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 257191783Srmacklem{ 258191783Srmacklem atkbd_softc_t *sc; 259191783Srmacklem 260191783Srmacklem sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 261191783Srmacklem return genkbdioctl(&sc->gensc, sc->kbd, cmd, arg, flag, p); 262191783Srmacklem} 263191783Srmacklem 264191783Srmacklemstatic int 265191783Srmacklematkbdpoll(dev_t dev, int event, struct proc *p) 266191783Srmacklem{ 267191783Srmacklem atkbd_softc_t *sc; 268191783Srmacklem 269191783Srmacklem sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 270191783Srmacklem return genkbdpoll(&sc->gensc, sc->kbd, event, p); 271191783Srmacklem} 272191783Srmacklem 273191783Srmacklem#endif /* KBD_INSTALL_CDEV */ 274191783Srmacklem 275191783Srmacklem/* LOW-LEVEL */ 276191783Srmacklem 277191783Srmacklem#include <machine/limits.h> 278191783Srmacklem#include <machine/console.h> 279191783Srmacklem#include <machine/clock.h> 280191783Srmacklem 281191783Srmacklem#define ATKBD_DEFAULT 0 282191783Srmacklem 283191783Srmacklemtypedef struct atkbd_state { 284191783Srmacklem KBDC kbdc; /* keyboard controller */ 285191783Srmacklem /* XXX: don't move this field; pcvt 286191783Srmacklem * expects `kbdc' to be the first 287191783Srmacklem * field in this structure. */ 288191783Srmacklem int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 289191783Srmacklem int ks_flags; /* flags */ 290191783Srmacklem#define COMPOSE (1 << 0) 291191783Srmacklem int ks_polling; 292191783Srmacklem int ks_state; /* shift/lock key state */ 293191783Srmacklem int ks_accents; /* accent key index (> 0) */ 294191783Srmacklem u_int ks_composed_char; /* composed char code (> 0) */ 295191783Srmacklem u_char ks_prefix; /* AT scan code prefix */ 296191783Srmacklem} atkbd_state_t; 297191783Srmacklem 298191783Srmacklem/* keyboard driver declaration */ 299191783Srmacklemstatic int atkbd_configure(int flags); 300191783Srmacklemstatic kbd_probe_t atkbd_probe; 301191783Srmacklemstatic kbd_init_t atkbd_init; 302191783Srmacklemstatic kbd_term_t atkbd_term; 303191783Srmacklemstatic kbd_intr_t atkbd_intr; 304191783Srmacklemstatic kbd_test_if_t atkbd_test_if; 305191783Srmacklemstatic kbd_enable_t atkbd_enable; 306191783Srmacklemstatic kbd_disable_t atkbd_disable; 307191783Srmacklemstatic kbd_read_t atkbd_read; 308191783Srmacklemstatic kbd_check_t atkbd_check; 309191783Srmacklemstatic kbd_read_char_t atkbd_read_char; 310191783Srmacklemstatic kbd_check_char_t atkbd_check_char; 311191783Srmacklemstatic kbd_ioctl_t atkbd_ioctl; 312191783Srmacklemstatic kbd_lock_t atkbd_lock; 313191783Srmacklemstatic kbd_clear_state_t atkbd_clear_state; 314191783Srmacklemstatic kbd_get_state_t atkbd_get_state; 315191783Srmacklemstatic kbd_set_state_t atkbd_set_state; 316191783Srmacklemstatic kbd_poll_mode_t atkbd_poll; 317191783Srmacklem 318191783Srmacklemkeyboard_switch_t atkbdsw = { 319191783Srmacklem atkbd_probe, 320191783Srmacklem atkbd_init, 321191783Srmacklem atkbd_term, 322191783Srmacklem atkbd_intr, 323191783Srmacklem atkbd_test_if, 324191783Srmacklem atkbd_enable, 325191783Srmacklem atkbd_disable, 326191783Srmacklem atkbd_read, 327191783Srmacklem atkbd_check, 328191783Srmacklem atkbd_read_char, 329191783Srmacklem atkbd_check_char, 330191783Srmacklem atkbd_ioctl, 331191783Srmacklem atkbd_lock, 332191783Srmacklem atkbd_clear_state, 333191783Srmacklem atkbd_get_state, 334191783Srmacklem atkbd_set_state, 335191783Srmacklem genkbd_get_fkeystr, 336191783Srmacklem atkbd_poll, 337191783Srmacklem genkbd_diag, 338191783Srmacklem}; 339191783Srmacklem 340191783SrmacklemKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); 341191783Srmacklem 342191783Srmacklem/* local functions */ 343191783Srmacklemstatic int setup_kbd_port(KBDC kbdc, int port, int intr); 344191783Srmacklemstatic int get_kbd_echo(KBDC kbdc); 345191783Srmacklemstatic int probe_keyboard(KBDC kbdc, int flags); 346191783Srmacklemstatic int init_keyboard(KBDC kbdc, int *type, int flags); 347191783Srmacklemstatic int write_kbd(KBDC kbdc, int command, int data); 348191783Srmacklemstatic int get_kbd_id(KBDC kbdc); 349191783Srmacklemstatic int typematic(int delay, int rate); 350191783Srmacklem 351191783Srmacklem/* local variables */ 352191783Srmacklem 353191783Srmacklem/* the initial key map, accent map and fkey strings */ 354191783Srmacklem#ifdef ATKBD_DFLT_KEYMAP 355191783Srmacklem#define KBD_DFLT_KEYMAP 356191783Srmacklem#include "atkbdmap.h" 357191783Srmacklem#endif 358191783Srmacklem#include <dev/kbd/kbdtables.h> 359191783Srmacklem 360191783Srmacklem/* structures for the default keyboard */ 361191783Srmacklemstatic keyboard_t default_kbd; 362191783Srmacklemstatic atkbd_state_t default_kbd_state; 363191783Srmacklemstatic keymap_t default_keymap; 364191783Srmacklemstatic accentmap_t default_accentmap; 365191783Srmacklemstatic fkeytab_t default_fkeytab[NUM_FKEYS]; 366191783Srmacklem 367191783Srmacklem/* 368191783Srmacklem * The back door to the keyboard driver! 369191783Srmacklem * This function is called by the console driver, via the kbdio module, 370191783Srmacklem * to tickle keyboard drivers when the low-level console is being initialized. 371191783Srmacklem * Almost nothing in the kernel has been initialied yet. Try to probe 372191783Srmacklem * keyboards if possible. 373191783Srmacklem * NOTE: because of the way the low-level conole is initialized, this routine 374191783Srmacklem * may be called more than once!! 375191783Srmacklem */ 376191783Srmacklemstatic int 377191783Srmacklematkbd_configure(int flags) 378191783Srmacklem{ 379191783Srmacklem keyboard_t *kbd; 380191783Srmacklem int arg[2]; 381191783Srmacklem int i; 382191783Srmacklem 383191783Srmacklem /* if the driver is disabled, unregister the keyboard if any */ 384191783Srmacklem if ((resource_int_value("atkbd", ATKBD_DEFAULT, "disabled", &i) == 0) 385191783Srmacklem && i != 0) { 386191783Srmacklem i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT); 387191783Srmacklem if (i >= 0) { 388191783Srmacklem kbd = kbd_get_keyboard(i); 389191783Srmacklem kbd_unregister(kbd); 390191783Srmacklem kbd->kb_flags &= ~KB_REGISTERED; 391191783Srmacklem return 0; 392191783Srmacklem } 393191783Srmacklem } 394191783Srmacklem 395191783Srmacklem /* XXX: a kludge to obtain the device configuration flags */ 396191783Srmacklem if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0) 397191783Srmacklem flags |= i; 398191783Srmacklem 399191783Srmacklem /* probe the keyboard controller */ 400191783Srmacklem atkbdc_configure(); 401191783Srmacklem 402191783Srmacklem /* probe the default keyboard */ 403191783Srmacklem arg[0] = -1; 404191783Srmacklem arg[1] = -1; 405191783Srmacklem kbd = NULL; 406191783Srmacklem if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) 407191783Srmacklem return 0; 408191783Srmacklem if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) 409191783Srmacklem return 0; 410191783Srmacklem 411191783Srmacklem /* return the number of found keyboards */ 412191783Srmacklem return 1; 413191783Srmacklem} 414191783Srmacklem 415191783Srmacklem/* low-level functions */ 416191783Srmacklem 417191783Srmacklem/* detect a keyboard */ 418191783Srmacklemstatic int 419191783Srmacklematkbd_probe(int unit, void *arg, int flags) 420191783Srmacklem{ 421191783Srmacklem KBDC kbdc; 422191783Srmacklem int *data = (int *)arg; 423191783Srmacklem 424191783Srmacklem /* XXX */ 425191783Srmacklem if (unit == ATKBD_DEFAULT) { 426191783Srmacklem if (KBD_IS_PROBED(&default_kbd)) 427191783Srmacklem return 0; 428191783Srmacklem } 429191783Srmacklem 430191783Srmacklem kbdc = kbdc_open(data[0]); 431191783Srmacklem if (kbdc == NULL) 432191783Srmacklem return ENXIO; 433191783Srmacklem if (probe_keyboard(kbdc, flags)) { 434191783Srmacklem if (flags & KB_CONF_FAIL_IF_NO_KBD) 435191783Srmacklem return ENXIO; 436191783Srmacklem } 437191783Srmacklem return 0; 438191783Srmacklem} 439191783Srmacklem 440191783Srmacklem/* reset and initialize the device */ 441191783Srmacklemstatic int 442191783Srmacklematkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 443191783Srmacklem{ 444191783Srmacklem keyboard_t *kbd; 445191783Srmacklem atkbd_state_t *state; 446191783Srmacklem keymap_t *keymap; 447191783Srmacklem accentmap_t *accmap; 448191783Srmacklem fkeytab_t *fkeymap; 449191783Srmacklem int fkeymap_size; 450191783Srmacklem int *data = (int *)arg; 451191783Srmacklem 452191783Srmacklem /* XXX */ 453191783Srmacklem if (unit == ATKBD_DEFAULT) { 454191783Srmacklem *kbdp = kbd = &default_kbd; 455191783Srmacklem if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) 456191783Srmacklem return 0; 457191783Srmacklem state = &default_kbd_state; 458191783Srmacklem keymap = &default_keymap; 459191783Srmacklem accmap = &default_accentmap; 460191783Srmacklem fkeymap = default_fkeytab; 461191783Srmacklem fkeymap_size = 462191783Srmacklem sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 463191783Srmacklem } else if (*kbdp == NULL) { 464191783Srmacklem *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT); 465191783Srmacklem if (kbd == NULL) 466191783Srmacklem return ENOMEM; 467191783Srmacklem bzero(kbd, sizeof(*kbd)); 468191783Srmacklem state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT); 469191783Srmacklem keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); 470191783Srmacklem accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); 471191783Srmacklem fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); 472191783Srmacklem fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 473191783Srmacklem if ((state == NULL) || (keymap == NULL) || (accmap == NULL) 474191783Srmacklem || (fkeymap == NULL)) { 475191783Srmacklem if (state != NULL) 476191783Srmacklem free(state, M_DEVBUF); 477191783Srmacklem if (keymap != NULL) 478191783Srmacklem free(keymap, M_DEVBUF); 479191783Srmacklem if (accmap != NULL) 480191783Srmacklem free(accmap, M_DEVBUF); 481191783Srmacklem if (fkeymap != NULL) 482191783Srmacklem free(fkeymap, M_DEVBUF); 483191783Srmacklem free(kbd, M_DEVBUF); 484191783Srmacklem return ENOMEM; 485191783Srmacklem } 486191783Srmacklem bzero(state, sizeof(*state)); 487191783Srmacklem } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 488191783Srmacklem return 0; 489191783Srmacklem } else { 490191783Srmacklem kbd = *kbdp; 491191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 492191783Srmacklem bzero(state, sizeof(*state)); 493191783Srmacklem keymap = kbd->kb_keymap; 494191783Srmacklem accmap = kbd->kb_accentmap; 495191783Srmacklem fkeymap = kbd->kb_fkeytab; 496191783Srmacklem fkeymap_size = kbd->kb_fkeytab_size; 497191783Srmacklem } 498191783Srmacklem 499191783Srmacklem if (!KBD_IS_PROBED(kbd)) { 500191783Srmacklem state->kbdc = kbdc_open(data[0]); 501191783Srmacklem if (state->kbdc == NULL) 502191783Srmacklem return ENXIO; 503191783Srmacklem kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 504191783Srmacklem data[0], IO_KBDSIZE); 505191783Srmacklem bcopy(&key_map, keymap, sizeof(key_map)); 506191783Srmacklem bcopy(&accent_map, accmap, sizeof(accent_map)); 507191783Srmacklem bcopy(fkey_tab, fkeymap, 508191783Srmacklem imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 509191783Srmacklem kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 510191783Srmacklem kbd->kb_data = (void *)state; 511191783Srmacklem 512191783Srmacklem if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ 513191783Srmacklem if (flags & KB_CONF_FAIL_IF_NO_KBD) 514191783Srmacklem return ENXIO; 515191783Srmacklem } else { 516191783Srmacklem KBD_FOUND_DEVICE(kbd); 517191783Srmacklem } 518191783Srmacklem atkbd_clear_state(kbd); 519191783Srmacklem state->ks_mode = K_XLATE; 520191783Srmacklem /* 521191783Srmacklem * FIXME: set the initial value for lock keys in ks_state 522191783Srmacklem * according to the BIOS data? 523191783Srmacklem */ 524191783Srmacklem KBD_PROBE_DONE(kbd); 525191783Srmacklem } 526191783Srmacklem if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 527191783Srmacklem if (KBD_HAS_DEVICE(kbd) 528191783Srmacklem && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 529191783Srmacklem && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 530191783Srmacklem return ENXIO; 531191783Srmacklem atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 532191783Srmacklem KBD_INIT_DONE(kbd); 533191783Srmacklem } 534191783Srmacklem if (!KBD_IS_CONFIGURED(kbd)) { 535191783Srmacklem if (kbd_register(kbd) < 0) 536191783Srmacklem return ENXIO; 537191783Srmacklem KBD_CONFIG_DONE(kbd); 538191783Srmacklem } 539191783Srmacklem 540191783Srmacklem return 0; 541191783Srmacklem} 542191783Srmacklem 543191783Srmacklem/* finish using this keyboard */ 544191783Srmacklemstatic int 545191783Srmacklematkbd_term(keyboard_t *kbd) 546191783Srmacklem{ 547191783Srmacklem kbd_unregister(kbd); 548191783Srmacklem return 0; 549191783Srmacklem} 550191783Srmacklem 551191783Srmacklem/* keyboard interrupt routine */ 552191783Srmacklemstatic int 553191783Srmacklematkbd_intr(keyboard_t *kbd, void *arg) 554191783Srmacklem{ 555191783Srmacklem atkbd_state_t *state; 556191783Srmacklem int c; 557191783Srmacklem 558191783Srmacklem if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 559191783Srmacklem /* let the callback function to process the input */ 560191783Srmacklem (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 561191783Srmacklem kbd->kb_callback.kc_arg); 562191783Srmacklem } else { 563191783Srmacklem /* read and discard the input; no one is waiting for input */ 564191783Srmacklem do { 565191783Srmacklem c = atkbd_read_char(kbd, FALSE); 566191783Srmacklem } while (c != NOKEY); 567191783Srmacklem 568191783Srmacklem if (!KBD_HAS_DEVICE(kbd)) { 569191783Srmacklem /* 570191783Srmacklem * The keyboard was not detected before; 571191783Srmacklem * it must have been reconnected! 572191783Srmacklem */ 573191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 574191783Srmacklem init_keyboard(state->kbdc, &kbd->kb_type, 575191783Srmacklem kbd->kb_config); 576191783Srmacklem atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 577191783Srmacklem KBD_FOUND_DEVICE(kbd); 578191783Srmacklem } 579191783Srmacklem } 580191783Srmacklem return 0; 581191783Srmacklem} 582191783Srmacklem 583191783Srmacklem/* test the interface to the device */ 584191783Srmacklemstatic int 585191783Srmacklematkbd_test_if(keyboard_t *kbd) 586191783Srmacklem{ 587191783Srmacklem int error; 588191783Srmacklem int s; 589191783Srmacklem 590191783Srmacklem error = 0; 591191783Srmacklem empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10); 592191783Srmacklem s = spltty(); 593191783Srmacklem if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc)) 594191783Srmacklem error = EIO; 595191783Srmacklem else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0) 596191783Srmacklem error = EIO; 597191783Srmacklem splx(s); 598191783Srmacklem 599191783Srmacklem return error; 600191783Srmacklem} 601191783Srmacklem 602191783Srmacklem/* 603191783Srmacklem * Enable the access to the device; until this function is called, 604191783Srmacklem * the client cannot read from the keyboard. 605191783Srmacklem */ 606191783Srmacklemstatic int 607191783Srmacklematkbd_enable(keyboard_t *kbd) 608191783Srmacklem{ 609191783Srmacklem int s; 610191783Srmacklem 611191783Srmacklem s = spltty(); 612191783Srmacklem KBD_ACTIVATE(kbd); 613191783Srmacklem splx(s); 614191783Srmacklem return 0; 615191783Srmacklem} 616191783Srmacklem 617191783Srmacklem/* disallow the access to the device */ 618191783Srmacklemstatic int 619191783Srmacklematkbd_disable(keyboard_t *kbd) 620191783Srmacklem{ 621191783Srmacklem int s; 622191783Srmacklem 623191783Srmacklem s = spltty(); 624191783Srmacklem KBD_DEACTIVATE(kbd); 625191783Srmacklem splx(s); 626191783Srmacklem return 0; 627191783Srmacklem} 628191783Srmacklem 629191783Srmacklem/* read one byte from the keyboard if it's allowed */ 630191783Srmacklemstatic int 631191783Srmacklematkbd_read(keyboard_t *kbd, int wait) 632191783Srmacklem{ 633191783Srmacklem int c; 634191783Srmacklem 635191783Srmacklem if (wait) 636191783Srmacklem c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc); 637191783Srmacklem else 638191783Srmacklem c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc); 639191783Srmacklem return (KBD_IS_ACTIVE(kbd) ? c : -1); 640191783Srmacklem} 641191783Srmacklem 642191783Srmacklem/* check if data is waiting */ 643191783Srmacklemstatic int 644191783Srmacklematkbd_check(keyboard_t *kbd) 645191783Srmacklem{ 646191783Srmacklem if (!KBD_IS_ACTIVE(kbd)) 647191783Srmacklem return FALSE; 648191783Srmacklem return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc); 649191783Srmacklem} 650191783Srmacklem 651191783Srmacklem/* read char from the keyboard */ 652191783Srmacklemstatic u_int 653191783Srmacklematkbd_read_char(keyboard_t *kbd, int wait) 654191783Srmacklem{ 655191783Srmacklem atkbd_state_t *state; 656191783Srmacklem u_int action; 657191783Srmacklem int scancode; 658191783Srmacklem int keycode; 659191783Srmacklem 660191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 661191783Srmacklemnext_code: 662191783Srmacklem /* do we have a composed char to return? */ 663191783Srmacklem if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 664191783Srmacklem action = state->ks_composed_char; 665191783Srmacklem state->ks_composed_char = 0; 666191783Srmacklem if (action > UCHAR_MAX) 667191783Srmacklem return ERRKEY; 668191783Srmacklem return action; 669191783Srmacklem } 670191783Srmacklem 671191783Srmacklem /* see if there is something in the keyboard port */ 672191783Srmacklem if (wait) { 673191783Srmacklem do { 674191783Srmacklem scancode = read_kbd_data(state->kbdc); 675191783Srmacklem } while (scancode == -1); 676191783Srmacklem } else { 677191783Srmacklem scancode = read_kbd_data_no_wait(state->kbdc); 678191783Srmacklem if (scancode == -1) 679191783Srmacklem return NOKEY; 680191783Srmacklem } 681191783Srmacklem 682191783Srmacklem /* return the byte as is for the K_RAW mode */ 683191783Srmacklem if (state->ks_mode == K_RAW) 684191783Srmacklem return scancode; 685191783Srmacklem 686191783Srmacklem /* translate the scan code into a keycode */ 687191783Srmacklem keycode = scancode & 0x7F; 688191783Srmacklem switch (state->ks_prefix) { 689191783Srmacklem case 0x00: /* normal scancode */ 690191783Srmacklem switch(scancode) { 691191783Srmacklem case 0xB8: /* left alt (compose key) released */ 692191783Srmacklem if (state->ks_flags & COMPOSE) { 693191783Srmacklem state->ks_flags &= ~COMPOSE; 694191783Srmacklem if (state->ks_composed_char > UCHAR_MAX) 695191783Srmacklem state->ks_composed_char = 0; 696191783Srmacklem } 697191783Srmacklem break; 698191783Srmacklem case 0x38: /* left alt (compose key) pressed */ 699191783Srmacklem if (!(state->ks_flags & COMPOSE)) { 700191783Srmacklem state->ks_flags |= COMPOSE; 701191783Srmacklem state->ks_composed_char = 0; 702191783Srmacklem } 703191783Srmacklem break; 704191783Srmacklem case 0xE0: 705191783Srmacklem case 0xE1: 706191783Srmacklem state->ks_prefix = scancode; 707191783Srmacklem goto next_code; 708191783Srmacklem } 709191783Srmacklem break; 710191783Srmacklem case 0xE0: /* 0xE0 prefix */ 711191783Srmacklem state->ks_prefix = 0; 712191783Srmacklem switch (keycode) { 713191783Srmacklem case 0x1C: /* right enter key */ 714191783Srmacklem keycode = 0x59; 715199616Srmacklem break; 716191783Srmacklem case 0x1D: /* right ctrl key */ 717191783Srmacklem keycode = 0x5A; 718191783Srmacklem break; 719191783Srmacklem case 0x35: /* keypad divide key */ 720191783Srmacklem keycode = 0x5B; 721191783Srmacklem break; 722191783Srmacklem case 0x37: /* print scrn key */ 723191783Srmacklem keycode = 0x5C; 724191783Srmacklem break; 725191783Srmacklem case 0x38: /* right alt key (alt gr) */ 726191783Srmacklem keycode = 0x5D; 727191783Srmacklem break; 728191783Srmacklem case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 729191783Srmacklem keycode = 0x68; 730191783Srmacklem break; 731191783Srmacklem case 0x47: /* grey home key */ 732199616Srmacklem keycode = 0x5E; 733199616Srmacklem break; 734191783Srmacklem case 0x48: /* grey up arrow key */ 735191783Srmacklem keycode = 0x5F; 736191783Srmacklem break; 737191783Srmacklem case 0x49: /* grey page up key */ 738191783Srmacklem keycode = 0x60; 739191783Srmacklem break; 740191783Srmacklem case 0x4B: /* grey left arrow key */ 741191783Srmacklem keycode = 0x61; 742191783Srmacklem break; 743191783Srmacklem case 0x4D: /* grey right arrow key */ 744191783Srmacklem keycode = 0x62; 745191783Srmacklem break; 746191783Srmacklem case 0x4F: /* grey end key */ 747191783Srmacklem keycode = 0x63; 748191783Srmacklem break; 749191783Srmacklem case 0x50: /* grey down arrow key */ 750191783Srmacklem keycode = 0x64; 751191783Srmacklem break; 752191783Srmacklem case 0x51: /* grey page down key */ 753191783Srmacklem keycode = 0x65; 754191783Srmacklem break; 755191783Srmacklem case 0x52: /* grey insert key */ 756191783Srmacklem keycode = 0x66; 757191783Srmacklem break; 758191783Srmacklem case 0x53: /* grey delete key */ 759191783Srmacklem keycode = 0x67; 760191783Srmacklem break; 761191783Srmacklem /* the following 3 are only used on the MS "Natural" keyboard */ 762191783Srmacklem case 0x5b: /* left Window key */ 763191783Srmacklem keycode = 0x69; 764191783Srmacklem break; 765191783Srmacklem case 0x5c: /* right Window key */ 766191783Srmacklem keycode = 0x6a; 767191783Srmacklem break; 768191783Srmacklem case 0x5d: /* menu key */ 769191783Srmacklem keycode = 0x6b; 770191783Srmacklem break; 771191783Srmacklem default: /* ignore everything else */ 772191783Srmacklem goto next_code; 773191783Srmacklem } 774191783Srmacklem break; 775191783Srmacklem case 0xE1: /* 0xE1 prefix */ 776191783Srmacklem /* 777191783Srmacklem * The pause/break key on the 101 keyboard produces: 778191783Srmacklem * E1-1D-45 E1-9D-C5 779191783Srmacklem * Ctrl-pause/break produces: 780191783Srmacklem * E0-46 E0-C6 (See above.) 781191783Srmacklem */ 782191783Srmacklem state->ks_prefix = 0; 783191783Srmacklem if (keycode == 0x1D) 784191783Srmacklem state->ks_prefix = 0x1D; 785200999Srmacklem goto next_code; 786191783Srmacklem /* NOT REACHED */ 787200999Srmacklem case 0x1D: /* pause / break */ 788191783Srmacklem state->ks_prefix = 0; 789191783Srmacklem if (keycode != 0x45) 790191783Srmacklem goto next_code; 791191783Srmacklem keycode = 0x68; 792191783Srmacklem break; 793191783Srmacklem } 794191783Srmacklem 795191783Srmacklem if (kbd->kb_type == KB_84) { 796191783Srmacklem switch (keycode) { 797191783Srmacklem case 0x37: /* *(numpad)/print screen */ 798191783Srmacklem if (state->ks_flags & SHIFTS) 799191783Srmacklem keycode = 0x5c; /* print screen */ 800191783Srmacklem break; 801191783Srmacklem case 0x45: /* num lock/pause */ 802191783Srmacklem if (state->ks_flags & CTLS) 803191783Srmacklem keycode = 0x68; /* pause */ 804191783Srmacklem break; 805191783Srmacklem case 0x46: /* scroll lock/break */ 806191783Srmacklem if (state->ks_flags & CTLS) 807191783Srmacklem keycode = 0x6c; /* break */ 808191783Srmacklem break; 809191783Srmacklem } 810191783Srmacklem } else if (kbd->kb_type == KB_101) { 811191783Srmacklem switch (keycode) { 812191783Srmacklem case 0x5c: /* print screen */ 813191783Srmacklem if (state->ks_flags & ALTS) 814191783Srmacklem keycode = 0x54; /* sysrq */ 815191783Srmacklem break; 816191783Srmacklem case 0x68: /* pause/break */ 817191783Srmacklem if (state->ks_flags & CTLS) 818191783Srmacklem keycode = 0x6c; /* break */ 819191783Srmacklem break; 820191783Srmacklem } 821191783Srmacklem } 822191783Srmacklem 823191783Srmacklem /* return the key code in the K_CODE mode */ 824191783Srmacklem if (state->ks_mode == K_CODE) 825191783Srmacklem return (keycode | (scancode & 0x80)); 826191783Srmacklem 827191783Srmacklem /* compose a character code */ 828191783Srmacklem if (state->ks_flags & COMPOSE) { 829191783Srmacklem switch (scancode) { 830191783Srmacklem /* key pressed, process it */ 831191783Srmacklem case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 832191783Srmacklem state->ks_composed_char *= 10; 833191783Srmacklem state->ks_composed_char += scancode - 0x40; 834191783Srmacklem if (state->ks_composed_char > UCHAR_MAX) 835191783Srmacklem return ERRKEY; 836191783Srmacklem goto next_code; 837191783Srmacklem case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 838191783Srmacklem state->ks_composed_char *= 10; 839191783Srmacklem state->ks_composed_char += scancode - 0x47; 840191783Srmacklem if (state->ks_composed_char > UCHAR_MAX) 841191783Srmacklem return ERRKEY; 842191783Srmacklem goto next_code; 843191783Srmacklem case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 844191783Srmacklem state->ks_composed_char *= 10; 845191783Srmacklem state->ks_composed_char += scancode - 0x4E; 846191783Srmacklem if (state->ks_composed_char > UCHAR_MAX) 847191783Srmacklem return ERRKEY; 848191783Srmacklem goto next_code; 849191783Srmacklem case 0x52: /* keypad 0 */ 850191783Srmacklem state->ks_composed_char *= 10; 851191783Srmacklem if (state->ks_composed_char > UCHAR_MAX) 852191783Srmacklem return ERRKEY; 853191783Srmacklem goto next_code; 854191783Srmacklem 855191783Srmacklem /* key released, no interest here */ 856191783Srmacklem case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 857191783Srmacklem case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 858191783Srmacklem case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 859191783Srmacklem case 0xD2: /* keypad 0 */ 860191783Srmacklem goto next_code; 861191783Srmacklem 862191783Srmacklem case 0x38: /* left alt key */ 863191783Srmacklem break; 864191783Srmacklem 865191783Srmacklem default: 866191783Srmacklem if (state->ks_composed_char > 0) { 867191783Srmacklem state->ks_flags &= ~COMPOSE; 868191783Srmacklem state->ks_composed_char = 0; 869191783Srmacklem return ERRKEY; 870191783Srmacklem } 871191783Srmacklem break; 872191783Srmacklem } 873191783Srmacklem } 874191783Srmacklem 875191783Srmacklem /* keycode to key action */ 876191783Srmacklem action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 877191783Srmacklem &state->ks_state, &state->ks_accents); 878191783Srmacklem if (action == NOKEY) 879191783Srmacklem goto next_code; 880191783Srmacklem else 881191783Srmacklem return action; 882191783Srmacklem} 883191783Srmacklem 884191783Srmacklem/* check if char is waiting */ 885191783Srmacklemstatic int 886191783Srmacklematkbd_check_char(keyboard_t *kbd) 887191783Srmacklem{ 888191783Srmacklem atkbd_state_t *state; 889191783Srmacklem 890191783Srmacklem if (!KBD_IS_ACTIVE(kbd)) 891191783Srmacklem return FALSE; 892191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 893191783Srmacklem if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 894191783Srmacklem return TRUE; 895191783Srmacklem return kbdc_data_ready(state->kbdc); 896191783Srmacklem} 897191783Srmacklem 898191783Srmacklem/* some useful control functions */ 899191783Srmacklemstatic int 900191783Srmacklematkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 901191783Srmacklem{ 902191783Srmacklem /* trasnlate LED_XXX bits into the device specific bits */ 903191783Srmacklem static u_char ledmap[8] = { 904191783Srmacklem 0, 4, 2, 6, 1, 5, 3, 7, 905191783Srmacklem }; 906191783Srmacklem atkbd_state_t *state = kbd->kb_data; 907191783Srmacklem int error; 908191783Srmacklem int s; 909191783Srmacklem int i; 910191783Srmacklem 911191783Srmacklem s = spltty(); 912191783Srmacklem switch (cmd) { 913191783Srmacklem 914191783Srmacklem case KDGKBMODE: /* get keyboard mode */ 915191783Srmacklem *(int *)arg = state->ks_mode; 916191783Srmacklem break; 917191783Srmacklem case KDSKBMODE: /* set keyboard mode */ 918191783Srmacklem switch (*(int *)arg) { 919191783Srmacklem case K_XLATE: 920191783Srmacklem if (state->ks_mode != K_XLATE) { 921191783Srmacklem /* make lock key state and LED state match */ 922191783Srmacklem state->ks_state &= ~LOCK_MASK; 923191783Srmacklem state->ks_state |= KBD_LED_VAL(kbd); 924191783Srmacklem } 925191783Srmacklem /* FALL THROUGH */ 926191783Srmacklem case K_RAW: 927191783Srmacklem case K_CODE: 928191783Srmacklem if (state->ks_mode != *(int *)arg) { 929191783Srmacklem atkbd_clear_state(kbd); 930191783Srmacklem state->ks_mode = *(int *)arg; 931191783Srmacklem } 932191783Srmacklem break; 933191783Srmacklem default: 934191783Srmacklem splx(s); 935191783Srmacklem return EINVAL; 936191783Srmacklem } 937191783Srmacklem break; 938191783Srmacklem 939191783Srmacklem case KDGETLED: /* get keyboard LED */ 940191783Srmacklem *(int *)arg = KBD_LED_VAL(kbd); 941191783Srmacklem break; 942191783Srmacklem case KDSETLED: /* set keyboard LED */ 943191783Srmacklem /* NOTE: lock key state in ks_state won't be changed */ 944191783Srmacklem if (*(int *)arg & ~LOCK_MASK) { 945191783Srmacklem splx(s); 946191783Srmacklem return EINVAL; 947191783Srmacklem } 948191783Srmacklem i = *(int *)arg; 949191783Srmacklem /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 950191783Srmacklem if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 951191783Srmacklem if (i & ALKED) 952191783Srmacklem i |= CLKED; 953191783Srmacklem else 954191783Srmacklem i &= ~CLKED; 955191783Srmacklem } 956191783Srmacklem if (KBD_HAS_DEVICE(kbd)) { 957191783Srmacklem error = write_kbd(state->kbdc, KBDC_SET_LEDS, 958191783Srmacklem ledmap[i & LED_MASK]); 959191783Srmacklem if (error) { 960191783Srmacklem splx(s); 961191783Srmacklem return error; 962191783Srmacklem } 963191783Srmacklem } 964191783Srmacklem KBD_LED_VAL(kbd) = *(int *)arg; 965191783Srmacklem break; 966191783Srmacklem 967191783Srmacklem case KDGKBSTATE: /* get lock key state */ 968191783Srmacklem *(int *)arg = state->ks_state & LOCK_MASK; 969191783Srmacklem break; 970191783Srmacklem case KDSKBSTATE: /* set lock key state */ 971191783Srmacklem if (*(int *)arg & ~LOCK_MASK) { 972191783Srmacklem splx(s); 973191783Srmacklem return EINVAL; 974191783Srmacklem } 975191783Srmacklem state->ks_state &= ~LOCK_MASK; 976191783Srmacklem state->ks_state |= *(int *)arg; 977191783Srmacklem splx(s); 978191783Srmacklem /* set LEDs and quit */ 979191783Srmacklem return atkbd_ioctl(kbd, KDSETLED, arg); 980191783Srmacklem 981191783Srmacklem case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 982191783Srmacklem splx(s); 983191783Srmacklem if (!KBD_HAS_DEVICE(kbd)) 984191783Srmacklem return 0; 985191783Srmacklem i = typematic(((int *)arg)[0], ((int *)arg)[1]); 986191783Srmacklem return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); 987191783Srmacklem 988191783Srmacklem case KDSETRAD: /* set keyboard repeat rate (old interface) */ 989191783Srmacklem splx(s); 990191783Srmacklem if (!KBD_HAS_DEVICE(kbd)) 991191783Srmacklem return 0; 992191783Srmacklem return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); 993191783Srmacklem 994191783Srmacklem case PIO_KEYMAP: /* set keyboard translation table */ 995191783Srmacklem case PIO_KEYMAPENT: /* set keyboard translation table entry */ 996191783Srmacklem case PIO_DEADKEYMAP: /* set accent key translation table */ 997191783Srmacklem state->ks_accents = 0; 998191783Srmacklem /* FALL THROUGH */ 999191783Srmacklem default: 1000191783Srmacklem splx(s); 1001191783Srmacklem return genkbd_commonioctl(kbd, cmd, arg); 1002191783Srmacklem } 1003191783Srmacklem 1004191783Srmacklem splx(s); 1005191783Srmacklem return 0; 1006191783Srmacklem} 1007191783Srmacklem 1008191783Srmacklem/* lock the access to the keyboard */ 1009191783Srmacklemstatic int 1010191783Srmacklematkbd_lock(keyboard_t *kbd, int lock) 1011191783Srmacklem{ 1012191783Srmacklem return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock); 1013191783Srmacklem} 1014191783Srmacklem 1015191783Srmacklem/* clear the internal state of the keyboard */ 1016191783Srmacklemstatic void 1017191783Srmacklematkbd_clear_state(keyboard_t *kbd) 1018191783Srmacklem{ 1019191783Srmacklem atkbd_state_t *state; 1020191783Srmacklem 1021191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 1022191783Srmacklem state->ks_flags = 0; 1023191783Srmacklem state->ks_polling = 0; 1024191783Srmacklem state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1025191783Srmacklem state->ks_accents = 0; 1026191783Srmacklem state->ks_composed_char = 0; 1027191783Srmacklem#if 0 1028191783Srmacklem state->ks_prefix = 0; /* XXX */ 1029191783Srmacklem#endif 1030191783Srmacklem} 1031191783Srmacklem 1032191783Srmacklem/* save the internal state */ 1033191783Srmacklemstatic int 1034191783Srmacklematkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1035191783Srmacklem{ 1036191783Srmacklem if (len == 0) 1037191783Srmacklem return sizeof(atkbd_state_t); 1038191783Srmacklem if (len < sizeof(atkbd_state_t)) 1039191783Srmacklem return -1; 1040191783Srmacklem bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t)); 1041191783Srmacklem return 0; 1042191783Srmacklem} 1043191783Srmacklem 1044191783Srmacklem/* set the internal state */ 1045191783Srmacklemstatic int 1046191783Srmacklematkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1047191783Srmacklem{ 1048191783Srmacklem if (len < sizeof(atkbd_state_t)) 1049191783Srmacklem return ENOMEM; 1050191783Srmacklem if (((atkbd_state_t *)kbd->kb_data)->kbdc 1051191783Srmacklem != ((atkbd_state_t *)buf)->kbdc) 1052191783Srmacklem return ENOMEM; 1053191783Srmacklem bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t)); 1054191783Srmacklem return 0; 1055191783Srmacklem} 1056191783Srmacklem 1057191783Srmacklemstatic int 1058191783Srmacklematkbd_poll(keyboard_t *kbd, int on) 1059191783Srmacklem{ 1060191783Srmacklem atkbd_state_t *state; 1061191783Srmacklem int s; 1062191783Srmacklem 1063191783Srmacklem state = (atkbd_state_t *)kbd->kb_data; 1064191783Srmacklem s = spltty(); 1065191783Srmacklem if (on) 1066191783Srmacklem ++state->ks_polling; 1067191783Srmacklem else 1068191783Srmacklem --state->ks_polling; 1069191783Srmacklem splx(s); 1070191783Srmacklem return 0; 1071191783Srmacklem} 1072191783Srmacklem 1073191783Srmacklem/* local functions */ 1074191783Srmacklem 1075191783Srmacklemstatic int 1076191783Srmacklemsetup_kbd_port(KBDC kbdc, int port, int intr) 1077191783Srmacklem{ 1078191783Srmacklem if (!set_controller_command_byte(kbdc, 1079191783Srmacklem KBD_KBD_CONTROL_BITS, 1080191783Srmacklem ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) 1081191783Srmacklem | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT))) 1082191783Srmacklem return 1; 1083191783Srmacklem return 0; 1084191783Srmacklem} 1085191783Srmacklem 1086191783Srmacklemstatic int 1087191783Srmacklemget_kbd_echo(KBDC kbdc) 1088191783Srmacklem{ 1089191783Srmacklem /* enable the keyboard port, but disable the keyboard intr. */ 1090191783Srmacklem if (setup_kbd_port(kbdc, TRUE, FALSE)) 1091191783Srmacklem /* CONTROLLER ERROR: there is very little we can do... */ 1092191783Srmacklem return ENXIO; 1093191783Srmacklem 1094191783Srmacklem /* see if something is present */ 1095191783Srmacklem write_kbd_command(kbdc, KBDC_ECHO); 1096191783Srmacklem if (read_kbd_data(kbdc) != KBD_ECHO) { 1097191783Srmacklem empty_both_buffers(kbdc, 10); 1098191783Srmacklem test_controller(kbdc); 1099191783Srmacklem test_kbd_port(kbdc); 1100191783Srmacklem return ENXIO; 1101191783Srmacklem } 1102191783Srmacklem 1103191783Srmacklem /* enable the keyboard port and intr. */ 1104191783Srmacklem if (setup_kbd_port(kbdc, TRUE, TRUE)) { 1105191783Srmacklem /* 1106191783Srmacklem * CONTROLLER ERROR 1107191783Srmacklem * This is serious; the keyboard intr is left disabled! 1108191783Srmacklem */ 1109191783Srmacklem return ENXIO; 1110191783Srmacklem } 1111191783Srmacklem 1112191783Srmacklem return 0; 1113191783Srmacklem} 1114191783Srmacklem 1115191783Srmacklemstatic int 1116191783Srmacklemprobe_keyboard(KBDC kbdc, int flags) 1117191783Srmacklem{ 1118191783Srmacklem /* 1119191783Srmacklem * Don't try to print anything in this function. The low-level 1120191783Srmacklem * console may not have been initialized yet... 1121191783Srmacklem */ 1122191783Srmacklem int err; 1123191783Srmacklem int c; 1124191783Srmacklem int m; 1125191783Srmacklem 1126191783Srmacklem if (!kbdc_lock(kbdc, TRUE)) { 1127191783Srmacklem /* driver error? */ 1128191783Srmacklem return ENXIO; 1129191783Srmacklem } 1130191783Srmacklem 1131191783Srmacklem /* flush any noise in the buffer */ 1132191783Srmacklem empty_both_buffers(kbdc, 10); 1133191783Srmacklem 1134191783Srmacklem /* save the current keyboard controller command byte */ 1135191783Srmacklem m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; 1136191783Srmacklem c = get_controller_command_byte(kbdc); 1137191783Srmacklem if (c == -1) { 1138191783Srmacklem /* CONTROLLER ERROR */ 1139191783Srmacklem kbdc_set_device_mask(kbdc, m); 1140191783Srmacklem kbdc_lock(kbdc, FALSE); 1141191783Srmacklem return ENXIO; 1142191783Srmacklem } 1143191783Srmacklem 1144191783Srmacklem /* 1145191783Srmacklem * The keyboard may have been screwed up by the boot block. 1146191783Srmacklem * We may just be able to recover from error by testing the controller 1147191783Srmacklem * and the keyboard port. The controller command byte needs to be 1148191783Srmacklem * saved before this recovery operation, as some controllers seem 1149191783Srmacklem * to set the command byte to particular values. 1150191783Srmacklem */ 1151191783Srmacklem test_controller(kbdc); 1152191783Srmacklem test_kbd_port(kbdc); 1153191783Srmacklem 1154191783Srmacklem err = get_kbd_echo(kbdc); 1155191783Srmacklem if (err == 0) { 1156191783Srmacklem kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 1157191783Srmacklem } else { 1158191783Srmacklem if (c != -1) 1159191783Srmacklem /* try to restore the command byte as before */ 1160191783Srmacklem set_controller_command_byte(kbdc, 0xff, c); 1161191783Srmacklem kbdc_set_device_mask(kbdc, m); 1162191783Srmacklem } 1163191783Srmacklem 1164191783Srmacklem kbdc_lock(kbdc, FALSE); 1165191783Srmacklem return err; 1166191783Srmacklem} 1167191783Srmacklem 1168191783Srmacklemstatic int 1169191783Srmackleminit_keyboard(KBDC kbdc, int *type, int flags) 1170191783Srmacklem{ 1171191783Srmacklem int codeset; 1172191783Srmacklem int id; 1173191783Srmacklem int c; 1174191783Srmacklem 1175191783Srmacklem if (!kbdc_lock(kbdc, TRUE)) { 1176191783Srmacklem /* driver error? */ 1177191783Srmacklem return EIO; 1178191783Srmacklem } 1179191783Srmacklem 1180191783Srmacklem /* save the current controller command byte */ 1181191783Srmacklem empty_both_buffers(kbdc, 10); 1182191783Srmacklem c = get_controller_command_byte(kbdc); 1183191783Srmacklem if (c == -1) { 1184191783Srmacklem /* CONTROLLER ERROR */ 1185191783Srmacklem kbdc_lock(kbdc, FALSE); 1186191783Srmacklem printf("atkbd: unable to get the current command byte value.\n"); 1187191783Srmacklem return EIO; 1188191783Srmacklem } 1189191783Srmacklem if (bootverbose) 1190191783Srmacklem printf("atkbd: the current kbd controller command byte %04x\n", 1191191783Srmacklem c); 1192191783Srmacklem#if 0 1193191783Srmacklem /* override the keyboard lock switch */ 1194191783Srmacklem c |= KBD_OVERRIDE_KBD_LOCK; 1195191783Srmacklem#endif 1196191783Srmacklem 1197191783Srmacklem /* enable the keyboard port, but disable the keyboard intr. */ 1198191783Srmacklem if (setup_kbd_port(kbdc, TRUE, FALSE)) { 1199191783Srmacklem /* CONTROLLER ERROR: there is very little we can do... */ 1200191783Srmacklem printf("atkbd: unable to set the command byte.\n"); 1201191783Srmacklem kbdc_lock(kbdc, FALSE); 1202191783Srmacklem return EIO; 1203191783Srmacklem } 1204191783Srmacklem 1205191783Srmacklem /* 1206191783Srmacklem * Check if we have an XT keyboard before we attempt to reset it. 1207191783Srmacklem * The procedure assumes that the keyboard and the controller have 1208191783Srmacklem * been set up properly by BIOS and have not been messed up 1209191783Srmacklem * during the boot process. 1210191783Srmacklem */ 1211191783Srmacklem codeset = -1; 1212191783Srmacklem if (flags & KB_CONF_ALT_SCANCODESET) 1213191783Srmacklem /* the user says there is a XT keyboard */ 1214191783Srmacklem codeset = 1; 1215191783Srmacklem#ifdef KBD_DETECT_XT_KEYBOARD 1216191783Srmacklem else if ((c & KBD_TRANSLATION) == 0) { 1217191783Srmacklem /* SET_SCANCODE_SET is not always supported; ignore error */ 1218191783Srmacklem if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0) 1219191783Srmacklem == KBD_ACK) 1220191783Srmacklem codeset = read_kbd_data(kbdc); 1221191783Srmacklem } 1222191783Srmacklem if (bootverbose) 1223191783Srmacklem printf("atkbd: scancode set %d\n", codeset); 1224191783Srmacklem#endif /* KBD_DETECT_XT_KEYBOARD */ 1225191783Srmacklem 1226191783Srmacklem *type = KB_OTHER; 1227191783Srmacklem id = get_kbd_id(kbdc); 1228191783Srmacklem switch(id) { 1229191783Srmacklem case 0x41ab: 1230191783Srmacklem case 0x83ab: 1231191783Srmacklem *type = KB_101; 1232191783Srmacklem break; 1233191783Srmacklem case -1: /* AT 84 keyboard doesn't return ID */ 1234191783Srmacklem *type = KB_84; 1235191783Srmacklem break; 1236191783Srmacklem default: 1237191783Srmacklem break; 1238191783Srmacklem } 1239191783Srmacklem if (bootverbose) 1240191783Srmacklem printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type); 1241191783Srmacklem 1242191783Srmacklem /* reset keyboard hardware */ 1243191783Srmacklem if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { 1244191783Srmacklem /* 1245191783Srmacklem * KEYBOARD ERROR 1246191783Srmacklem * Keyboard reset may fail either because the keyboard 1247191783Srmacklem * doen't exist, or because the keyboard doesn't pass 1248191783Srmacklem * the self-test, or the keyboard controller on the 1249191783Srmacklem * motherboard and the keyboard somehow fail to shake hands. 1250191783Srmacklem * It is just possible, particularly in the last case, 1251191783Srmacklem * that the keyoard controller may be left in a hung state. 1252191783Srmacklem * test_controller() and test_kbd_port() appear to bring 1253191783Srmacklem * the keyboard controller back (I don't know why and how, 1254191783Srmacklem * though.) 1255191783Srmacklem */ 1256191783Srmacklem empty_both_buffers(kbdc, 10); 1257191783Srmacklem test_controller(kbdc); 1258191783Srmacklem test_kbd_port(kbdc); 1259191783Srmacklem /* 1260191783Srmacklem * We could disable the keyboard port and interrupt... but, 1261191783Srmacklem * the keyboard may still exist (see above). 1262191783Srmacklem */ 1263191783Srmacklem set_controller_command_byte(kbdc, 0xff, c); 1264191783Srmacklem kbdc_lock(kbdc, FALSE); 1265191783Srmacklem if (bootverbose) 1266191783Srmacklem printf("atkbd: failed to reset the keyboard.\n"); 1267191990Sattilio return EIO; 1268191783Srmacklem } 1269191783Srmacklem 1270191990Sattilio /* 1271191783Srmacklem * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards 1272191783Srmacklem * such as those on the IBM ThinkPad laptop computers can be used 1273191783Srmacklem * with the standard console driver. 1274191783Srmacklem */ 1275191783Srmacklem if (codeset == 1) { 1276191783Srmacklem if (send_kbd_command_and_data(kbdc, 1277191783Srmacklem KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 1278191783Srmacklem /* XT kbd doesn't need scan code translation */ 1279191783Srmacklem c &= ~KBD_TRANSLATION; 1280199616Srmacklem } else { 1281191783Srmacklem /* 1282191783Srmacklem * KEYBOARD ERROR 1283191783Srmacklem * The XT kbd isn't usable unless the proper scan 1284191783Srmacklem * code set is selected. 1285191783Srmacklem */ 1286191783Srmacklem set_controller_command_byte(kbdc, 0xff, c); 1287191783Srmacklem kbdc_lock(kbdc, FALSE); 1288191783Srmacklem printf("atkbd: unable to set the XT keyboard mode.\n"); 1289191783Srmacklem return EIO; 1290191783Srmacklem } 1291191783Srmacklem } 1292191783Srmacklem 1293191783Srmacklem#ifdef __alpha__ 1294191783Srmacklem if (send_kbd_command_and_data( 1295191783Srmacklem kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) { 1296191783Srmacklem printf("atkbd: can't set translation.\n"); 1297191783Srmacklem 1298191783Srmacklem } 1299191783Srmacklem c |= KBD_TRANSLATION; 1300191783Srmacklem#endif 1301191783Srmacklem 1302199616Srmacklem /* enable the keyboard port and intr. */ 1303199616Srmacklem if (!set_controller_command_byte(kbdc, 1304191783Srmacklem KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 1305191783Srmacklem (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 1306191783Srmacklem | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 1307191783Srmacklem /* 1308191783Srmacklem * CONTROLLER ERROR 1309191783Srmacklem * This is serious; we are left with the disabled 1310191783Srmacklem * keyboard intr. 1311191783Srmacklem */ 1312191783Srmacklem set_controller_command_byte(kbdc, 0xff, c); 1313191783Srmacklem kbdc_lock(kbdc, FALSE); 1314191783Srmacklem printf("atkbd: unable to enable the keyboard port and intr.\n"); 1315191783Srmacklem return EIO; 1316191783Srmacklem } 1317191783Srmacklem 1318191783Srmacklem kbdc_lock(kbdc, FALSE); 1319191783Srmacklem return 0; 1320191783Srmacklem} 1321191783Srmacklem 1322191783Srmacklemstatic int 1323191783Srmacklemwrite_kbd(KBDC kbdc, int command, int data) 1324191783Srmacklem{ 1325191783Srmacklem int s; 1326191783Srmacklem 1327191783Srmacklem /* prevent the timeout routine from polling the keyboard */ 1328191783Srmacklem if (!kbdc_lock(kbdc, TRUE)) 1329200999Srmacklem return EBUSY; 1330200999Srmacklem 1331200999Srmacklem /* disable the keyboard and mouse interrupt */ 1332191783Srmacklem s = spltty(); 1333191783Srmacklem#if 0 1334191783Srmacklem c = get_controller_command_byte(kbdc); 1335191783Srmacklem if ((c == -1) 1336191783Srmacklem || !set_controller_command_byte(kbdc, 1337191783Srmacklem kbdc_get_device_mask(kbdc), 1338191783Srmacklem KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 1339191783Srmacklem | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 1340191783Srmacklem /* CONTROLLER ERROR */ 1341191783Srmacklem kbdc_lock(kbdc, FALSE); 1342191783Srmacklem splx(s); 1343191783Srmacklem return EIO; 1344191783Srmacklem } 1345191783Srmacklem /* 1346191783Srmacklem * Now that the keyboard controller is told not to generate 1347191783Srmacklem * the keyboard and mouse interrupts, call `splx()' to allow 1348191783Srmacklem * the other tty interrupts. The clock interrupt may also occur, 1349191783Srmacklem * but the timeout routine (`scrn_timer()') will be blocked 1350191783Srmacklem * by the lock flag set via `kbdc_lock()' 1351191783Srmacklem */ 1352191783Srmacklem splx(s); 1353191783Srmacklem#endif 1354191783Srmacklem 1355191783Srmacklem if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) 1356191783Srmacklem send_kbd_command(kbdc, KBDC_ENABLE_KBD); 1357191783Srmacklem 1358191783Srmacklem#if 0 1359191783Srmacklem /* restore the interrupts */ 1360191783Srmacklem if (!set_controller_command_byte(kbdc, 1361191783Srmacklem kbdc_get_device_mask(kbdc), 1362191783Srmacklem c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 1363191783Srmacklem /* CONTROLLER ERROR */ 1364191783Srmacklem } 1365191783Srmacklem#else 1366191783Srmacklem splx(s); 1367191783Srmacklem#endif 1368191783Srmacklem kbdc_lock(kbdc, FALSE); 1369191783Srmacklem 1370191783Srmacklem return 0; 1371191783Srmacklem} 1372191783Srmacklem 1373191783Srmacklemstatic int 1374191783Srmacklemget_kbd_id(KBDC kbdc) 1375191783Srmacklem{ 1376191783Srmacklem int id1, id2; 1377191783Srmacklem 1378191783Srmacklem empty_both_buffers(kbdc, 10); 1379191783Srmacklem id1 = id2 = -1; 1380191783Srmacklem if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK) 1381191783Srmacklem return -1; 1382191783Srmacklem 1383191783Srmacklem DELAY(10000); /* 10 msec delay */ 1384191783Srmacklem id1 = read_kbd_data(kbdc); 1385191783Srmacklem if (id1 != -1) 1386191783Srmacklem id2 = read_kbd_data(kbdc); 1387191783Srmacklem 1388191783Srmacklem if ((id1 == -1) || (id2 == -1)) { 1389191783Srmacklem empty_both_buffers(kbdc, 10); 1390191783Srmacklem test_controller(kbdc); 1391191783Srmacklem test_kbd_port(kbdc); 1392191783Srmacklem return -1; 1393191783Srmacklem } 1394191783Srmacklem return ((id2 << 8) | id1); 1395191783Srmacklem} 1396191783Srmacklem 1397191783Srmacklemstatic int 1398191783Srmacklemtypematic(int delay, int rate) 1399191783Srmacklem{ 1400191783Srmacklem static int delays[] = { 250, 500, 750, 1000 }; 1401191783Srmacklem static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 1402191783Srmacklem 68, 76, 84, 92, 100, 110, 118, 126, 1403191783Srmacklem 136, 152, 168, 184, 200, 220, 236, 252, 1404191783Srmacklem 272, 304, 336, 368, 400, 440, 472, 504 }; 1405191783Srmacklem int value; 1406191783Srmacklem int i; 1407191783Srmacklem 1408191783Srmacklem for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { 1409191783Srmacklem if (delay >= delays[i]) 1410191783Srmacklem break; 1411191783Srmacklem } 1412191783Srmacklem value = i << 5; 1413191783Srmacklem for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { 1414191783Srmacklem if (rate >= rates[i]) 1415191783Srmacklem break; 1416191783Srmacklem } 1417191783Srmacklem value |= i; 1418191783Srmacklem return value; 1419191783Srmacklem} 1420191783Srmacklem 1421191783Srmacklem#endif /* NATKBD > 0 */ 1422191783Srmacklem