atkbd.c revision 49820
142421Syokota/*- 242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 342421Syokota * All rights reserved. 442421Syokota * 542421Syokota * Redistribution and use in source and binary forms, with or without 642421Syokota * modification, are permitted provided that the following conditions 742421Syokota * are met: 842421Syokota * 1. Redistributions of source code must retain the above copyright 942421Syokota * notice, this list of conditions and the following disclaimer as 1042421Syokota * the first lines of this file unmodified. 1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright 1242421Syokota * notice, this list of conditions and the following disclaimer in the 1342421Syokota * documentation and/or other materials provided with the distribution. 1442421Syokota * 1542421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1642421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1742421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1842421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1942421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2042421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2142421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2242421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2342421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2442421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2542421Syokota * 2649820Syokota * $Id: atkbd.c,v 1.12 1999/07/18 06:16:25 yokota Exp $ 2742421Syokota */ 2842421Syokota 2942421Syokota#include "atkbd.h" 3042421Syokota#include "opt_kbd.h" 3144628Syokota#include "opt_atkbd.h" 3242421Syokota#include "opt_devfs.h" 3342421Syokota 3442421Syokota#if NATKBD > 0 3542421Syokota 3642421Syokota#include <sys/param.h> 3742421Syokota#include <sys/systm.h> 3842421Syokota#include <sys/kernel.h> 3942421Syokota#include <sys/conf.h> 4047336Syokota#include <sys/bus.h> 4142421Syokota#include <sys/proc.h> 4242421Syokota#include <sys/tty.h> 4342421Syokota#include <sys/fcntl.h> 4442421Syokota#include <sys/malloc.h> 4542421Syokota 4642421Syokota#include <dev/kbd/kbdreg.h> 4742421Syokota#include <dev/kbd/atkbdreg.h> 4842421Syokota#include <dev/kbd/atkbdcreg.h> 4942421Syokota 5042831Syokota#include <isa/isareg.h> 5142831Syokota 5242421Syokota#define ATKBD_SOFTC(unit) \ 5342421Syokota ((atkbd_softc_t *)devclass_get_softc(atkbd_devclass, unit)) 5442421Syokota 5547336Syokotaextern devclass_t atkbd_devclass; 5642421Syokota 5742421Syokotastatic timeout_t atkbd_timeout; 5842421Syokota 5942421Syokota#ifdef KBD_INSTALL_CDEV 6042421Syokota 6142421Syokotastatic d_open_t atkbdopen; 6242421Syokotastatic d_close_t atkbdclose; 6342421Syokotastatic d_read_t atkbdread; 6442421Syokotastatic d_ioctl_t atkbdioctl; 6542421Syokotastatic d_poll_t atkbdpoll; 6642421Syokota 6747625Sphkstatic struct cdevsw atkbd_cdevsw = { 6847625Sphk /* open */ atkbdopen, 6947625Sphk /* close */ atkbdclose, 7047625Sphk /* read */ atkbdread, 7147625Sphk /* write */ nowrite, 7247625Sphk /* ioctl */ atkbdioctl, 7347625Sphk /* stop */ nostop, 7447625Sphk /* reset */ noreset, 7547625Sphk /* devtotty */ nodevtotty, 7647625Sphk /* poll */ atkbdpoll, 7747625Sphk /* mmap */ nommap, 7847625Sphk /* strategy */ nostrategy, 7947625Sphk /* name */ ATKBD_DRIVER_NAME, 8047625Sphk /* parms */ noparms, 8147625Sphk /* maj */ -1, 8247625Sphk /* dump */ nodump, 8347625Sphk /* psize */ nopsize, 8447625Sphk /* flags */ 0, 8547625Sphk /* maxio */ 0, 8647625Sphk /* bmaj */ -1 8742421Syokota}; 8842421Syokota 8942421Syokota#endif /* KBD_INSTALL_CDEV */ 9042421Syokota 9142421Syokotaint 9244628Syokotaatkbd_probe_unit(int unit, int port, int irq, int flags) 9342421Syokota{ 9442421Syokota keyboard_switch_t *sw; 9542421Syokota int args[2]; 9644628Syokota int error; 9742421Syokota 9842421Syokota sw = kbd_get_switch(ATKBD_DRIVER_NAME); 9942421Syokota if (sw == NULL) 10042421Syokota return ENXIO; 10142421Syokota 10242421Syokota args[0] = port; 10342421Syokota args[1] = irq; 10444628Syokota error = (*sw->probe)(unit, args, flags); 10544628Syokota if (error) 10644628Syokota return error; 10744628Syokota return 0; 10842421Syokota} 10942421Syokota 11042421Syokotaint 11144628Syokotaatkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags) 11242421Syokota{ 11342421Syokota keyboard_switch_t *sw; 11444628Syokota int args[2]; 11542421Syokota int error; 11642421Syokota 11742421Syokota if (sc->flags & ATKBD_ATTACHED) 11842421Syokota return 0; 11942421Syokota 12042421Syokota sw = kbd_get_switch(ATKBD_DRIVER_NAME); 12142421Syokota if (sw == NULL) 12242421Syokota return ENXIO; 12342421Syokota 12442421Syokota /* reset, initialize and enable the device */ 12544628Syokota args[0] = port; 12644628Syokota args[1] = irq; 12744628Syokota sc->kbd = NULL; 12844628Syokota error = (*sw->probe)(unit, args, flags); 12942421Syokota if (error) 13044628Syokota return error; 13144628Syokota error = (*sw->init)(unit, &sc->kbd, args, flags); 13244628Syokota if (error) 13344628Syokota return error; 13442421Syokota (*sw->enable)(sc->kbd); 13542421Syokota 13642421Syokota#ifdef KBD_INSTALL_CDEV 13742421Syokota /* attach a virtual keyboard cdev */ 13842421Syokota error = kbd_attach(makedev(0, ATKBD_MKMINOR(unit)), sc->kbd, 13942421Syokota &atkbd_cdevsw); 14042421Syokota if (error) 14142421Syokota return error; 14242421Syokota#endif 14342421Syokota 14442421Syokota /* 14542421Syokota * This is a kludge to compensate for lost keyboard interrupts. 14642421Syokota * A similar code used to be in syscons. See below. XXX 14742421Syokota */ 14842421Syokota atkbd_timeout(sc->kbd); 14942421Syokota 15042421Syokota if (bootverbose) 15142421Syokota (*sw->diag)(sc->kbd, bootverbose); 15242421Syokota 15342421Syokota sc->flags |= ATKBD_ATTACHED; 15442421Syokota return 0; 15542421Syokota} 15642421Syokota 15742421Syokotastatic void 15842421Syokotaatkbd_timeout(void *arg) 15942421Syokota{ 16042421Syokota keyboard_t *kbd; 16142421Syokota int s; 16242421Syokota 16342421Syokota /* The following comments are extracted from syscons.c (1.287) */ 16442421Syokota /* 16542421Syokota * With release 2.1 of the Xaccel server, the keyboard is left 16642421Syokota * hanging pretty often. Apparently an interrupt from the 16742421Syokota * keyboard is lost, and I don't know why (yet). 16842421Syokota * This ugly hack calls scintr if input is ready for the keyboard 16942421Syokota * and conveniently hides the problem. XXX 17042421Syokota */ 17142421Syokota /* 17242421Syokota * Try removing anything stuck in the keyboard controller; whether 17342421Syokota * it's a keyboard scan code or mouse data. `scintr()' doesn't 17442421Syokota * read the mouse data directly, but `kbdio' routines will, as a 17542421Syokota * side effect. 17642421Syokota */ 17742421Syokota s = spltty(); 17842421Syokota kbd = (keyboard_t *)arg; 17942421Syokota if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { 18042421Syokota /* 18142421Syokota * We have seen the lock flag is not set. Let's reset 18242421Syokota * the flag early, otherwise the LED update routine fails 18342421Syokota * which may want the lock during the interrupt routine. 18442421Syokota */ 18542421Syokota (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); 18642421Syokota if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) 18744628Syokota (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 18842421Syokota } 18942421Syokota splx(s); 19042421Syokota timeout(atkbd_timeout, arg, hz/10); 19142421Syokota} 19242421Syokota 19342421Syokota/* cdev driver functions */ 19442421Syokota 19542421Syokota#ifdef KBD_INSTALL_CDEV 19642421Syokota 19742421Syokotastatic int 19842421Syokotaatkbdopen(dev_t dev, int flag, int mode, struct proc *p) 19942421Syokota{ 20042421Syokota atkbd_softc_t *sc; 20142421Syokota 20244628Syokota sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 20344628Syokota if (sc == NULL) 20442421Syokota return ENXIO; 20542421Syokota if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC)) 20642421Syokota return ENODEV; 20742421Syokota 20842421Syokota /* FIXME: set the initial input mode (K_XLATE?) and lock state? */ 20942421Syokota return genkbdopen(&sc->gensc, sc->kbd, flag, mode, p); 21042421Syokota} 21142421Syokota 21242421Syokotastatic int 21342421Syokotaatkbdclose(dev_t dev, int flag, int mode, struct proc *p) 21442421Syokota{ 21542421Syokota atkbd_softc_t *sc; 21642421Syokota 21742421Syokota sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 21842421Syokota return genkbdclose(&sc->gensc, sc->kbd, flag, mode, p); 21942421Syokota} 22042421Syokota 22142421Syokotastatic int 22242421Syokotaatkbdread(dev_t dev, struct uio *uio, int flag) 22342421Syokota{ 22442421Syokota atkbd_softc_t *sc; 22542421Syokota 22642421Syokota sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 22742421Syokota return genkbdread(&sc->gensc, sc->kbd, uio, flag); 22842421Syokota} 22942421Syokota 23042421Syokotastatic int 23142421Syokotaatkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) 23242421Syokota{ 23342421Syokota atkbd_softc_t *sc; 23442421Syokota 23542421Syokota sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 23642421Syokota return genkbdioctl(&sc->gensc, sc->kbd, cmd, arg, flag, p); 23742421Syokota} 23842421Syokota 23942421Syokotastatic int 24042421Syokotaatkbdpoll(dev_t dev, int event, struct proc *p) 24142421Syokota{ 24242421Syokota atkbd_softc_t *sc; 24342421Syokota 24442421Syokota sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); 24542421Syokota return genkbdpoll(&sc->gensc, sc->kbd, event, p); 24642421Syokota} 24742421Syokota 24842421Syokota#endif /* KBD_INSTALL_CDEV */ 24942421Syokota 25042421Syokota/* LOW-LEVEL */ 25142421Syokota 25242421Syokota#include <machine/limits.h> 25342421Syokota#include <machine/console.h> 25442421Syokota#include <machine/clock.h> 25542421Syokota 25642421Syokota#define ATKBD_DEFAULT 0 25742421Syokota 25842421Syokotatypedef struct atkbd_state { 25942421Syokota KBDC kbdc; /* keyboard controller */ 26042421Syokota /* XXX: don't move this field; pcvt 26142421Syokota * expects `kbdc' to be the first 26242421Syokota * field in this structure. */ 26342421Syokota int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 26442421Syokota int ks_flags; /* flags */ 26542421Syokota#define COMPOSE (1 << 0) 26644628Syokota int ks_polling; 26742421Syokota int ks_state; /* shift/lock key state */ 26842421Syokota int ks_accents; /* accent key index (> 0) */ 26942421Syokota u_int ks_composed_char; /* composed char code (> 0) */ 27042421Syokota u_char ks_prefix; /* AT scan code prefix */ 27142421Syokota} atkbd_state_t; 27242421Syokota 27342421Syokota/* keyboard driver declaration */ 27442421Syokotastatic int atkbd_configure(int flags); 27542421Syokotastatic kbd_probe_t atkbd_probe; 27642421Syokotastatic kbd_init_t atkbd_init; 27742421Syokotastatic kbd_term_t atkbd_term; 27842421Syokotastatic kbd_intr_t atkbd_intr; 27942421Syokotastatic kbd_test_if_t atkbd_test_if; 28042421Syokotastatic kbd_enable_t atkbd_enable; 28142421Syokotastatic kbd_disable_t atkbd_disable; 28242421Syokotastatic kbd_read_t atkbd_read; 28342421Syokotastatic kbd_check_t atkbd_check; 28442421Syokotastatic kbd_read_char_t atkbd_read_char; 28542421Syokotastatic kbd_check_char_t atkbd_check_char; 28642421Syokotastatic kbd_ioctl_t atkbd_ioctl; 28742421Syokotastatic kbd_lock_t atkbd_lock; 28842421Syokotastatic kbd_clear_state_t atkbd_clear_state; 28942421Syokotastatic kbd_get_state_t atkbd_get_state; 29042421Syokotastatic kbd_set_state_t atkbd_set_state; 29144628Syokotastatic kbd_poll_mode_t atkbd_poll; 29242421Syokota 29342421Syokotakeyboard_switch_t atkbdsw = { 29442421Syokota atkbd_probe, 29542421Syokota atkbd_init, 29642421Syokota atkbd_term, 29742421Syokota atkbd_intr, 29842421Syokota atkbd_test_if, 29942421Syokota atkbd_enable, 30042421Syokota atkbd_disable, 30142421Syokota atkbd_read, 30242421Syokota atkbd_check, 30342421Syokota atkbd_read_char, 30442421Syokota atkbd_check_char, 30542421Syokota atkbd_ioctl, 30642421Syokota atkbd_lock, 30742421Syokota atkbd_clear_state, 30842421Syokota atkbd_get_state, 30942421Syokota atkbd_set_state, 31042421Syokota genkbd_get_fkeystr, 31144628Syokota atkbd_poll, 31242421Syokota genkbd_diag, 31342421Syokota}; 31442421Syokota 31542421SyokotaKEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); 31642421Syokota 31742421Syokota/* local functions */ 31842421Syokotastatic int setup_kbd_port(KBDC kbdc, int port, int intr); 31942421Syokotastatic int get_kbd_echo(KBDC kbdc); 32042421Syokotastatic int probe_keyboard(KBDC kbdc, int flags); 32142421Syokotastatic int init_keyboard(KBDC kbdc, int *type, int flags); 32242421Syokotastatic int write_kbd(KBDC kbdc, int command, int data); 32342421Syokotastatic int get_kbd_id(KBDC kbdc); 32444628Syokotastatic int typematic(int delay, int rate); 32542421Syokota 32642421Syokota/* local variables */ 32742421Syokota 32842421Syokota/* the initial key map, accent map and fkey strings */ 32944628Syokota#ifdef ATKBD_DFLT_KEYMAP 33044628Syokota#define KBD_DFLT_KEYMAP 33144628Syokota#include "atkbdmap.h" 33244628Syokota#endif 33342831Syokota#include <dev/kbd/kbdtables.h> 33442421Syokota 33542421Syokota/* structures for the default keyboard */ 33642421Syokotastatic keyboard_t default_kbd; 33742421Syokotastatic atkbd_state_t default_kbd_state; 33842421Syokotastatic keymap_t default_keymap; 33942421Syokotastatic accentmap_t default_accentmap; 34042421Syokotastatic fkeytab_t default_fkeytab[NUM_FKEYS]; 34142421Syokota 34242421Syokota/* 34342421Syokota * The back door to the keyboard driver! 34442421Syokota * This function is called by the console driver, via the kbdio module, 34542421Syokota * to tickle keyboard drivers when the low-level console is being initialized. 34642421Syokota * Almost nothing in the kernel has been initialied yet. Try to probe 34742421Syokota * keyboards if possible. 34842421Syokota * NOTE: because of the way the low-level conole is initialized, this routine 34942421Syokota * may be called more than once!! 35042421Syokota */ 35142421Syokotastatic int 35242421Syokotaatkbd_configure(int flags) 35342421Syokota{ 35442421Syokota keyboard_t *kbd; 35542421Syokota int arg[2]; 35644628Syokota int i; 35742421Syokota 35848878Syokota /* probe the keyboard controller */ 35948878Syokota atkbdc_configure(); 36048878Syokota 36146764Syokota /* if the driver is disabled, unregister the keyboard if any */ 36246764Syokota if ((resource_int_value("atkbd", ATKBD_DEFAULT, "disabled", &i) == 0) 36346764Syokota && i != 0) { 36446764Syokota i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT); 36546764Syokota if (i >= 0) { 36646764Syokota kbd = kbd_get_keyboard(i); 36746764Syokota kbd_unregister(kbd); 36846764Syokota kbd->kb_flags &= ~KB_REGISTERED; 36944628Syokota } 37048878Syokota return 0; 37144628Syokota } 37245720Speter 37346764Syokota /* XXX: a kludge to obtain the device configuration flags */ 37446764Syokota if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0) 37546764Syokota flags |= i; 37646764Syokota 37742421Syokota /* probe the default keyboard */ 37842421Syokota arg[0] = -1; 37942421Syokota arg[1] = -1; 38044628Syokota kbd = NULL; 38144628Syokota if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) 38242421Syokota return 0; 38344628Syokota if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) 38444628Syokota return 0; 38542421Syokota 38644628Syokota /* return the number of found keyboards */ 38744628Syokota return 1; 38844628Syokota} 38944628Syokota 39044628Syokota/* low-level functions */ 39144628Syokota 39244628Syokota/* detect a keyboard */ 39344628Syokotastatic int 39444628Syokotaatkbd_probe(int unit, void *arg, int flags) 39544628Syokota{ 39644628Syokota KBDC kbdc; 39744628Syokota int *data = (int *)arg; 39844628Syokota 39944628Syokota /* XXX */ 40044628Syokota if (unit == ATKBD_DEFAULT) { 40144628Syokota if (KBD_IS_PROBED(&default_kbd)) 40242421Syokota return 0; 40342421Syokota } 40442421Syokota 40544628Syokota kbdc = kbdc_open(data[0]); 40644628Syokota if (kbdc == NULL) 40744628Syokota return ENXIO; 40844628Syokota if (probe_keyboard(kbdc, flags)) { 40944628Syokota if (flags & KB_CONF_FAIL_IF_NO_KBD) 41044628Syokota return ENXIO; 41142421Syokota } 41244628Syokota return 0; 41342421Syokota} 41442421Syokota 41544628Syokota/* reset and initialize the device */ 41642421Syokotastatic int 41744628Syokotaatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 41842421Syokota{ 41942421Syokota keyboard_t *kbd; 42042421Syokota atkbd_state_t *state; 42142421Syokota keymap_t *keymap; 42242421Syokota accentmap_t *accmap; 42342421Syokota fkeytab_t *fkeymap; 42442421Syokota int fkeymap_size; 42542421Syokota int *data = (int *)arg; 42642421Syokota 42742421Syokota /* XXX */ 42842421Syokota if (unit == ATKBD_DEFAULT) { 42942421Syokota *kbdp = kbd = &default_kbd; 43044628Syokota if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) 43142421Syokota return 0; 43242421Syokota state = &default_kbd_state; 43342421Syokota keymap = &default_keymap; 43442421Syokota accmap = &default_accentmap; 43542421Syokota fkeymap = default_fkeytab; 43642421Syokota fkeymap_size = 43742421Syokota sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 43842421Syokota } else if (*kbdp == NULL) { 43942421Syokota *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT); 44042421Syokota if (kbd == NULL) 44142421Syokota return ENOMEM; 44242421Syokota bzero(kbd, sizeof(*kbd)); 44342421Syokota state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT); 44442421Syokota keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); 44542421Syokota accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); 44642421Syokota fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); 44742421Syokota fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 44842421Syokota if ((state == NULL) || (keymap == NULL) || (accmap == NULL) 44942421Syokota || (fkeymap == NULL)) { 45042421Syokota if (state != NULL) 45142421Syokota free(state, M_DEVBUF); 45242421Syokota if (keymap != NULL) 45342421Syokota free(keymap, M_DEVBUF); 45442421Syokota if (accmap != NULL) 45542421Syokota free(accmap, M_DEVBUF); 45642421Syokota if (fkeymap != NULL) 45742421Syokota free(fkeymap, M_DEVBUF); 45842421Syokota free(kbd, M_DEVBUF); 45942421Syokota return ENOMEM; 46042421Syokota } 46142421Syokota bzero(state, sizeof(*state)); 46244628Syokota } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 46342421Syokota return 0; 46442421Syokota } else { 46542421Syokota kbd = *kbdp; 46642421Syokota state = (atkbd_state_t *)kbd->kb_data; 46742421Syokota bzero(state, sizeof(*state)); 46842421Syokota keymap = kbd->kb_keymap; 46942421Syokota accmap = kbd->kb_accentmap; 47042421Syokota fkeymap = kbd->kb_fkeytab; 47142421Syokota fkeymap_size = kbd->kb_fkeytab_size; 47242421Syokota } 47342421Syokota 47444628Syokota if (!KBD_IS_PROBED(kbd)) { 47544628Syokota state->kbdc = kbdc_open(data[0]); 47644628Syokota if (state->kbdc == NULL) 47742421Syokota return ENXIO; 47844628Syokota kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 47944628Syokota data[0], IO_KBDSIZE); 48044628Syokota bcopy(&key_map, keymap, sizeof(key_map)); 48144628Syokota bcopy(&accent_map, accmap, sizeof(accent_map)); 48244628Syokota bcopy(fkey_tab, fkeymap, 48344628Syokota imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 48444628Syokota kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 48544628Syokota kbd->kb_data = (void *)state; 48644628Syokota 48744628Syokota if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ 48844628Syokota if (flags & KB_CONF_FAIL_IF_NO_KBD) 48944628Syokota return ENXIO; 49044628Syokota } else { 49144628Syokota KBD_FOUND_DEVICE(kbd); 49244628Syokota } 49344628Syokota atkbd_clear_state(kbd); 49444628Syokota state->ks_mode = K_XLATE; 49544628Syokota /* 49644628Syokota * FIXME: set the initial value for lock keys in ks_state 49744628Syokota * according to the BIOS data? 49844628Syokota */ 49944628Syokota KBD_PROBE_DONE(kbd); 50042421Syokota } 50144628Syokota if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 50249820Syokota kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 50342421Syokota if (KBD_HAS_DEVICE(kbd) 50444628Syokota && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 50544628Syokota && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 50642421Syokota return ENXIO; 50744628Syokota atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 50842421Syokota KBD_INIT_DONE(kbd); 50942421Syokota } 51042421Syokota if (!KBD_IS_CONFIGURED(kbd)) { 51142421Syokota if (kbd_register(kbd) < 0) 51242421Syokota return ENXIO; 51342421Syokota KBD_CONFIG_DONE(kbd); 51442421Syokota } 51542421Syokota 51642421Syokota return 0; 51742421Syokota} 51842421Syokota 51942421Syokota/* finish using this keyboard */ 52042421Syokotastatic int 52142421Syokotaatkbd_term(keyboard_t *kbd) 52242421Syokota{ 52342421Syokota kbd_unregister(kbd); 52442421Syokota return 0; 52542421Syokota} 52642421Syokota 52742421Syokota/* keyboard interrupt routine */ 52842421Syokotastatic int 52944628Syokotaatkbd_intr(keyboard_t *kbd, void *arg) 53042421Syokota{ 53142421Syokota atkbd_state_t *state; 53242421Syokota int c; 53342421Syokota 53442421Syokota if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 53542421Syokota /* let the callback function to process the input */ 53642421Syokota (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 53742421Syokota kbd->kb_callback.kc_arg); 53842421Syokota } else { 53942421Syokota /* read and discard the input; no one is waiting for input */ 54042421Syokota do { 54142421Syokota c = atkbd_read_char(kbd, FALSE); 54242421Syokota } while (c != NOKEY); 54342421Syokota 54442421Syokota if (!KBD_HAS_DEVICE(kbd)) { 54542421Syokota /* 54642421Syokota * The keyboard was not detected before; 54742421Syokota * it must have been reconnected! 54842421Syokota */ 54942421Syokota state = (atkbd_state_t *)kbd->kb_data; 55042421Syokota init_keyboard(state->kbdc, &kbd->kb_type, 55142421Syokota kbd->kb_config); 55242421Syokota atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 55342421Syokota KBD_FOUND_DEVICE(kbd); 55442421Syokota } 55542421Syokota } 55642421Syokota return 0; 55742421Syokota} 55842421Syokota 55942421Syokota/* test the interface to the device */ 56042421Syokotastatic int 56142421Syokotaatkbd_test_if(keyboard_t *kbd) 56242421Syokota{ 56342421Syokota int error; 56442421Syokota int s; 56542421Syokota 56642421Syokota error = 0; 56742421Syokota empty_both_buffers(((atkbd_state_t *)kbd->kb_data)->kbdc, 10); 56842421Syokota s = spltty(); 56942421Syokota if (!test_controller(((atkbd_state_t *)kbd->kb_data)->kbdc)) 57042421Syokota error = EIO; 57142421Syokota else if (test_kbd_port(((atkbd_state_t *)kbd->kb_data)->kbdc) != 0) 57242421Syokota error = EIO; 57342421Syokota splx(s); 57442421Syokota 57542421Syokota return error; 57642421Syokota} 57742421Syokota 57842421Syokota/* 57942421Syokota * Enable the access to the device; until this function is called, 58042421Syokota * the client cannot read from the keyboard. 58142421Syokota */ 58242421Syokotastatic int 58342421Syokotaatkbd_enable(keyboard_t *kbd) 58442421Syokota{ 58542421Syokota int s; 58642421Syokota 58742421Syokota s = spltty(); 58842421Syokota KBD_ACTIVATE(kbd); 58942421Syokota splx(s); 59042421Syokota return 0; 59142421Syokota} 59242421Syokota 59342421Syokota/* disallow the access to the device */ 59442421Syokotastatic int 59542421Syokotaatkbd_disable(keyboard_t *kbd) 59642421Syokota{ 59742421Syokota int s; 59842421Syokota 59942421Syokota s = spltty(); 60042421Syokota KBD_DEACTIVATE(kbd); 60142421Syokota splx(s); 60242421Syokota return 0; 60342421Syokota} 60442421Syokota 60542421Syokota/* read one byte from the keyboard if it's allowed */ 60642421Syokotastatic int 60742421Syokotaatkbd_read(keyboard_t *kbd, int wait) 60842421Syokota{ 60942421Syokota int c; 61042421Syokota 61142421Syokota if (wait) 61242421Syokota c = read_kbd_data(((atkbd_state_t *)kbd->kb_data)->kbdc); 61342421Syokota else 61442421Syokota c = read_kbd_data_no_wait(((atkbd_state_t *)kbd->kb_data)->kbdc); 61542421Syokota return (KBD_IS_ACTIVE(kbd) ? c : -1); 61642421Syokota} 61742421Syokota 61842421Syokota/* check if data is waiting */ 61942421Syokotastatic int 62042421Syokotaatkbd_check(keyboard_t *kbd) 62142421Syokota{ 62242421Syokota if (!KBD_IS_ACTIVE(kbd)) 62342421Syokota return FALSE; 62442421Syokota return kbdc_data_ready(((atkbd_state_t *)kbd->kb_data)->kbdc); 62542421Syokota} 62642421Syokota 62742421Syokota/* read char from the keyboard */ 62842421Syokotastatic u_int 62942421Syokotaatkbd_read_char(keyboard_t *kbd, int wait) 63042421Syokota{ 63142421Syokota atkbd_state_t *state; 63242421Syokota u_int action; 63342421Syokota int scancode; 63442421Syokota int keycode; 63542421Syokota 63642421Syokota state = (atkbd_state_t *)kbd->kb_data; 63742421Syokotanext_code: 63842421Syokota /* do we have a composed char to return? */ 63942421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 64042421Syokota action = state->ks_composed_char; 64142421Syokota state->ks_composed_char = 0; 64242421Syokota if (action > UCHAR_MAX) 64342421Syokota return ERRKEY; 64442421Syokota return action; 64542421Syokota } 64642421Syokota 64742421Syokota /* see if there is something in the keyboard port */ 64842421Syokota if (wait) { 64942421Syokota do { 65042421Syokota scancode = read_kbd_data(state->kbdc); 65142421Syokota } while (scancode == -1); 65242421Syokota } else { 65342421Syokota scancode = read_kbd_data_no_wait(state->kbdc); 65442421Syokota if (scancode == -1) 65542421Syokota return NOKEY; 65642421Syokota } 65742421Syokota 65842421Syokota /* return the byte as is for the K_RAW mode */ 65942421Syokota if (state->ks_mode == K_RAW) 66042421Syokota return scancode; 66142421Syokota 66242421Syokota /* translate the scan code into a keycode */ 66342421Syokota keycode = scancode & 0x7F; 66442421Syokota switch (state->ks_prefix) { 66542421Syokota case 0x00: /* normal scancode */ 66642421Syokota switch(scancode) { 66742421Syokota case 0xB8: /* left alt (compose key) released */ 66842421Syokota if (state->ks_flags & COMPOSE) { 66942421Syokota state->ks_flags &= ~COMPOSE; 67042421Syokota if (state->ks_composed_char > UCHAR_MAX) 67142421Syokota state->ks_composed_char = 0; 67242421Syokota } 67342421Syokota break; 67442421Syokota case 0x38: /* left alt (compose key) pressed */ 67542421Syokota if (!(state->ks_flags & COMPOSE)) { 67642421Syokota state->ks_flags |= COMPOSE; 67742421Syokota state->ks_composed_char = 0; 67842421Syokota } 67942421Syokota break; 68042421Syokota case 0xE0: 68142421Syokota case 0xE1: 68242421Syokota state->ks_prefix = scancode; 68342421Syokota goto next_code; 68442421Syokota } 68542421Syokota break; 68642421Syokota case 0xE0: /* 0xE0 prefix */ 68742421Syokota state->ks_prefix = 0; 68842421Syokota switch (keycode) { 68942421Syokota case 0x1C: /* right enter key */ 69042421Syokota keycode = 0x59; 69142421Syokota break; 69242421Syokota case 0x1D: /* right ctrl key */ 69342421Syokota keycode = 0x5A; 69442421Syokota break; 69542421Syokota case 0x35: /* keypad divide key */ 69642421Syokota keycode = 0x5B; 69742421Syokota break; 69842421Syokota case 0x37: /* print scrn key */ 69942421Syokota keycode = 0x5C; 70042421Syokota break; 70142421Syokota case 0x38: /* right alt key (alt gr) */ 70242421Syokota keycode = 0x5D; 70342421Syokota break; 70443337Syokota case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 70543337Syokota keycode = 0x68; 70643337Syokota break; 70742421Syokota case 0x47: /* grey home key */ 70842421Syokota keycode = 0x5E; 70942421Syokota break; 71042421Syokota case 0x48: /* grey up arrow key */ 71142421Syokota keycode = 0x5F; 71242421Syokota break; 71342421Syokota case 0x49: /* grey page up key */ 71442421Syokota keycode = 0x60; 71542421Syokota break; 71642421Syokota case 0x4B: /* grey left arrow key */ 71742421Syokota keycode = 0x61; 71842421Syokota break; 71942421Syokota case 0x4D: /* grey right arrow key */ 72042421Syokota keycode = 0x62; 72142421Syokota break; 72242421Syokota case 0x4F: /* grey end key */ 72342421Syokota keycode = 0x63; 72442421Syokota break; 72542421Syokota case 0x50: /* grey down arrow key */ 72642421Syokota keycode = 0x64; 72742421Syokota break; 72842421Syokota case 0x51: /* grey page down key */ 72942421Syokota keycode = 0x65; 73042421Syokota break; 73142421Syokota case 0x52: /* grey insert key */ 73242421Syokota keycode = 0x66; 73342421Syokota break; 73442421Syokota case 0x53: /* grey delete key */ 73542421Syokota keycode = 0x67; 73642421Syokota break; 73742421Syokota /* the following 3 are only used on the MS "Natural" keyboard */ 73842421Syokota case 0x5b: /* left Window key */ 73942421Syokota keycode = 0x69; 74042421Syokota break; 74142421Syokota case 0x5c: /* right Window key */ 74242421Syokota keycode = 0x6a; 74342421Syokota break; 74442421Syokota case 0x5d: /* menu key */ 74542421Syokota keycode = 0x6b; 74642421Syokota break; 74742421Syokota default: /* ignore everything else */ 74842421Syokota goto next_code; 74942421Syokota } 75042421Syokota break; 75142421Syokota case 0xE1: /* 0xE1 prefix */ 75243337Syokota /* 75343337Syokota * The pause/break key on the 101 keyboard produces: 75443337Syokota * E1-1D-45 E1-9D-C5 75543337Syokota * Ctrl-pause/break produces: 75643337Syokota * E0-46 E0-C6 (See above.) 75743337Syokota */ 75842421Syokota state->ks_prefix = 0; 75942421Syokota if (keycode == 0x1D) 76042421Syokota state->ks_prefix = 0x1D; 76142421Syokota goto next_code; 76242421Syokota /* NOT REACHED */ 76342421Syokota case 0x1D: /* pause / break */ 76442421Syokota state->ks_prefix = 0; 76542421Syokota if (keycode != 0x45) 76643337Syokota goto next_code; 76742421Syokota keycode = 0x68; 76842421Syokota break; 76942421Syokota } 77042421Syokota 77143337Syokota if (kbd->kb_type == KB_84) { 77243337Syokota switch (keycode) { 77343337Syokota case 0x37: /* *(numpad)/print screen */ 77443337Syokota if (state->ks_flags & SHIFTS) 77543337Syokota keycode = 0x5c; /* print screen */ 77643337Syokota break; 77743337Syokota case 0x45: /* num lock/pause */ 77843337Syokota if (state->ks_flags & CTLS) 77943337Syokota keycode = 0x68; /* pause */ 78043337Syokota break; 78143337Syokota case 0x46: /* scroll lock/break */ 78243337Syokota if (state->ks_flags & CTLS) 78343337Syokota keycode = 0x6c; /* break */ 78443337Syokota break; 78543337Syokota } 78643337Syokota } else if (kbd->kb_type == KB_101) { 78743337Syokota switch (keycode) { 78843337Syokota case 0x5c: /* print screen */ 78943337Syokota if (state->ks_flags & ALTS) 79043337Syokota keycode = 0x54; /* sysrq */ 79143337Syokota break; 79243337Syokota case 0x68: /* pause/break */ 79343337Syokota if (state->ks_flags & CTLS) 79443337Syokota keycode = 0x6c; /* break */ 79543337Syokota break; 79643337Syokota } 79743337Syokota } 79843337Syokota 79942421Syokota /* return the key code in the K_CODE mode */ 80042421Syokota if (state->ks_mode == K_CODE) 80142421Syokota return (keycode | (scancode & 0x80)); 80242421Syokota 80342421Syokota /* compose a character code */ 80442421Syokota if (state->ks_flags & COMPOSE) { 80547293Syokota switch (keycode | (scancode & 0x80)) { 80642421Syokota /* key pressed, process it */ 80742421Syokota case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 80842421Syokota state->ks_composed_char *= 10; 80946765Syokota state->ks_composed_char += keycode - 0x40; 81042421Syokota if (state->ks_composed_char > UCHAR_MAX) 81142421Syokota return ERRKEY; 81242421Syokota goto next_code; 81342421Syokota case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 81442421Syokota state->ks_composed_char *= 10; 81546765Syokota state->ks_composed_char += keycode - 0x47; 81642421Syokota if (state->ks_composed_char > UCHAR_MAX) 81742421Syokota return ERRKEY; 81842421Syokota goto next_code; 81942421Syokota case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 82042421Syokota state->ks_composed_char *= 10; 82146765Syokota state->ks_composed_char += keycode - 0x4E; 82242421Syokota if (state->ks_composed_char > UCHAR_MAX) 82342421Syokota return ERRKEY; 82442421Syokota goto next_code; 82542421Syokota case 0x52: /* keypad 0 */ 82642421Syokota state->ks_composed_char *= 10; 82742421Syokota if (state->ks_composed_char > UCHAR_MAX) 82842421Syokota return ERRKEY; 82942421Syokota goto next_code; 83042421Syokota 83142421Syokota /* key released, no interest here */ 83242421Syokota case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 83342421Syokota case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 83442421Syokota case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 83542421Syokota case 0xD2: /* keypad 0 */ 83642421Syokota goto next_code; 83742421Syokota 83842421Syokota case 0x38: /* left alt key */ 83942421Syokota break; 84042421Syokota 84142421Syokota default: 84242421Syokota if (state->ks_composed_char > 0) { 84342421Syokota state->ks_flags &= ~COMPOSE; 84442421Syokota state->ks_composed_char = 0; 84542421Syokota return ERRKEY; 84642421Syokota } 84742421Syokota break; 84842421Syokota } 84942421Syokota } 85042421Syokota 85142421Syokota /* keycode to key action */ 85242421Syokota action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 85342421Syokota &state->ks_state, &state->ks_accents); 85442421Syokota if (action == NOKEY) 85542421Syokota goto next_code; 85642421Syokota else 85742421Syokota return action; 85842421Syokota} 85942421Syokota 86042421Syokota/* check if char is waiting */ 86142421Syokotastatic int 86242421Syokotaatkbd_check_char(keyboard_t *kbd) 86342421Syokota{ 86442421Syokota atkbd_state_t *state; 86542421Syokota 86642421Syokota if (!KBD_IS_ACTIVE(kbd)) 86742421Syokota return FALSE; 86842421Syokota state = (atkbd_state_t *)kbd->kb_data; 86942421Syokota if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 87042421Syokota return TRUE; 87142421Syokota return kbdc_data_ready(state->kbdc); 87242421Syokota} 87342421Syokota 87442421Syokota/* some useful control functions */ 87542421Syokotastatic int 87642421Syokotaatkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 87742421Syokota{ 87842421Syokota /* trasnlate LED_XXX bits into the device specific bits */ 87942421Syokota static u_char ledmap[8] = { 88042421Syokota 0, 4, 2, 6, 1, 5, 3, 7, 88142421Syokota }; 88242421Syokota atkbd_state_t *state = kbd->kb_data; 88342421Syokota int error; 88442421Syokota int s; 88542421Syokota int i; 88642421Syokota 88742421Syokota s = spltty(); 88842421Syokota switch (cmd) { 88942421Syokota 89042421Syokota case KDGKBMODE: /* get keyboard mode */ 89142421Syokota *(int *)arg = state->ks_mode; 89242421Syokota break; 89342421Syokota case KDSKBMODE: /* set keyboard mode */ 89442421Syokota switch (*(int *)arg) { 89542421Syokota case K_XLATE: 89642421Syokota if (state->ks_mode != K_XLATE) { 89742421Syokota /* make lock key state and LED state match */ 89842421Syokota state->ks_state &= ~LOCK_MASK; 89942421Syokota state->ks_state |= KBD_LED_VAL(kbd); 90042421Syokota } 90142421Syokota /* FALL THROUGH */ 90242421Syokota case K_RAW: 90342421Syokota case K_CODE: 90442421Syokota if (state->ks_mode != *(int *)arg) { 90542421Syokota atkbd_clear_state(kbd); 90642421Syokota state->ks_mode = *(int *)arg; 90742421Syokota } 90842421Syokota break; 90942421Syokota default: 91042421Syokota splx(s); 91142421Syokota return EINVAL; 91242421Syokota } 91342421Syokota break; 91442421Syokota 91542421Syokota case KDGETLED: /* get keyboard LED */ 91642421Syokota *(int *)arg = KBD_LED_VAL(kbd); 91742421Syokota break; 91842421Syokota case KDSETLED: /* set keyboard LED */ 91942421Syokota /* NOTE: lock key state in ks_state won't be changed */ 92042421Syokota if (*(int *)arg & ~LOCK_MASK) { 92142421Syokota splx(s); 92242421Syokota return EINVAL; 92342421Syokota } 92442421Syokota i = *(int *)arg; 92542421Syokota /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 92642421Syokota if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 92742421Syokota if (i & ALKED) 92842421Syokota i |= CLKED; 92942421Syokota else 93042421Syokota i &= ~CLKED; 93142421Syokota } 93242421Syokota if (KBD_HAS_DEVICE(kbd)) { 93342421Syokota error = write_kbd(state->kbdc, KBDC_SET_LEDS, 93442421Syokota ledmap[i & LED_MASK]); 93542421Syokota if (error) { 93642421Syokota splx(s); 93742421Syokota return error; 93842421Syokota } 93942421Syokota } 94042421Syokota KBD_LED_VAL(kbd) = *(int *)arg; 94142421Syokota break; 94242421Syokota 94342421Syokota case KDGKBSTATE: /* get lock key state */ 94442421Syokota *(int *)arg = state->ks_state & LOCK_MASK; 94542421Syokota break; 94642421Syokota case KDSKBSTATE: /* set lock key state */ 94742421Syokota if (*(int *)arg & ~LOCK_MASK) { 94842421Syokota splx(s); 94942421Syokota return EINVAL; 95042421Syokota } 95142421Syokota state->ks_state &= ~LOCK_MASK; 95242421Syokota state->ks_state |= *(int *)arg; 95342421Syokota splx(s); 95442421Syokota /* set LEDs and quit */ 95542421Syokota return atkbd_ioctl(kbd, KDSETLED, arg); 95642421Syokota 95744628Syokota case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 95842421Syokota splx(s); 95942421Syokota if (!KBD_HAS_DEVICE(kbd)) 96042421Syokota return 0; 96144628Syokota i = typematic(((int *)arg)[0], ((int *)arg)[1]); 96244628Syokota return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); 96342421Syokota 96444628Syokota case KDSETRAD: /* set keyboard repeat rate (old interface) */ 96544628Syokota splx(s); 96644628Syokota if (!KBD_HAS_DEVICE(kbd)) 96744628Syokota return 0; 96844628Syokota return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); 96944628Syokota 97042421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 97142421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 97242421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 97342421Syokota state->ks_accents = 0; 97442421Syokota /* FALL THROUGH */ 97542421Syokota default: 97642421Syokota splx(s); 97742421Syokota return genkbd_commonioctl(kbd, cmd, arg); 97842421Syokota } 97942421Syokota 98042421Syokota splx(s); 98142421Syokota return 0; 98242421Syokota} 98342421Syokota 98442421Syokota/* lock the access to the keyboard */ 98542421Syokotastatic int 98642421Syokotaatkbd_lock(keyboard_t *kbd, int lock) 98742421Syokota{ 98842421Syokota return kbdc_lock(((atkbd_state_t *)kbd->kb_data)->kbdc, lock); 98942421Syokota} 99042421Syokota 99142421Syokota/* clear the internal state of the keyboard */ 99242421Syokotastatic void 99342421Syokotaatkbd_clear_state(keyboard_t *kbd) 99442421Syokota{ 99542421Syokota atkbd_state_t *state; 99642421Syokota 99742421Syokota state = (atkbd_state_t *)kbd->kb_data; 99842421Syokota state->ks_flags = 0; 99944628Syokota state->ks_polling = 0; 100042421Syokota state->ks_state &= LOCK_MASK; /* preserve locking key state */ 100142421Syokota state->ks_accents = 0; 100242421Syokota state->ks_composed_char = 0; 100342421Syokota#if 0 100442421Syokota state->ks_prefix = 0; /* XXX */ 100542421Syokota#endif 100642421Syokota} 100742421Syokota 100842421Syokota/* save the internal state */ 100942421Syokotastatic int 101042421Syokotaatkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 101142421Syokota{ 101242421Syokota if (len == 0) 101342421Syokota return sizeof(atkbd_state_t); 101442421Syokota if (len < sizeof(atkbd_state_t)) 101542421Syokota return -1; 101642421Syokota bcopy(kbd->kb_data, buf, sizeof(atkbd_state_t)); 101742421Syokota return 0; 101842421Syokota} 101942421Syokota 102042421Syokota/* set the internal state */ 102142421Syokotastatic int 102242421Syokotaatkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 102342421Syokota{ 102442421Syokota if (len < sizeof(atkbd_state_t)) 102542421Syokota return ENOMEM; 102642421Syokota if (((atkbd_state_t *)kbd->kb_data)->kbdc 102742421Syokota != ((atkbd_state_t *)buf)->kbdc) 102842421Syokota return ENOMEM; 102942421Syokota bcopy(buf, kbd->kb_data, sizeof(atkbd_state_t)); 103042421Syokota return 0; 103142421Syokota} 103242421Syokota 103344628Syokotastatic int 103444628Syokotaatkbd_poll(keyboard_t *kbd, int on) 103544628Syokota{ 103644628Syokota atkbd_state_t *state; 103744628Syokota int s; 103844628Syokota 103944628Syokota state = (atkbd_state_t *)kbd->kb_data; 104044628Syokota s = spltty(); 104144628Syokota if (on) 104244628Syokota ++state->ks_polling; 104344628Syokota else 104444628Syokota --state->ks_polling; 104544628Syokota splx(s); 104644628Syokota return 0; 104744628Syokota} 104844628Syokota 104942421Syokota/* local functions */ 105042421Syokota 105142421Syokotastatic int 105242421Syokotasetup_kbd_port(KBDC kbdc, int port, int intr) 105342421Syokota{ 105442421Syokota if (!set_controller_command_byte(kbdc, 105542421Syokota KBD_KBD_CONTROL_BITS, 105642421Syokota ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) 105742421Syokota | ((intr) ? KBD_ENABLE_KBD_INT : KBD_DISABLE_KBD_INT))) 105842421Syokota return 1; 105942421Syokota return 0; 106042421Syokota} 106142421Syokota 106242421Syokotastatic int 106342421Syokotaget_kbd_echo(KBDC kbdc) 106442421Syokota{ 106542421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 106642421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) 106742421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 106842421Syokota return ENXIO; 106942421Syokota 107042421Syokota /* see if something is present */ 107142421Syokota write_kbd_command(kbdc, KBDC_ECHO); 107242421Syokota if (read_kbd_data(kbdc) != KBD_ECHO) { 107342421Syokota empty_both_buffers(kbdc, 10); 107442421Syokota test_controller(kbdc); 107542421Syokota test_kbd_port(kbdc); 107642421Syokota return ENXIO; 107742421Syokota } 107842421Syokota 107942421Syokota /* enable the keyboard port and intr. */ 108042421Syokota if (setup_kbd_port(kbdc, TRUE, TRUE)) { 108142421Syokota /* 108242421Syokota * CONTROLLER ERROR 108342421Syokota * This is serious; the keyboard intr is left disabled! 108442421Syokota */ 108542421Syokota return ENXIO; 108642421Syokota } 108742421Syokota 108842421Syokota return 0; 108942421Syokota} 109042421Syokota 109142421Syokotastatic int 109242421Syokotaprobe_keyboard(KBDC kbdc, int flags) 109342421Syokota{ 109442421Syokota /* 109542421Syokota * Don't try to print anything in this function. The low-level 109642421Syokota * console may not have been initialized yet... 109742421Syokota */ 109842421Syokota int err; 109942421Syokota int c; 110042421Syokota int m; 110142421Syokota 110242421Syokota if (!kbdc_lock(kbdc, TRUE)) { 110342421Syokota /* driver error? */ 110442421Syokota return ENXIO; 110542421Syokota } 110642421Syokota 110742421Syokota /* flush any noise in the buffer */ 110842421Syokota empty_both_buffers(kbdc, 10); 110942421Syokota 111042421Syokota /* save the current keyboard controller command byte */ 111142421Syokota m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS; 111242421Syokota c = get_controller_command_byte(kbdc); 111342421Syokota if (c == -1) { 111442421Syokota /* CONTROLLER ERROR */ 111542421Syokota kbdc_set_device_mask(kbdc, m); 111642421Syokota kbdc_lock(kbdc, FALSE); 111742421Syokota return ENXIO; 111842421Syokota } 111942421Syokota 112042421Syokota /* 112142421Syokota * The keyboard may have been screwed up by the boot block. 112242421Syokota * We may just be able to recover from error by testing the controller 112342421Syokota * and the keyboard port. The controller command byte needs to be 112442421Syokota * saved before this recovery operation, as some controllers seem 112542421Syokota * to set the command byte to particular values. 112642421Syokota */ 112742421Syokota test_controller(kbdc); 112842421Syokota test_kbd_port(kbdc); 112942421Syokota 113042421Syokota err = get_kbd_echo(kbdc); 113142421Syokota if (err == 0) { 113242421Syokota kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS); 113342421Syokota } else { 113442421Syokota if (c != -1) 113542421Syokota /* try to restore the command byte as before */ 113642421Syokota set_controller_command_byte(kbdc, 0xff, c); 113742421Syokota kbdc_set_device_mask(kbdc, m); 113842421Syokota } 113942421Syokota 114042421Syokota kbdc_lock(kbdc, FALSE); 114142421Syokota return err; 114242421Syokota} 114342421Syokota 114442421Syokotastatic int 114542421Syokotainit_keyboard(KBDC kbdc, int *type, int flags) 114642421Syokota{ 114742421Syokota int codeset; 114842421Syokota int id; 114942421Syokota int c; 115042421Syokota 115142421Syokota if (!kbdc_lock(kbdc, TRUE)) { 115242421Syokota /* driver error? */ 115342421Syokota return EIO; 115442421Syokota } 115542421Syokota 115642421Syokota /* save the current controller command byte */ 115742421Syokota empty_both_buffers(kbdc, 10); 115842421Syokota c = get_controller_command_byte(kbdc); 115942421Syokota if (c == -1) { 116042421Syokota /* CONTROLLER ERROR */ 116142421Syokota kbdc_lock(kbdc, FALSE); 116242421Syokota printf("atkbd: unable to get the current command byte value.\n"); 116342421Syokota return EIO; 116442421Syokota } 116542421Syokota if (bootverbose) 116642421Syokota printf("atkbd: the current kbd controller command byte %04x\n", 116742421Syokota c); 116842421Syokota#if 0 116942421Syokota /* override the keyboard lock switch */ 117042421Syokota c |= KBD_OVERRIDE_KBD_LOCK; 117142421Syokota#endif 117242421Syokota 117342421Syokota /* enable the keyboard port, but disable the keyboard intr. */ 117442421Syokota if (setup_kbd_port(kbdc, TRUE, FALSE)) { 117542421Syokota /* CONTROLLER ERROR: there is very little we can do... */ 117642421Syokota printf("atkbd: unable to set the command byte.\n"); 117742421Syokota kbdc_lock(kbdc, FALSE); 117842421Syokota return EIO; 117942421Syokota } 118042421Syokota 118142421Syokota /* 118242421Syokota * Check if we have an XT keyboard before we attempt to reset it. 118342421Syokota * The procedure assumes that the keyboard and the controller have 118442421Syokota * been set up properly by BIOS and have not been messed up 118542421Syokota * during the boot process. 118642421Syokota */ 118742421Syokota codeset = -1; 118842421Syokota if (flags & KB_CONF_ALT_SCANCODESET) 118942421Syokota /* the user says there is a XT keyboard */ 119042421Syokota codeset = 1; 119142421Syokota#ifdef KBD_DETECT_XT_KEYBOARD 119242421Syokota else if ((c & KBD_TRANSLATION) == 0) { 119342421Syokota /* SET_SCANCODE_SET is not always supported; ignore error */ 119442421Syokota if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0) 119542421Syokota == KBD_ACK) 119642421Syokota codeset = read_kbd_data(kbdc); 119742421Syokota } 119842421Syokota if (bootverbose) 119942421Syokota printf("atkbd: scancode set %d\n", codeset); 120042421Syokota#endif /* KBD_DETECT_XT_KEYBOARD */ 120142421Syokota 120242421Syokota *type = KB_OTHER; 120342421Syokota id = get_kbd_id(kbdc); 120442421Syokota switch(id) { 120542421Syokota case 0x41ab: 120642421Syokota case 0x83ab: 120742421Syokota *type = KB_101; 120842421Syokota break; 120942421Syokota case -1: /* AT 84 keyboard doesn't return ID */ 121042421Syokota *type = KB_84; 121142421Syokota break; 121242421Syokota default: 121342421Syokota break; 121442421Syokota } 121542421Syokota if (bootverbose) 121642421Syokota printf("atkbd: keyboard ID 0x%x (%d)\n", id, *type); 121742421Syokota 121842421Syokota /* reset keyboard hardware */ 121942421Syokota if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { 122042421Syokota /* 122142421Syokota * KEYBOARD ERROR 122242421Syokota * Keyboard reset may fail either because the keyboard 122342421Syokota * doen't exist, or because the keyboard doesn't pass 122442421Syokota * the self-test, or the keyboard controller on the 122542421Syokota * motherboard and the keyboard somehow fail to shake hands. 122642421Syokota * It is just possible, particularly in the last case, 122742421Syokota * that the keyoard controller may be left in a hung state. 122842421Syokota * test_controller() and test_kbd_port() appear to bring 122942421Syokota * the keyboard controller back (I don't know why and how, 123042421Syokota * though.) 123142421Syokota */ 123242421Syokota empty_both_buffers(kbdc, 10); 123342421Syokota test_controller(kbdc); 123442421Syokota test_kbd_port(kbdc); 123542421Syokota /* 123642421Syokota * We could disable the keyboard port and interrupt... but, 123742421Syokota * the keyboard may still exist (see above). 123842421Syokota */ 123942421Syokota set_controller_command_byte(kbdc, 0xff, c); 124042421Syokota kbdc_lock(kbdc, FALSE); 124142421Syokota if (bootverbose) 124242421Syokota printf("atkbd: failed to reset the keyboard.\n"); 124342421Syokota return EIO; 124442421Syokota } 124542421Syokota 124642421Syokota /* 124742421Syokota * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards 124842421Syokota * such as those on the IBM ThinkPad laptop computers can be used 124942421Syokota * with the standard console driver. 125042421Syokota */ 125142421Syokota if (codeset == 1) { 125242421Syokota if (send_kbd_command_and_data(kbdc, 125342421Syokota KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) { 125442421Syokota /* XT kbd doesn't need scan code translation */ 125542421Syokota c &= ~KBD_TRANSLATION; 125642421Syokota } else { 125742421Syokota /* 125842421Syokota * KEYBOARD ERROR 125942421Syokota * The XT kbd isn't usable unless the proper scan 126042421Syokota * code set is selected. 126142421Syokota */ 126242421Syokota set_controller_command_byte(kbdc, 0xff, c); 126342421Syokota kbdc_lock(kbdc, FALSE); 126442421Syokota printf("atkbd: unable to set the XT keyboard mode.\n"); 126542421Syokota return EIO; 126642421Syokota } 126742421Syokota } 126842421Syokota 126942831Syokota#ifdef __alpha__ 127042831Syokota if (send_kbd_command_and_data( 127142831Syokota kbdc, KBDC_SET_SCANCODE_SET, 2) != KBD_ACK) { 127242831Syokota printf("atkbd: can't set translation.\n"); 127342831Syokota 127442831Syokota } 127542831Syokota c |= KBD_TRANSLATION; 127642831Syokota#endif 127742831Syokota 127842421Syokota /* enable the keyboard port and intr. */ 127942421Syokota if (!set_controller_command_byte(kbdc, 128042421Syokota KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK, 128142421Syokota (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK)) 128242421Syokota | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) { 128342421Syokota /* 128442421Syokota * CONTROLLER ERROR 128542421Syokota * This is serious; we are left with the disabled 128642421Syokota * keyboard intr. 128742421Syokota */ 128842421Syokota set_controller_command_byte(kbdc, 0xff, c); 128942421Syokota kbdc_lock(kbdc, FALSE); 129042421Syokota printf("atkbd: unable to enable the keyboard port and intr.\n"); 129142421Syokota return EIO; 129242421Syokota } 129342421Syokota 129442421Syokota kbdc_lock(kbdc, FALSE); 129542421Syokota return 0; 129642421Syokota} 129742421Syokota 129842421Syokotastatic int 129942421Syokotawrite_kbd(KBDC kbdc, int command, int data) 130042421Syokota{ 130142421Syokota int s; 130242421Syokota 130342421Syokota /* prevent the timeout routine from polling the keyboard */ 130442421Syokota if (!kbdc_lock(kbdc, TRUE)) 130542421Syokota return EBUSY; 130642421Syokota 130742421Syokota /* disable the keyboard and mouse interrupt */ 130842421Syokota s = spltty(); 130942421Syokota#if 0 131042421Syokota c = get_controller_command_byte(kbdc); 131142421Syokota if ((c == -1) 131242421Syokota || !set_controller_command_byte(kbdc, 131342421Syokota kbdc_get_device_mask(kbdc), 131442421Syokota KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 131542421Syokota | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 131642421Syokota /* CONTROLLER ERROR */ 131742421Syokota kbdc_lock(kbdc, FALSE); 131842421Syokota splx(s); 131942421Syokota return EIO; 132042421Syokota } 132142421Syokota /* 132242421Syokota * Now that the keyboard controller is told not to generate 132342421Syokota * the keyboard and mouse interrupts, call `splx()' to allow 132442421Syokota * the other tty interrupts. The clock interrupt may also occur, 132542421Syokota * but the timeout routine (`scrn_timer()') will be blocked 132642421Syokota * by the lock flag set via `kbdc_lock()' 132742421Syokota */ 132842421Syokota splx(s); 132942421Syokota#endif 133042421Syokota 133142421Syokota if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK) 133242421Syokota send_kbd_command(kbdc, KBDC_ENABLE_KBD); 133342421Syokota 133442421Syokota#if 0 133542421Syokota /* restore the interrupts */ 133642421Syokota if (!set_controller_command_byte(kbdc, 133742421Syokota kbdc_get_device_mask(kbdc), 133842421Syokota c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 133942421Syokota /* CONTROLLER ERROR */ 134042421Syokota } 134142421Syokota#else 134242421Syokota splx(s); 134342421Syokota#endif 134442421Syokota kbdc_lock(kbdc, FALSE); 134542421Syokota 134642421Syokota return 0; 134742421Syokota} 134842421Syokota 134942421Syokotastatic int 135042421Syokotaget_kbd_id(KBDC kbdc) 135142421Syokota{ 135242421Syokota int id1, id2; 135342421Syokota 135442421Syokota empty_both_buffers(kbdc, 10); 135542421Syokota id1 = id2 = -1; 135642421Syokota if (send_kbd_command(kbdc, KBDC_SEND_DEV_ID) != KBD_ACK) 135742421Syokota return -1; 135842421Syokota 135942421Syokota DELAY(10000); /* 10 msec delay */ 136042421Syokota id1 = read_kbd_data(kbdc); 136142421Syokota if (id1 != -1) 136242421Syokota id2 = read_kbd_data(kbdc); 136342421Syokota 136442421Syokota if ((id1 == -1) || (id2 == -1)) { 136542421Syokota empty_both_buffers(kbdc, 10); 136642421Syokota test_controller(kbdc); 136742421Syokota test_kbd_port(kbdc); 136842421Syokota return -1; 136942421Syokota } 137042421Syokota return ((id2 << 8) | id1); 137142421Syokota} 137242421Syokota 137344628Syokotastatic int 137444628Syokotatypematic(int delay, int rate) 137544628Syokota{ 137644628Syokota static int delays[] = { 250, 500, 750, 1000 }; 137744628Syokota static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 137844628Syokota 68, 76, 84, 92, 100, 110, 118, 126, 137944628Syokota 136, 152, 168, 184, 200, 220, 236, 252, 138044628Syokota 272, 304, 336, 368, 400, 440, 472, 504 }; 138144628Syokota int value; 138244628Syokota int i; 138344628Syokota 138444628Syokota for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { 138544628Syokota if (delay >= delays[i]) 138644628Syokota break; 138744628Syokota } 138844628Syokota value = i << 5; 138944628Syokota for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { 139044628Syokota if (rate >= rates[i]) 139144628Syokota break; 139244628Syokota } 139344628Syokota value |= i; 139444628Syokota return value; 139544628Syokota} 139644628Syokota 139742421Syokota#endif /* NATKBD > 0 */ 1398