kbd.c revision 42421
142421Syokota/*-
242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
342421Syokota * All rights reserved.
442421Syokota *
542421Syokota * Redistribution and use in source and binary forms, with or without
642421Syokota * modification, are permitted provided that the following conditions
742421Syokota * are met:
842421Syokota * 1. Redistributions of source code must retain the above copyright
942421Syokota *    notice, this list of conditions and the following disclaimer as
1042421Syokota *    the first lines of this file unmodified.
1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright
1242421Syokota *    notice, this list of conditions and the following disclaimer in the
1342421Syokota *    documentation and/or other materials provided with the distribution.
1442421Syokota *
1542421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1642421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1742421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1842421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1942421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2042421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2142421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2242421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2342421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2442421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2542421Syokota *
2642421Syokota * $Id: $
2742421Syokota */
2842421Syokota
2942421Syokota#include "kbd.h"
3042421Syokota#include "opt_kbd.h"
3142421Syokota
3242421Syokota#include <sys/param.h>
3342421Syokota#include <sys/systm.h>
3442421Syokota#include <sys/kernel.h>
3542421Syokota#include <sys/malloc.h>
3642421Syokota#include <sys/conf.h>
3742421Syokota#include <sys/proc.h>
3842421Syokota#include <sys/tty.h>
3942421Syokota#include <sys/poll.h>
4042421Syokota#include <sys/vnode.h>
4142421Syokota#include <sys/uio.h>
4242421Syokota
4342421Syokota#include <machine/console.h>
4442421Syokota
4542421Syokota#include <dev/kbd/kbdreg.h>
4642421Syokota
4742421Syokota/* local arrays */
4842421Syokota
4942421Syokota/*
5042421Syokota * We need at least one entry each in order to initialize a keyboard
5142421Syokota * for the kernel console.  The arrays will be increased dynamically
5242421Syokota * when necessary.
5342421Syokota */
5442421Syokotastatic keyboard_t	*kbd_ini;
5542421Syokotastatic keyboard_switch_t *kbdsw_ini;
5642421Syokotastatic struct cdevsw	*kbdcdevsw_ini;
5742421Syokota
5842421Syokotastatic keyboard_t	**keyboard = &kbd_ini;
5942421Syokotastatic int		keyboards = 1;
6042421Syokota       keyboard_switch_t **kbdsw = &kbdsw_ini;
6142421Syokotastatic struct cdevsw	**kbdcdevsw = &kbdcdevsw_ini;
6242421Syokota
6342421Syokota#define ARRAY_DELTA	4
6442421Syokota
6542421Syokotastatic void
6642421Syokotakbd_realloc_array(void)
6742421Syokota{
6842421Syokota	keyboard_t **new_kbd;
6942421Syokota	keyboard_switch_t **new_kbdsw;
7042421Syokota	struct cdevsw **new_cdevsw;
7142421Syokota	int newsize;
7242421Syokota	int s;
7342421Syokota
7442421Syokota	s = spltty();
7542421Syokota	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
7642421Syokota	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT);
7742421Syokota	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT);
7842421Syokota	new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_NOWAIT);
7942421Syokota	bzero(new_kbd, sizeof(*new_kbd)*newsize);
8042421Syokota	bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
8142421Syokota	bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize);
8242421Syokota	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
8342421Syokota	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
8442421Syokota	bcopy(kbdcdevsw, new_cdevsw, sizeof(*kbdcdevsw)*keyboards);
8542421Syokota	if (keyboards > 1) {
8642421Syokota		free(keyboard, M_DEVBUF);
8742421Syokota		free(kbdsw, M_DEVBUF);
8842421Syokota		free(kbdcdevsw, M_DEVBUF);
8942421Syokota	}
9042421Syokota	keyboard = new_kbd;
9142421Syokota	kbdsw = new_kbdsw;
9242421Syokota	kbdcdevsw = new_cdevsw;
9342421Syokota	keyboards = newsize;
9442421Syokota	splx(s);
9542421Syokota
9642421Syokota	if (bootverbose)
9742421Syokota		printf("kbd: new array size %d\n", keyboards);
9842421Syokota}
9942421Syokota
10042421Syokota/*
10142421Syokota * Low-level keyboard driver functions
10242421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
10342421Syokota * driver, call these functions to initialize the keyboard_t structure
10442421Syokota * and register it to the virtual keyboard driver `kbd'.
10542421Syokota */
10642421Syokota
10742421Syokota/* initialize the keyboard_t structure */
10842421Syokotavoid
10942421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
11042421Syokota		int port, int port_size)
11142421Syokota{
11242421Syokota	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
11342421Syokota	kbd->kb_name = name;
11442421Syokota	kbd->kb_type = type;
11542421Syokota	kbd->kb_unit = unit;
11642421Syokota	kbd->kb_config = config;
11742421Syokota	kbd->kb_led = 0;		/* unknown */
11842421Syokota	kbd->kb_io_base = port;
11942421Syokota	kbd->kb_io_size = port_size;
12042421Syokota	kbd->kb_data = NULL;
12142421Syokota	kbd->kb_keymap = NULL;
12242421Syokota	kbd->kb_accentmap = NULL;
12342421Syokota	kbd->kb_fkeytab = NULL;
12442421Syokota	kbd->kb_fkeytab_size = 0;
12542421Syokota}
12642421Syokota
12742421Syokotavoid
12842421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
12942421Syokota	     fkeytab_t *fkeymap, int fkeymap_size)
13042421Syokota{
13142421Syokota	kbd->kb_keymap = keymap;
13242421Syokota	kbd->kb_accentmap = accmap;
13342421Syokota	kbd->kb_fkeytab = fkeymap;
13442421Syokota	kbd->kb_fkeytab_size = fkeymap_size;
13542421Syokota}
13642421Syokota
13742421Syokota/* register a keyboard and associate it with a function table */
13842421Syokotaint
13942421Syokotakbd_register(keyboard_t *kbd)
14042421Syokota{
14142421Syokota	keyboard_driver_t **list;
14242421Syokota	keyboard_driver_t *p;
14342421Syokota	int index;
14442421Syokota
14542421Syokota	for (index = 0; index < keyboards; ++index) {
14642421Syokota		if (keyboard[index] == NULL)
14742421Syokota			break;
14842421Syokota	}
14942421Syokota	if (index >= keyboards)
15042421Syokota		return -1;
15142421Syokota
15242421Syokota	kbd->kb_index = index;
15342421Syokota	KBD_UNBUSY(kbd);
15442421Syokota	KBD_VALID(kbd);
15542421Syokota	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
15642421Syokota	kbd->kb_token = NULL;
15742421Syokota	kbd->kb_callback.kc_func = NULL;
15842421Syokota	kbd->kb_callback.kc_arg = NULL;
15942421Syokota
16042421Syokota	list = (keyboard_driver_t **)kbddriver_set.ls_items;
16142421Syokota	while ((p = *list++) != NULL) {
16242421Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
16342421Syokota			keyboard[index] = kbd;
16442421Syokota			kbdsw[index] = p->kbdsw;
16542421Syokota			return index;
16642421Syokota		}
16742421Syokota	}
16842421Syokota
16942421Syokota	return -1;
17042421Syokota}
17142421Syokota
17242421Syokotaint
17342421Syokotakbd_unregister(keyboard_t *kbd)
17442421Syokota{
17542421Syokota	int error;
17642421Syokota	int s;
17742421Syokota
17842421Syokota	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
17942421Syokota		return ENOENT;
18042421Syokota	if (keyboard[kbd->kb_index] != kbd)
18142421Syokota		return ENOENT;
18242421Syokota
18342421Syokota	s = spltty();
18442421Syokota	if (KBD_IS_BUSY(kbd)) {
18542421Syokota		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
18642421Syokota						    kbd->kb_callback.kc_arg);
18742421Syokota		if (error) {
18842421Syokota			splx(s);
18942421Syokota			return error;
19042421Syokota		}
19142421Syokota		if (KBD_IS_BUSY(kbd)) {
19242421Syokota			splx(s);
19342421Syokota			return EBUSY;
19442421Syokota		}
19542421Syokota	}
19642421Syokota	KBD_INVALID(kbd);
19742421Syokota	keyboard[kbd->kb_index] = NULL;
19842421Syokota	kbdsw[kbd->kb_index] = NULL;
19942421Syokota
20042421Syokota	splx(s);
20142421Syokota	return 0;
20242421Syokota}
20342421Syokota
20442421Syokota/* find a funciton table by the driver name */
20542421Syokotakeyboard_switch_t
20642421Syokota*kbd_get_switch(char *driver)
20742421Syokota{
20842421Syokota	keyboard_driver_t **list;
20942421Syokota	keyboard_driver_t *p;
21042421Syokota
21142421Syokota	list = (keyboard_driver_t **)kbddriver_set.ls_items;
21242421Syokota	while ((p = *list++) != NULL) {
21342421Syokota		if (strcmp(p->name, driver) == 0)
21442421Syokota			return p->kbdsw;
21542421Syokota	}
21642421Syokota
21742421Syokota	return NULL;
21842421Syokota}
21942421Syokota
22042421Syokota/*
22142421Syokota * Keyboard client functions
22242421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard
22342421Syokota * cdev driver, use these functions to claim and release a keyboard for
22442421Syokota * exclusive use.
22542421Syokota */
22642421Syokota
22742421Syokota/* find the keyboard specified by a driver name and a unit number */
22842421Syokotaint
22942421Syokotakbd_find_keyboard(char *driver, int unit)
23042421Syokota{
23142421Syokota	int i;
23242421Syokota
23342421Syokota	for (i = 0; i < keyboards; ++i) {
23442421Syokota		if (keyboard[i] == NULL)
23542421Syokota			continue;
23642421Syokota		if (!KBD_IS_VALID(keyboard[i]))
23742421Syokota			continue;
23842421Syokota		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
23942421Syokota			continue;
24042421Syokota		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
24142421Syokota			continue;
24242421Syokota		return i;
24342421Syokota	}
24442421Syokota	return -1;
24542421Syokota}
24642421Syokota
24742421Syokota/* allocate a keyboard */
24842421Syokotaint
24942421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
25042421Syokota	     void *arg)
25142421Syokota{
25242421Syokota	int index;
25342421Syokota	int s;
25442421Syokota
25542421Syokota	if (func == NULL)
25642421Syokota		return -1;
25742421Syokota
25842421Syokota	s = spltty();
25942421Syokota	index = kbd_find_keyboard(driver, unit);
26042421Syokota	if (index >= 0) {
26142421Syokota		if (KBD_IS_BUSY(keyboard[index])) {
26242421Syokota			splx(s);
26342421Syokota			return -1;
26442421Syokota		}
26542421Syokota		keyboard[index]->kb_token = id;
26642421Syokota		KBD_BUSY(keyboard[index]);
26742421Syokota		keyboard[index]->kb_callback.kc_func = func;
26842421Syokota		keyboard[index]->kb_callback.kc_arg = arg;
26942421Syokota		(*kbdsw[index]->clear_state)(keyboard[index]);
27042421Syokota	}
27142421Syokota	splx(s);
27242421Syokota	return index;
27342421Syokota}
27442421Syokota
27542421Syokotaint
27642421Syokotakbd_release(keyboard_t *kbd, void *id)
27742421Syokota{
27842421Syokota	int error;
27942421Syokota	int s;
28042421Syokota
28142421Syokota	s = spltty();
28242421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
28342421Syokota		error = EINVAL;
28442421Syokota	} else if (kbd->kb_token != id) {
28542421Syokota		error = EPERM;
28642421Syokota	} else {
28742421Syokota		kbd->kb_token = NULL;
28842421Syokota		KBD_UNBUSY(kbd);
28942421Syokota		kbd->kb_callback.kc_func = NULL;
29042421Syokota		kbd->kb_callback.kc_arg = NULL;
29142421Syokota		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
29242421Syokota		error = 0;
29342421Syokota	}
29442421Syokota	splx(s);
29542421Syokota	return error;
29642421Syokota}
29742421Syokota
29842421Syokotaint
29942421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
30042421Syokota		    void *arg)
30142421Syokota{
30242421Syokota	int error;
30342421Syokota	int s;
30442421Syokota
30542421Syokota	s = spltty();
30642421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
30742421Syokota		error = EINVAL;
30842421Syokota	} else if (kbd->kb_token != id) {
30942421Syokota		error = EPERM;
31042421Syokota	} else if (func == NULL) {
31142421Syokota		error = EINVAL;
31242421Syokota	} else {
31342421Syokota		kbd->kb_callback.kc_func = func;
31442421Syokota		kbd->kb_callback.kc_arg = arg;
31542421Syokota		error = 0;
31642421Syokota	}
31742421Syokota	splx(s);
31842421Syokota	return error;
31942421Syokota}
32042421Syokota
32142421Syokota/* get a keyboard structure */
32242421Syokotakeyboard_t
32342421Syokota*kbd_get_keyboard(int index)
32442421Syokota{
32542421Syokota	if ((index < 0) || (index >= keyboards))
32642421Syokota		return NULL;
32742421Syokota	if (!KBD_IS_VALID(keyboard[index]))
32842421Syokota		return NULL;
32942421Syokota	return keyboard[index];
33042421Syokota}
33142421Syokota
33242421Syokota/*
33342421Syokota * The back door for the console driver; configure keyboards
33442421Syokota * This function is for the kernel console to initialize keyboards
33542421Syokota * at very early stage.
33642421Syokota */
33742421Syokota
33842421Syokotaint
33942421Syokotakbd_configure(int flags)
34042421Syokota{
34142421Syokota	keyboard_driver_t **list;
34242421Syokota	keyboard_driver_t *p;
34342421Syokota
34442421Syokota	list = (keyboard_driver_t **)kbddriver_set.ls_items;
34542421Syokota	while ((p = *list++) != NULL) {
34642421Syokota		if (p->configure != NULL)
34742421Syokota			(*p->configure)(flags);
34842421Syokota	}
34942421Syokota
35042421Syokota	return 0;
35142421Syokota}
35242421Syokota
35342421Syokota#ifdef KBD_INSTALL_CDEV
35442421Syokota
35542421Syokota/*
35642421Syokota * Virtual keyboard cdev driver functions
35742421Syokota * The virtual keyboard driver dispatches driver functions to
35842421Syokota * appropriate subdrivers.
35942421Syokota */
36042421Syokota
36142421Syokota#define KBD_UNIT(dev)	minor(dev)
36242421Syokota
36342421Syokotastatic d_open_t		kbdopen;
36442421Syokotastatic d_close_t	kbdclose;
36542421Syokotastatic d_read_t		kbdread;
36642421Syokotastatic d_write_t	kbdwrite;
36742421Syokotastatic d_ioctl_t	kbdioctl;
36842421Syokotastatic d_reset_t	kbdreset;
36942421Syokotastatic d_devtotty_t	kbddevtotty;
37042421Syokotastatic d_poll_t		kbdpoll;
37142421Syokotastatic d_mmap_t		kbdmmap;
37242421Syokota
37342421Syokota#define CDEV_MAJOR	112
37442421Syokota
37542421Syokotastatic struct cdevsw kbd_cdevsw = {
37642421Syokota	kbdopen,	kbdclose,	kbdread,	kbdwrite,   /* ??? */
37742421Syokota	kbdioctl,	nullstop,	kbdreset,	kbddevtotty,
37842421Syokota	kbdpoll,	kbdmmap,	nostrategy,	"kbd",
37942421Syokota	NULL,		-1,		nodump,		nopsize,
38042421Syokota};
38142421Syokota
38242421Syokotastatic void
38342421Syokotavkbdattach(void *arg)
38442421Syokota{
38542421Syokota	static int kbd_devsw_installed = FALSE;
38642421Syokota	dev_t dev;
38742421Syokota
38842421Syokota	if (!kbd_devsw_installed) {
38942421Syokota		dev = makedev(CDEV_MAJOR, 0);
39042421Syokota		cdevsw_add(&dev, &kbd_cdevsw, NULL);
39142421Syokota		kbd_devsw_installed = TRUE;
39242421Syokota	}
39342421Syokota}
39442421Syokota
39542421SyokotaPSEUDO_SET(vkbdattach, kbd);
39642421Syokota
39742421Syokotaint
39842421Syokotakbd_attach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
39942421Syokota{
40042421Syokota	int s;
40142421Syokota
40242421Syokota	if (kbd->kb_index >= keyboards)
40342421Syokota		return EINVAL;
40442421Syokota	if (keyboard[kbd->kb_index] != kbd)
40542421Syokota		return EINVAL;
40642421Syokota
40742421Syokota	s = spltty();
40842421Syokota	kbd->kb_minor = minor(dev);
40942421Syokota	kbdcdevsw[kbd->kb_index] = cdevsw;
41042421Syokota	splx(s);
41142421Syokota
41242421Syokota	/* XXX: DEVFS? */
41342421Syokota
41442421Syokota	if (kbd->kb_index + 1 >= keyboards)
41542421Syokota		kbd_realloc_array();
41642421Syokota
41742421Syokota	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
41842421Syokota	return 0;
41942421Syokota}
42042421Syokota
42142421Syokotaint
42242421Syokotakbd_detach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
42342421Syokota{
42442421Syokota	int s;
42542421Syokota
42642421Syokota	if (kbd->kb_index >= keyboards)
42742421Syokota		return EINVAL;
42842421Syokota	if (keyboard[kbd->kb_index] != kbd)
42942421Syokota		return EINVAL;
43042421Syokota	if (kbdcdevsw[kbd->kb_index] != cdevsw)
43142421Syokota		return EINVAL;
43242421Syokota
43342421Syokota	s = spltty();
43442421Syokota	(*kbdsw[kbd->kb_index]->term)(kbd);
43542421Syokota	kbdcdevsw[kbd->kb_index] = NULL;
43642421Syokota	splx(s);
43742421Syokota	return 0;
43842421Syokota}
43942421Syokota
44042421Syokotastatic int
44142421Syokotakbdopen(dev_t dev, int flag, int mode, struct proc *p)
44242421Syokota{
44342421Syokota	int unit;
44442421Syokota
44542421Syokota	unit = KBD_UNIT(dev);
44642421Syokota	if (unit >= keyboards)
44742421Syokota		return ENXIO;
44842421Syokota	if (kbdcdevsw[unit] == NULL)
44942421Syokota		return ENXIO;
45042421Syokota	if (KBD_IS_BUSY(keyboard[unit]))
45142421Syokota		return EBUSY;
45242421Syokota	return (*kbdcdevsw[unit]->d_open)(makedev(0, keyboard[unit]->kb_minor),
45342421Syokota					  flag, mode, p);
45442421Syokota}
45542421Syokota
45642421Syokotastatic int
45742421Syokotakbdclose(dev_t dev, int flag, int mode, struct proc *p)
45842421Syokota{
45942421Syokota	int unit;
46042421Syokota
46142421Syokota	unit = KBD_UNIT(dev);
46242421Syokota	if (kbdcdevsw[unit] == NULL)
46342421Syokota		return ENXIO;
46442421Syokota	return (*kbdcdevsw[unit]->d_close)(makedev(0, keyboard[unit]->kb_minor),
46542421Syokota					   flag, mode, p);
46642421Syokota}
46742421Syokota
46842421Syokotastatic int
46942421Syokotakbdread(dev_t dev, struct uio *uio, int flag)
47042421Syokota{
47142421Syokota	int unit;
47242421Syokota
47342421Syokota	unit = KBD_UNIT(dev);
47442421Syokota	if (kbdcdevsw[unit] == NULL)
47542421Syokota		return ENXIO;
47642421Syokota	return (*kbdcdevsw[unit]->d_read)(makedev(0, keyboard[unit]->kb_minor),
47742421Syokota					  uio, flag);
47842421Syokota}
47942421Syokota
48042421Syokotastatic int
48142421Syokotakbdwrite(dev_t dev, struct uio *uio, int flag)
48242421Syokota{
48342421Syokota	int unit;
48442421Syokota
48542421Syokota	unit = KBD_UNIT(dev);
48642421Syokota	if (kbdcdevsw[unit] == NULL)
48742421Syokota		return ENXIO;
48842421Syokota	return (*kbdcdevsw[unit]->d_write)(makedev(0, keyboard[unit]->kb_minor),
48942421Syokota					   uio, flag);
49042421Syokota}
49142421Syokota
49242421Syokotastatic int
49342421Syokotakbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
49442421Syokota{
49542421Syokota	int unit;
49642421Syokota
49742421Syokota	unit = KBD_UNIT(dev);
49842421Syokota	if (kbdcdevsw[unit] == NULL)
49942421Syokota		return ENXIO;
50042421Syokota	return (*kbdcdevsw[unit]->d_ioctl)(makedev(0, keyboard[unit]->kb_minor),
50142421Syokota					   cmd, arg, flag, p);
50242421Syokota}
50342421Syokota
50442421Syokotastatic int
50542421Syokotakbdreset(dev_t dev)
50642421Syokota{
50742421Syokota	int unit;
50842421Syokota
50942421Syokota	unit = KBD_UNIT(dev);
51042421Syokota	if (kbdcdevsw[unit] == NULL)
51142421Syokota		return ENXIO;
51242421Syokota	return (*kbdcdevsw[unit]->d_reset)(makedev(0, keyboard[unit]->kb_minor));
51342421Syokota}
51442421Syokota
51542421Syokotastatic struct tty
51642421Syokota*kbddevtotty(dev_t dev)
51742421Syokota{
51842421Syokota	int unit;
51942421Syokota
52042421Syokota	unit = KBD_UNIT(dev);
52142421Syokota	if (kbdcdevsw[unit] == NULL)
52242421Syokota		return NULL;
52342421Syokota	return (*kbdcdevsw[unit]->d_devtotty)(makedev(0, keyboard[unit]->kb_minor));
52442421Syokota}
52542421Syokota
52642421Syokotastatic int
52742421Syokotakbdpoll(dev_t dev, int event, struct proc *p)
52842421Syokota{
52942421Syokota	int unit;
53042421Syokota
53142421Syokota	unit = KBD_UNIT(dev);
53242421Syokota	if (kbdcdevsw[unit] == NULL)
53342421Syokota		return ENXIO;
53442421Syokota	return (*kbdcdevsw[unit]->d_poll)(makedev(0, keyboard[unit]->kb_minor),
53542421Syokota					  event, p);
53642421Syokota}
53742421Syokota
53842421Syokotastatic int
53942421Syokotakbdmmap(dev_t dev,  vm_offset_t offset, int nprot)
54042421Syokota{
54142421Syokota	int unit;
54242421Syokota
54342421Syokota	unit = KBD_UNIT(dev);
54442421Syokota	if (kbdcdevsw[unit] == NULL)
54542421Syokota		return ENXIO;
54642421Syokota	return (*kbdcdevsw[unit]->d_mmap)(makedev(0, keyboard[unit]->kb_minor),
54742421Syokota					  offset, nprot);
54842421Syokota}
54942421Syokota
55042421Syokota/*
55142421Syokota * Generic keyboard cdev driver functions
55242421Syokota * Keyboard subdrivers may call these functions to implement common
55342421Syokota * driver functions.
55442421Syokota */
55542421Syokota
55642421Syokota#define KB_QSIZE	512
55742421Syokota#define KB_BUFSIZE	64
55842421Syokota
55942421Syokotastatic kbd_callback_func_t genkbd_event;
56042421Syokota
56142421Syokotaint
56242421Syokotagenkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
56342421Syokota	   struct proc *p)
56442421Syokota{
56542421Syokota	int s;
56642421Syokota	int i;
56742421Syokota
56842421Syokota	s = spltty();
56942421Syokota	if (!KBD_IS_VALID(kbd)) {
57042421Syokota		splx(s);
57142421Syokota		return ENXIO;
57242421Syokota	}
57342421Syokota	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
57442421Syokota			 genkbd_event, (void *)sc);
57542421Syokota	if (i < 0) {
57642421Syokota		splx(s);
57742421Syokota		return EBUSY;
57842421Syokota	}
57942421Syokota	/* assert(i == kbd->kb_index) */
58042421Syokota	/* assert(kbd == kbd_get_keyboard(i)) */
58142421Syokota
58242421Syokota	/*
58342421Syokota	 * NOTE: even when we have successfully claimed a keyboard,
58442421Syokota	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
58542421Syokota	 */
58642421Syokota
58742421Syokota#if 0
58842421Syokota	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
58942421Syokota#endif
59042421Syokota	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
59142421Syokota	sc->gkb_rsel.si_flags = 0;
59242421Syokota	sc->gkb_rsel.si_pid = 0;
59342421Syokota	splx(s);
59442421Syokota
59542421Syokota	return 0;
59642421Syokota}
59742421Syokota
59842421Syokotaint
59942421Syokotagenkbdclose(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
60042421Syokota	    struct proc *p)
60142421Syokota{
60242421Syokota	int s;
60342421Syokota
60442421Syokota	/*
60542421Syokota	 * NOTE: the device may have already become invalid.
60642421Syokota	 * !KBD_IS_VALID(kbd)
60742421Syokota	 */
60842421Syokota	s = spltty();
60942421Syokota	kbd_release(kbd, (void *)sc);
61042421Syokota#if 0
61142421Syokota	clist_free_cblocks(&sc->gkb_q);
61242421Syokota#endif
61342421Syokota	splx(s);
61442421Syokota
61542421Syokota	return 0;
61642421Syokota}
61742421Syokota
61842421Syokotaint
61942421Syokotagenkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
62042421Syokota{
62142421Syokota	u_char buffer[KB_BUFSIZE];
62242421Syokota	int len;
62342421Syokota	int error;
62442421Syokota	int s;
62542421Syokota
62642421Syokota	/* wait for input */
62742421Syokota	s = spltty();
62842421Syokota	while (sc->gkb_q.c_cc == 0) {
62942421Syokota		if (!KBD_IS_VALID(kbd)) {
63042421Syokota			splx(s);
63142421Syokota			return EIO;
63242421Syokota		}
63342421Syokota		if (flag & IO_NDELAY) {
63442421Syokota			splx(s);
63542421Syokota			return EWOULDBLOCK;
63642421Syokota		}
63742421Syokota		sc->gkb_flags |= KB_ASLEEP;
63842421Syokota		error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
63942421Syokota		if (error) {
64042421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
64142421Syokota			splx(s);
64242421Syokota			return error;
64342421Syokota		}
64442421Syokota	}
64542421Syokota	splx(s);
64642421Syokota
64742421Syokota	/* copy as much input as possible */
64842421Syokota	error = 0;
64942421Syokota	while (uio->uio_resid > 0) {
65042421Syokota		len = imin(uio->uio_resid, sizeof(buffer));
65142421Syokota		len = q_to_b(&sc->gkb_q, buffer, len);
65242421Syokota		if (len <= 0)
65342421Syokota			break;
65442421Syokota		error = uiomove(buffer, len, uio);
65542421Syokota		if (error)
65642421Syokota			break;
65742421Syokota	}
65842421Syokota
65942421Syokota	return error;
66042421Syokota}
66142421Syokota
66242421Syokotaint
66342421Syokotagenkbdwrite(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
66442421Syokota{
66542421Syokota	if (!KBD_IS_VALID(kbd))
66642421Syokota		return ENXIO;
66742421Syokota	return ENODEV;
66842421Syokota}
66942421Syokota
67042421Syokotaint
67142421Syokotagenkbdioctl(genkbd_softc_t *sc, keyboard_t *kbd, u_long cmd, caddr_t arg,
67242421Syokota	    int flag, struct proc *p)
67342421Syokota{
67442421Syokota	int error;
67542421Syokota
67642421Syokota	if (kbd == NULL)	/* XXX */
67742421Syokota		return ENXIO;
67842421Syokota	if (!KBD_IS_VALID(kbd))
67942421Syokota		return ENXIO;
68042421Syokota	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
68142421Syokota	if (error == ENOIOCTL)
68242421Syokota		error = ENODEV;
68342421Syokota	return error;
68442421Syokota}
68542421Syokota
68642421Syokotaint
68742421Syokotagenkbdpoll(genkbd_softc_t *sc, keyboard_t *kbd, int events, struct proc *p)
68842421Syokota{
68942421Syokota	int revents;
69042421Syokota	int s;
69142421Syokota
69242421Syokota	revents = 0;
69342421Syokota	s = spltty();
69442421Syokota	if (events & (POLLIN | POLLRDNORM)) {
69542421Syokota		if ((sc->gkb_q.c_cc > 0) || !KBD_IS_VALID(kbd))
69642421Syokota			revents |= (POLLIN | POLLRDNORM);
69742421Syokota		else
69842421Syokota			selrecord(p, &sc->gkb_rsel);
69942421Syokota	}
70042421Syokota	splx(s);
70142421Syokota	return revents;
70242421Syokota}
70342421Syokota
70442421Syokotastatic int
70542421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg)
70642421Syokota{
70742421Syokota	genkbd_softc_t *sc;
70842421Syokota	size_t len;
70942421Syokota	u_char *cp;
71042421Syokota	int mode;
71142421Syokota	int c;
71242421Syokota
71342421Syokota	/* assert(KBD_IS_VALID(kbd)) */
71442421Syokota	sc = (genkbd_softc_t *)arg;
71542421Syokota
71642421Syokota	switch (event) {
71742421Syokota	case KBDIO_KEYINPUT:
71842421Syokota		break;
71942421Syokota	case KBDIO_UNLOADING:
72042421Syokota		/* the keyboard is going... */
72142421Syokota		kbd_release(kbd, (void *)sc);
72242421Syokota		return 0;
72342421Syokota	default:
72442421Syokota		return EINVAL;
72542421Syokota	}
72642421Syokota
72742421Syokota	/* obtain the current key input mode */
72842421Syokota	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
72942421Syokota		mode = K_XLATE;
73042421Syokota
73142421Syokota	/* read all pending input */
73242421Syokota	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
73342421Syokota		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
73442421Syokota		if (c == NOKEY)
73542421Syokota			continue;
73642421Syokota		if (c == ERRKEY)	/* XXX: ring bell? */
73742421Syokota			continue;
73842421Syokota		if (!KBD_IS_BUSY(kbd))
73942421Syokota			/* the device is not open, discard the input */
74042421Syokota			continue;
74142421Syokota
74242421Syokota		/* store the byte as is for K_RAW and K_CODE modes */
74342421Syokota		if (mode != K_XLATE) {
74442421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
74542421Syokota			continue;
74642421Syokota		}
74742421Syokota
74842421Syokota		/* K_XLATE */
74942421Syokota		if (c & RELKEY)	/* key release is ignored */
75042421Syokota			continue;
75142421Syokota
75242421Syokota		/* process special keys; most of them are just ignored... */
75342421Syokota		if (c & SPCLKEY) {
75442421Syokota			switch (KEYCHAR(c)) {
75542421Syokota			/* locking keys */
75642421Syokota			case NLK:  case CLK:  case SLK:  case ALK:
75742421Syokota			/* shift keys */
75842421Syokota			case LSH:  case RSH:  case LCTR: case RCTR:
75942421Syokota			case LALT: case RALT: case ASH:  case META:
76042421Syokota			/* other special keys */
76142421Syokota			case NOP:  case SPSC: case RBT:  case SUSP:
76242421Syokota			case STBY: case DBG:  case NEXT:
76342421Syokota				/* ignore them... */
76442421Syokota				continue;
76542421Syokota			case BTAB:	/* a backtab: ESC [ Z */
76642421Syokota				putc(0x1b, &sc->gkb_q);
76742421Syokota				putc('[', &sc->gkb_q);
76842421Syokota				putc('Z', &sc->gkb_q);
76942421Syokota				continue;
77042421Syokota			}
77142421Syokota		}
77242421Syokota
77342421Syokota		/* normal chars, normal chars with the META, function keys */
77442421Syokota		switch (KEYFLAGS(c)) {
77542421Syokota		case 0:			/* a normal char */
77642421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
77742421Syokota			break;
77842421Syokota		case MKEY:		/* the META flag: prepend ESC */
77942421Syokota			putc(0x1b, &sc->gkb_q);
78042421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
78142421Syokota			break;
78242421Syokota		case FKEY | SPCLKEY:	/* a function key, return string */
78342421Syokota			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
78442421Syokota							KEYCHAR(c), &len);
78542421Syokota			if (cp != NULL) {
78642421Syokota				while (len-- >  0)
78742421Syokota					putc(*cp++, &sc->gkb_q);
78842421Syokota			}
78942421Syokota			break;
79042421Syokota		}
79142421Syokota	}
79242421Syokota
79342421Syokota	/* wake up sleeping/polling processes */
79442421Syokota	if (sc->gkb_q.c_cc > 0) {
79542421Syokota		if (sc->gkb_flags & KB_ASLEEP) {
79642421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
79742421Syokota			wakeup((caddr_t)sc);
79842421Syokota		}
79942421Syokota		selwakeup(&sc->gkb_rsel);
80042421Syokota	}
80142421Syokota
80242421Syokota	return 0;
80342421Syokota}
80442421Syokota
80542421Syokota#endif /* KBD_INSTALL_CDEV */
80642421Syokota
80742421Syokota/*
80842421Syokota * Generic low-level keyboard functions
80942421Syokota * The low-level functions in the keyboard subdriver may use these
81042421Syokota * functions.
81142421Syokota */
81242421Syokota
81342421Syokotaint
81442421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
81542421Syokota{
81642421Syokota	keyarg_t *keyp;
81742421Syokota	fkeyarg_t *fkeyp;
81842421Syokota	int s;
81942421Syokota	int i;
82042421Syokota
82142421Syokota	s = spltty();
82242421Syokota	switch (cmd) {
82342421Syokota
82442421Syokota	case KDGKBINFO:		/* get keyboard information */
82542421Syokota		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
82642421Syokota		i = imin(strlen(kbd->kb_name) + 1,
82742421Syokota			 sizeof(((keyboard_info_t *)arg)->kb_name));
82842421Syokota		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
82942421Syokota		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
83042421Syokota		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
83142421Syokota		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
83242421Syokota		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
83342421Syokota		break;
83442421Syokota
83542421Syokota	case KDGKBTYPE:		/* get keyboard type */
83642421Syokota		*(int *)arg = kbd->kb_type;
83742421Syokota		break;
83842421Syokota
83942421Syokota	case GIO_KEYMAP:	/* get keyboard translation table */
84042421Syokota		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
84142421Syokota		break;
84242421Syokota	case PIO_KEYMAP:	/* set keyboard translation table */
84342421Syokota		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
84442421Syokota		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
84542421Syokota		break;
84642421Syokota
84742421Syokota	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
84842421Syokota		keyp = (keyarg_t *)arg;
84942421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
85042421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
85142421Syokota			splx(s);
85242421Syokota			return EINVAL;
85342421Syokota		}
85442421Syokota		bcopy(&kbd->kb_keymap[keyp->keynum], &keyp->key,
85542421Syokota		      sizeof(keyp->key));
85642421Syokota		break;
85742421Syokota	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
85842421Syokota		keyp = (keyarg_t *)arg;
85942421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
86042421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
86142421Syokota			splx(s);
86242421Syokota			return EINVAL;
86342421Syokota		}
86442421Syokota		bcopy(&keyp->key, &kbd->kb_keymap[keyp->keynum],
86542421Syokota		      sizeof(keyp->key));
86642421Syokota		break;
86742421Syokota
86842421Syokota	case GIO_DEADKEYMAP:	/* get accent key translation table */
86942421Syokota		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
87042421Syokota		break;
87142421Syokota	case PIO_DEADKEYMAP:	/* set accent key translation table */
87242421Syokota		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
87342421Syokota		break;
87442421Syokota
87542421Syokota	case GETFKEY:		/* get functionkey string */
87642421Syokota		fkeyp = (fkeyarg_t *)arg;
87742421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
87842421Syokota			splx(s);
87942421Syokota			return EINVAL;
88042421Syokota		}
88142421Syokota		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
88242421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
88342421Syokota		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
88442421Syokota		break;
88542421Syokota	case SETFKEY:		/* set functionkey string */
88642421Syokota		fkeyp = (fkeyarg_t *)arg;
88742421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
88842421Syokota			splx(s);
88942421Syokota			return EINVAL;
89042421Syokota		}
89142421Syokota		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
89242421Syokota		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
89342421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
89442421Syokota		break;
89542421Syokota
89642421Syokota	default:
89742421Syokota		splx(s);
89842421Syokota		return ENOIOCTL;
89942421Syokota	}
90042421Syokota
90142421Syokota	splx(s);
90242421Syokota	return 0;
90342421Syokota}
90442421Syokota
90542421Syokota/* get a pointer to the string associated with the given function key */
90642421Syokotau_char
90742421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
90842421Syokota{
90942421Syokota	if (kbd == NULL)
91042421Syokota		return NULL;
91142421Syokota	fkey -= F_FN;
91242421Syokota	if (fkey > kbd->kb_fkeytab_size)
91342421Syokota		return NULL;
91442421Syokota	*len = kbd->kb_fkeytab[fkey].len;
91542421Syokota	return kbd->kb_fkeytab[fkey].str;
91642421Syokota}
91742421Syokota
91842421Syokota/* diagnostic dump */
91942421Syokotastatic char
92042421Syokota*get_kbd_type_name(int type)
92142421Syokota{
92242421Syokota	static struct {
92342421Syokota		int type;
92442421Syokota		char *name;
92542421Syokota	} name_table[] = {
92642421Syokota		{ KB_84,	"AT 84" },
92742421Syokota		{ KB_101,	"AT 101/102" },
92842421Syokota		{ KB_OTHER,	"generic" },
92942421Syokota	};
93042421Syokota	int i;
93142421Syokota
93242421Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
93342421Syokota		if (type == name_table[i].type)
93442421Syokota			return name_table[i].name;
93542421Syokota	}
93642421Syokota	return "unknown";
93742421Syokota}
93842421Syokota
93942421Syokotavoid
94042421Syokotagenkbd_diag(keyboard_t *kbd, int level)
94142421Syokota{
94242421Syokota	if (level > 0) {
94342421Syokota		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
94442421Syokota		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
94542421Syokota		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
94642421Syokota		       kbd->kb_config, kbd->kb_flags);
94742421Syokota		if (kbd->kb_io_base > 0)
94842421Syokota			printf(", port:0x%x-0x%x", kbd->kb_io_base,
94942421Syokota			       kbd->kb_io_base + kbd->kb_io_size - 1);
95042421Syokota		printf("\n");
95142421Syokota	}
95242421Syokota}
95342421Syokota
95442421Syokota#define set_lockkey_state(k, s, l)				\
95542421Syokota	if (!((s) & l ## DOWN)) {				\
95642421Syokota		int i;						\
95742421Syokota		(s) |= l ## DOWN;				\
95842421Syokota		(s) ^= l ## ED;					\
95942421Syokota		i = (s) & LOCK_MASK;				\
96042421Syokota		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
96142421Syokota	}
96242421Syokota
96342421Syokotastatic u_int
96442421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents)
96542421Syokota{
96642421Syokota	int i;
96742421Syokota
96842421Syokota	/* make an index into the accent map */
96942421Syokota	i = key - F_ACC + 1;
97042421Syokota	if ((i > kbd->kb_accentmap->n_accs)
97142421Syokota	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
97242421Syokota		/* the index is out of range or pointing to an empty entry */
97342421Syokota		*accents = 0;
97442421Syokota		return ERRKEY;
97542421Syokota	}
97642421Syokota
97742421Syokota	/*
97842421Syokota	 * If the same accent key has been hit twice, produce the accent char
97942421Syokota	 * itself.
98042421Syokota	 */
98142421Syokota	if (i == *accents) {
98242421Syokota		key = kbd->kb_accentmap->acc[i - 1].accchar;
98342421Syokota		*accents = 0;
98442421Syokota		return key;
98542421Syokota	}
98642421Syokota
98742421Syokota	/* remember the index and wait for the next key  */
98842421Syokota	*accents = i;
98942421Syokota	return NOKEY;
99042421Syokota}
99142421Syokota
99242421Syokotastatic u_int
99342421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents)
99442421Syokota{
99542421Syokota	struct acc_t *acc;
99642421Syokota	int i;
99742421Syokota
99842421Syokota	acc = &kbd->kb_accentmap->acc[*accents - 1];
99942421Syokota	*accents = 0;
100042421Syokota
100142421Syokota	/*
100242421Syokota	 * If the accent key is followed by the space key,
100342421Syokota	 * produce the accent char itself.
100442421Syokota	 */
100542421Syokota	if (ch == ' ')
100642421Syokota		return acc->accchar;
100742421Syokota
100842421Syokota	/* scan the accent map */
100942421Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
101042421Syokota		if (acc->map[i][0] == 0)	/* end of table */
101142421Syokota			break;
101242421Syokota		if (acc->map[i][0] == ch)
101342421Syokota			return acc->map[i][1];
101442421Syokota	}
101542421Syokota	/* this char cannot be accented... */
101642421Syokota	return ERRKEY;
101742421Syokota}
101842421Syokota
101942421Syokotaint
102042421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
102142421Syokota		 int *accents)
102242421Syokota{
102342421Syokota	struct keyent_t *key;
102442421Syokota	int state = *shiftstate;
102542421Syokota	int action;
102642421Syokota	int f;
102742421Syokota	int i;
102842421Syokota
102942421Syokota	f = state & (AGRS | ALKED);
103042421Syokota	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
103142421Syokota		keycode += ALTGR_OFFSET;
103242421Syokota	key = &kbd->kb_keymap->key[keycode];
103342421Syokota	i = ((state & SHIFTS) ? 1 : 0)
103442421Syokota	    | ((state & CTLS) ? 2 : 0)
103542421Syokota	    | ((state & ALTS) ? 4 : 0);
103642421Syokota	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
103742421Syokota		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
103842421Syokota		i ^= 1;
103942421Syokota
104042421Syokota	action = key->map[i];
104142421Syokota	if (up) {	/* break: key released */
104242421Syokota		if (key->spcl & (0x80 >> i)) {
104342421Syokota			/* special keys */
104442421Syokota			switch (action) {
104542421Syokota			case LSH:
104642421Syokota				state &= ~SHIFTS1;
104742421Syokota				break;
104842421Syokota			case RSH:
104942421Syokota				state &= ~SHIFTS2;
105042421Syokota				break;
105142421Syokota			case LCTR:
105242421Syokota				state &= ~CTLS1;
105342421Syokota				break;
105442421Syokota			case RCTR:
105542421Syokota				state &= ~CTLS2;
105642421Syokota				break;
105742421Syokota			case LALT:
105842421Syokota				state &= ~ALTS1;
105942421Syokota				break;
106042421Syokota			case RALT:
106142421Syokota				state &= ~ALTS2;
106242421Syokota				break;
106342421Syokota			case ASH:
106442421Syokota				state &= ~AGRS1;
106542421Syokota				break;
106642421Syokota			case META:
106742421Syokota				state &= ~METAS1;
106842421Syokota				break;
106942421Syokota			case NLK:
107042421Syokota				state &= ~NLKDOWN;
107142421Syokota				break;
107242421Syokota			case CLK:
107342421Syokota#ifndef PC98
107442421Syokota				state &= ~CLKDOWN;
107542421Syokota#else
107642421Syokota				state &= ~CLKED;
107742421Syokota				i = state & LOCK_MASK;
107842421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
107942421Syokota							       (caddr_t)&i);
108042421Syokota#endif
108142421Syokota				break;
108242421Syokota			case SLK:
108342421Syokota				state &= ~SLKDOWN;
108442421Syokota				break;
108542421Syokota			case ALK:
108642421Syokota				state &= ~ALKDOWN;
108742421Syokota				break;
108842421Syokota			}
108942421Syokota			*shiftstate = state;
109042421Syokota			return (SPCLKEY | RELKEY | action);
109142421Syokota		}
109242421Syokota		/* release events of regular keys are not reported */
109342421Syokota		return NOKEY;
109442421Syokota	} else {	/* make: key pressed */
109542421Syokota		if (key->spcl & (0x80 >> i)) {
109642421Syokota			/* special keys */
109742421Syokota			switch (action) {
109842421Syokota			/* LOCKING KEYS */
109942421Syokota			case NLK:
110042421Syokota				set_lockkey_state(kbd, state, NLK);
110142421Syokota				break;
110242421Syokota			case CLK:
110342421Syokota#ifndef PC98
110442421Syokota				set_lockkey_state(kbd, state, CLK);
110542421Syokota#else
110642421Syokota				state |= CLKED;
110742421Syokota				i = state & LOCK_MASK;
110842421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
110942421Syokota							       (caddr_t)&i);
111042421Syokota#endif
111142421Syokota				break;
111242421Syokota			case SLK:
111342421Syokota				set_lockkey_state(kbd, state, SLK);
111442421Syokota				break;
111542421Syokota			case ALK:
111642421Syokota				set_lockkey_state(kbd, state, ALK);
111742421Syokota				break;
111842421Syokota			/* NON-LOCKING KEYS */
111942421Syokota			case SPSC: case RBT:  case SUSP: case STBY:
112042421Syokota			case DBG:  case NEXT:
112142421Syokota				*accents = 0;
112242421Syokota				break;
112342421Syokota			case BTAB:
112442421Syokota				*accents = 0;
112542421Syokota				action |= BKEY;
112642421Syokota				break;
112742421Syokota			case LSH:
112842421Syokota				state |= SHIFTS1;
112942421Syokota				break;
113042421Syokota			case RSH:
113142421Syokota				state |= SHIFTS2;
113242421Syokota				break;
113342421Syokota			case LCTR:
113442421Syokota				state |= CTLS1;
113542421Syokota				break;
113642421Syokota			case RCTR:
113742421Syokota				state |= CTLS2;
113842421Syokota				break;
113942421Syokota			case LALT:
114042421Syokota				state |= ALTS1;
114142421Syokota				break;
114242421Syokota			case RALT:
114342421Syokota				state |= ALTS2;
114442421Syokota				break;
114542421Syokota			case ASH:
114642421Syokota				state |= AGRS1;
114742421Syokota				break;
114842421Syokota			case META:
114942421Syokota				state |= METAS1;
115042421Syokota				break;
115142421Syokota			default:
115242421Syokota				/* is this an accent (dead) key? */
115342421Syokota				if (action >= F_ACC && action <= L_ACC) {
115442421Syokota					action = save_accent_key(kbd, action,
115542421Syokota								 accents);
115642421Syokota					switch (action) {
115742421Syokota					case NOKEY:
115842421Syokota					case ERRKEY:
115942421Syokota						return action;
116042421Syokota					default:
116142421Syokota						if (state & METAS)
116242421Syokota							return (action | MKEY);
116342421Syokota						else
116442421Syokota							return action;
116542421Syokota					}
116642421Syokota					/* NOT REACHED */
116742421Syokota				}
116842421Syokota				/* other special keys */
116942421Syokota				if (*accents > 0) {
117042421Syokota					*accents = 0;
117142421Syokota					return ERRKEY;
117242421Syokota				}
117342421Syokota				if (action >= F_FN && action <= L_FN)
117442421Syokota					action |= FKEY;
117542421Syokota				/* XXX: return fkey string for the FKEY? */
117642421Syokota			}
117742421Syokota			*shiftstate = state;
117842421Syokota			return (SPCLKEY | action);
117942421Syokota		} else {
118042421Syokota			/* regular keys */
118142421Syokota			if (*accents > 0) {
118242421Syokota				/* make an accented char */
118342421Syokota				action = make_accent_char(kbd, action, accents);
118442421Syokota				if (action == ERRKEY)
118542421Syokota					return action;
118642421Syokota			}
118742421Syokota			if (state & METAS)
118842421Syokota				action |= MKEY;
118942421Syokota			return action;
119042421Syokota		}
119142421Syokota	}
119242421Syokota	/* NOT REACHED */
119342421Syokota}
1194