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