kbd.c revision 78161
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 *
2650477Speter * $FreeBSD: head/sys/dev/kbd/kbd.c 78161 2001-06-13 10:58:39Z peter $
2742421Syokota */
2842421Syokota
2942421Syokota#include "opt_kbd.h"
3042421Syokota
3142421Syokota#include <sys/param.h>
3242421Syokota#include <sys/systm.h>
3342421Syokota#include <sys/kernel.h>
3442421Syokota#include <sys/malloc.h>
3542421Syokota#include <sys/conf.h>
3642421Syokota#include <sys/tty.h>
3742421Syokota#include <sys/poll.h>
3842421Syokota#include <sys/vnode.h>
3942421Syokota#include <sys/uio.h>
4042421Syokota
4166834Sphk#include <sys/kbio.h>
4242421Syokota
4342421Syokota#include <dev/kbd/kbdreg.h>
4442421Syokota
4550154Syokota#define KBD_INDEX(dev)	minor(dev)
4650154Syokota
4750154Syokotatypedef struct genkbd_softc {
4850154Syokota	int		gkb_flags;	/* flag/status bits */
4950154Syokota#define KB_ASLEEP	(1 << 0)
5050154Syokota	struct clist	gkb_q;		/* input queue */
5150154Syokota	struct selinfo	gkb_rsel;
5250154Syokota} genkbd_softc_t;
5350154Syokota
5460938Sjakestatic	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
5554545Syokota 	SLIST_HEAD_INITIALIZER(keyboard_drivers);
5654545Syokota
5778161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t);
5878161Speter
5942421Syokota/* local arrays */
6042421Syokota
6142421Syokota/*
6242421Syokota * We need at least one entry each in order to initialize a keyboard
6342421Syokota * for the kernel console.  The arrays will be increased dynamically
6442421Syokota * when necessary.
6542421Syokota */
6642564Syokota
6742564Syokotastatic int		keyboards = 1;
6842421Syokotastatic keyboard_t	*kbd_ini;
6942564Syokotastatic keyboard_t	**keyboard = &kbd_ini;
7042421Syokotastatic keyboard_switch_t *kbdsw_ini;
7142421Syokota       keyboard_switch_t **kbdsw = &kbdsw_ini;
7242421Syokota
7342421Syokota#define ARRAY_DELTA	4
7442421Syokota
7544628Syokotastatic int
7642421Syokotakbd_realloc_array(void)
7742421Syokota{
7842421Syokota	keyboard_t **new_kbd;
7942421Syokota	keyboard_switch_t **new_kbdsw;
8042421Syokota	int newsize;
8142421Syokota	int s;
8242421Syokota
8342421Syokota	s = spltty();
8442421Syokota	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
8569781Sdwmalone	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO);
8644628Syokota	if (new_kbd == NULL) {
8744628Syokota		splx(s);
8844628Syokota		return ENOMEM;
8944628Syokota	}
9069781Sdwmalone	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF,
9169781Sdwmalone			    M_NOWAIT|M_ZERO);
9244628Syokota	if (new_kbdsw == NULL) {
9344628Syokota		free(new_kbd, M_DEVBUF);
9444628Syokota		splx(s);
9544628Syokota		return ENOMEM;
9644628Syokota	}
9742421Syokota	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
9842421Syokota	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
9942421Syokota	if (keyboards > 1) {
10042421Syokota		free(keyboard, M_DEVBUF);
10142421Syokota		free(kbdsw, M_DEVBUF);
10242421Syokota	}
10342421Syokota	keyboard = new_kbd;
10442421Syokota	kbdsw = new_kbdsw;
10542421Syokota	keyboards = newsize;
10642421Syokota	splx(s);
10742421Syokota
10842421Syokota	if (bootverbose)
10942421Syokota		printf("kbd: new array size %d\n", keyboards);
11044628Syokota
11144628Syokota	return 0;
11242421Syokota}
11342421Syokota
11442421Syokota/*
11542421Syokota * Low-level keyboard driver functions
11642421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
11742421Syokota * driver, call these functions to initialize the keyboard_t structure
11842421Syokota * and register it to the virtual keyboard driver `kbd'.
11942421Syokota */
12042421Syokota
12142421Syokota/* initialize the keyboard_t structure */
12242421Syokotavoid
12342421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
12442421Syokota		int port, int port_size)
12542421Syokota{
12642421Syokota	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
12742421Syokota	kbd->kb_name = name;
12842421Syokota	kbd->kb_type = type;
12942421Syokota	kbd->kb_unit = unit;
13044628Syokota	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
13142421Syokota	kbd->kb_led = 0;		/* unknown */
13242421Syokota	kbd->kb_io_base = port;
13342421Syokota	kbd->kb_io_size = port_size;
13442421Syokota	kbd->kb_data = NULL;
13542421Syokota	kbd->kb_keymap = NULL;
13642421Syokota	kbd->kb_accentmap = NULL;
13742421Syokota	kbd->kb_fkeytab = NULL;
13842421Syokota	kbd->kb_fkeytab_size = 0;
13944628Syokota	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
14044628Syokota	kbd->kb_delay2 = KB_DELAY2;
14154382Syokota	kbd->kb_count = 0L;
14242421Syokota}
14342421Syokota
14442421Syokotavoid
14542421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
14642421Syokota	     fkeytab_t *fkeymap, int fkeymap_size)
14742421Syokota{
14842421Syokota	kbd->kb_keymap = keymap;
14942421Syokota	kbd->kb_accentmap = accmap;
15042421Syokota	kbd->kb_fkeytab = fkeymap;
15142421Syokota	kbd->kb_fkeytab_size = fkeymap_size;
15242421Syokota}
15342421Syokota
15454545Syokota/* declare a new keyboard driver */
15554545Syokotaint
15654545Syokotakbd_add_driver(keyboard_driver_t *driver)
15754545Syokota{
15854545Syokota	if (SLIST_NEXT(driver, link))
15954545Syokota		return EINVAL;
16054545Syokota	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
16154545Syokota	return 0;
16254545Syokota}
16354545Syokota
16454545Syokotaint
16554545Syokotakbd_delete_driver(keyboard_driver_t *driver)
16654545Syokota{
16760938Sjake	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
16854545Syokota	SLIST_NEXT(driver, link) = NULL;
16954545Syokota	return 0;
17054545Syokota}
17154545Syokota
17242421Syokota/* register a keyboard and associate it with a function table */
17342421Syokotaint
17442421Syokotakbd_register(keyboard_t *kbd)
17542421Syokota{
17647295Syokota	const keyboard_driver_t **list;
17747295Syokota	const keyboard_driver_t *p;
17842421Syokota	int index;
17942421Syokota
18042421Syokota	for (index = 0; index < keyboards; ++index) {
18142421Syokota		if (keyboard[index] == NULL)
18242421Syokota			break;
18342421Syokota	}
18444628Syokota	if (index >= keyboards) {
18544628Syokota		if (kbd_realloc_array())
18644628Syokota			return -1;
18744628Syokota	}
18842421Syokota
18942421Syokota	kbd->kb_index = index;
19042421Syokota	KBD_UNBUSY(kbd);
19142421Syokota	KBD_VALID(kbd);
19242421Syokota	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
19342421Syokota	kbd->kb_token = NULL;
19442421Syokota	kbd->kb_callback.kc_func = NULL;
19542421Syokota	kbd->kb_callback.kc_arg = NULL;
19642421Syokota
19754545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
19854545Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
19954545Syokota			keyboard[index] = kbd;
20054545Syokota			kbdsw[index] = p->kbdsw;
20154545Syokota			return index;
20254545Syokota		}
20354545Syokota	}
20478161Speter	SET_FOREACH(list, kbddriver_set) {
20578161Speter		p = *list;
20642421Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
20742421Syokota			keyboard[index] = kbd;
20842421Syokota			kbdsw[index] = p->kbdsw;
20942421Syokota			return index;
21042421Syokota		}
21142421Syokota	}
21242421Syokota
21342421Syokota	return -1;
21442421Syokota}
21542421Syokota
21642421Syokotaint
21742421Syokotakbd_unregister(keyboard_t *kbd)
21842421Syokota{
21942421Syokota	int error;
22042421Syokota	int s;
22142421Syokota
22242421Syokota	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
22342421Syokota		return ENOENT;
22442421Syokota	if (keyboard[kbd->kb_index] != kbd)
22542421Syokota		return ENOENT;
22642421Syokota
22742421Syokota	s = spltty();
22842421Syokota	if (KBD_IS_BUSY(kbd)) {
22942421Syokota		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
23042421Syokota						    kbd->kb_callback.kc_arg);
23142421Syokota		if (error) {
23242421Syokota			splx(s);
23342421Syokota			return error;
23442421Syokota		}
23542421Syokota		if (KBD_IS_BUSY(kbd)) {
23642421Syokota			splx(s);
23742421Syokota			return EBUSY;
23842421Syokota		}
23942421Syokota	}
24042421Syokota	KBD_INVALID(kbd);
24142421Syokota	keyboard[kbd->kb_index] = NULL;
24242421Syokota	kbdsw[kbd->kb_index] = NULL;
24342421Syokota
24442421Syokota	splx(s);
24542421Syokota	return 0;
24642421Syokota}
24742421Syokota
24842421Syokota/* find a funciton table by the driver name */
24942421Syokotakeyboard_switch_t
25042421Syokota*kbd_get_switch(char *driver)
25142421Syokota{
25247295Syokota	const keyboard_driver_t **list;
25347295Syokota	const keyboard_driver_t *p;
25442421Syokota
25554545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
25654545Syokota		if (strcmp(p->name, driver) == 0)
25754545Syokota			return p->kbdsw;
25854545Syokota	}
25978161Speter	SET_FOREACH(list, kbddriver_set) {
26078161Speter		p = *list;
26142421Syokota		if (strcmp(p->name, driver) == 0)
26242421Syokota			return p->kbdsw;
26342421Syokota	}
26442421Syokota
26542421Syokota	return NULL;
26642421Syokota}
26742421Syokota
26842421Syokota/*
26942421Syokota * Keyboard client functions
27042421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard
27142421Syokota * cdev driver, use these functions to claim and release a keyboard for
27242421Syokota * exclusive use.
27342421Syokota */
27442421Syokota
27542421Syokota/* find the keyboard specified by a driver name and a unit number */
27642421Syokotaint
27742421Syokotakbd_find_keyboard(char *driver, int unit)
27842421Syokota{
27942421Syokota	int i;
28042421Syokota
28142421Syokota	for (i = 0; i < keyboards; ++i) {
28242421Syokota		if (keyboard[i] == NULL)
28342421Syokota			continue;
28442421Syokota		if (!KBD_IS_VALID(keyboard[i]))
28542421Syokota			continue;
28642421Syokota		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
28742421Syokota			continue;
28842421Syokota		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
28942421Syokota			continue;
29042421Syokota		return i;
29142421Syokota	}
29242421Syokota	return -1;
29342421Syokota}
29442421Syokota
29542421Syokota/* allocate a keyboard */
29642421Syokotaint
29742421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
29842421Syokota	     void *arg)
29942421Syokota{
30042421Syokota	int index;
30142421Syokota	int s;
30242421Syokota
30342421Syokota	if (func == NULL)
30442421Syokota		return -1;
30542421Syokota
30642421Syokota	s = spltty();
30742421Syokota	index = kbd_find_keyboard(driver, unit);
30842421Syokota	if (index >= 0) {
30942421Syokota		if (KBD_IS_BUSY(keyboard[index])) {
31042421Syokota			splx(s);
31142421Syokota			return -1;
31242421Syokota		}
31342421Syokota		keyboard[index]->kb_token = id;
31442421Syokota		KBD_BUSY(keyboard[index]);
31542421Syokota		keyboard[index]->kb_callback.kc_func = func;
31642421Syokota		keyboard[index]->kb_callback.kc_arg = arg;
31742421Syokota		(*kbdsw[index]->clear_state)(keyboard[index]);
31842421Syokota	}
31942421Syokota	splx(s);
32042421Syokota	return index;
32142421Syokota}
32242421Syokota
32342421Syokotaint
32442421Syokotakbd_release(keyboard_t *kbd, void *id)
32542421Syokota{
32642421Syokota	int error;
32742421Syokota	int s;
32842421Syokota
32942421Syokota	s = spltty();
33042421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
33142421Syokota		error = EINVAL;
33242421Syokota	} else if (kbd->kb_token != id) {
33342421Syokota		error = EPERM;
33442421Syokota	} else {
33542421Syokota		kbd->kb_token = NULL;
33642421Syokota		KBD_UNBUSY(kbd);
33742421Syokota		kbd->kb_callback.kc_func = NULL;
33842421Syokota		kbd->kb_callback.kc_arg = NULL;
33942421Syokota		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
34042421Syokota		error = 0;
34142421Syokota	}
34242421Syokota	splx(s);
34342421Syokota	return error;
34442421Syokota}
34542421Syokota
34642421Syokotaint
34742421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
34842421Syokota		    void *arg)
34942421Syokota{
35042421Syokota	int error;
35142421Syokota	int s;
35242421Syokota
35342421Syokota	s = spltty();
35442421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
35542421Syokota		error = EINVAL;
35642421Syokota	} else if (kbd->kb_token != id) {
35742421Syokota		error = EPERM;
35842421Syokota	} else if (func == NULL) {
35942421Syokota		error = EINVAL;
36042421Syokota	} else {
36142421Syokota		kbd->kb_callback.kc_func = func;
36242421Syokota		kbd->kb_callback.kc_arg = arg;
36342421Syokota		error = 0;
36442421Syokota	}
36542421Syokota	splx(s);
36642421Syokota	return error;
36742421Syokota}
36842421Syokota
36942421Syokota/* get a keyboard structure */
37042421Syokotakeyboard_t
37142421Syokota*kbd_get_keyboard(int index)
37242421Syokota{
37342421Syokota	if ((index < 0) || (index >= keyboards))
37442421Syokota		return NULL;
37550154Syokota	if (keyboard[index] == NULL)
37650154Syokota		return NULL;
37742421Syokota	if (!KBD_IS_VALID(keyboard[index]))
37842421Syokota		return NULL;
37942421Syokota	return keyboard[index];
38042421Syokota}
38142421Syokota
38242421Syokota/*
38342421Syokota * The back door for the console driver; configure keyboards
38442421Syokota * This function is for the kernel console to initialize keyboards
38542421Syokota * at very early stage.
38642421Syokota */
38742421Syokota
38842421Syokotaint
38942421Syokotakbd_configure(int flags)
39042421Syokota{
39147295Syokota	const keyboard_driver_t **list;
39247295Syokota	const keyboard_driver_t *p;
39342421Syokota
39454545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
39554545Syokota		if (p->configure != NULL)
39654545Syokota			(*p->configure)(flags);
39754545Syokota	}
39878161Speter	SET_FOREACH(list, kbddriver_set) {
39978161Speter		p = *list;
40042421Syokota		if (p->configure != NULL)
40142421Syokota			(*p->configure)(flags);
40242421Syokota	}
40342421Syokota
40442421Syokota	return 0;
40542421Syokota}
40642421Syokota
40742421Syokota#ifdef KBD_INSTALL_CDEV
40842421Syokota
40942421Syokota/*
41042421Syokota * Virtual keyboard cdev driver functions
41142421Syokota * The virtual keyboard driver dispatches driver functions to
41242421Syokota * appropriate subdrivers.
41342421Syokota */
41442421Syokota
41542421Syokota#define KBD_UNIT(dev)	minor(dev)
41642421Syokota
41750154Syokotastatic d_open_t		genkbdopen;
41850154Syokotastatic d_close_t	genkbdclose;
41950154Syokotastatic d_read_t		genkbdread;
42050154Syokotastatic d_write_t	genkbdwrite;
42150154Syokotastatic d_ioctl_t	genkbdioctl;
42250154Syokotastatic d_poll_t		genkbdpoll;
42342421Syokota
42442421Syokota#define CDEV_MAJOR	112
42542421Syokota
42642421Syokotastatic struct cdevsw kbd_cdevsw = {
42750154Syokota	/* open */	genkbdopen,
42850154Syokota	/* close */	genkbdclose,
42950154Syokota	/* read */	genkbdread,
43050154Syokota	/* write */	genkbdwrite,
43150154Syokota	/* ioctl */	genkbdioctl,
43250154Syokota	/* poll */	genkbdpoll,
43350154Syokota	/* mmap */	nommap,
43447625Sphk	/* strategy */	nostrategy,
43547625Sphk	/* name */	"kbd",
43647625Sphk	/* maj */	CDEV_MAJOR,
43747625Sphk	/* dump */	nodump,
43847625Sphk	/* psize */	nopsize,
43947625Sphk	/* flags */	0,
44042421Syokota};
44142421Syokota
44242421Syokotaint
44350154Syokotakbd_attach(keyboard_t *kbd)
44442421Syokota{
44550154Syokota	dev_t dev;
44642421Syokota
44742421Syokota	if (kbd->kb_index >= keyboards)
44842421Syokota		return EINVAL;
44942421Syokota	if (keyboard[kbd->kb_index] != kbd)
45042421Syokota		return EINVAL;
45142421Syokota
45250154Syokota	dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
45350154Syokota		       "kbd%r", kbd->kb_index);
45450154Syokota	if (dev->si_drv1 == NULL)
45550154Syokota		dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
45650154Syokota				      M_WAITOK);
45750154Syokota	bzero(dev->si_drv1, sizeof(genkbd_softc_t));
45842421Syokota
45942421Syokota	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
46042421Syokota	return 0;
46142421Syokota}
46242421Syokota
46342421Syokotaint
46450154Syokotakbd_detach(keyboard_t *kbd)
46542421Syokota{
46654545Syokota	dev_t dev;
46754545Syokota
46842421Syokota	if (kbd->kb_index >= keyboards)
46942421Syokota		return EINVAL;
47042421Syokota	if (keyboard[kbd->kb_index] != kbd)
47142421Syokota		return EINVAL;
47242421Syokota
47354545Syokota	dev = makedev(kbd_cdevsw.d_maj, kbd->kb_index);
47454545Syokota	if (dev->si_drv1)
47554545Syokota		free(dev->si_drv1, M_DEVBUF);
47654545Syokota	destroy_dev(dev);
47754545Syokota
47842421Syokota	return 0;
47942421Syokota}
48042421Syokota
48142421Syokota/*
48242421Syokota * Generic keyboard cdev driver functions
48342421Syokota * Keyboard subdrivers may call these functions to implement common
48442421Syokota * driver functions.
48542421Syokota */
48642421Syokota
48742421Syokota#define KB_QSIZE	512
48842421Syokota#define KB_BUFSIZE	64
48942421Syokota
49042421Syokotastatic kbd_callback_func_t genkbd_event;
49142421Syokota
49250154Syokotastatic int
49350154Syokotagenkbdopen(dev_t dev, int mode, int flag, struct proc *p)
49442421Syokota{
49550154Syokota	keyboard_t *kbd;
49650154Syokota	genkbd_softc_t *sc;
49742421Syokota	int s;
49842421Syokota	int i;
49942421Syokota
50042421Syokota	s = spltty();
50150154Syokota	sc = dev->si_drv1;
50250154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
50350154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
50442421Syokota		splx(s);
50542421Syokota		return ENXIO;
50642421Syokota	}
50742421Syokota	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
50842421Syokota			 genkbd_event, (void *)sc);
50942421Syokota	if (i < 0) {
51042421Syokota		splx(s);
51142421Syokota		return EBUSY;
51242421Syokota	}
51342421Syokota	/* assert(i == kbd->kb_index) */
51442421Syokota	/* assert(kbd == kbd_get_keyboard(i)) */
51542421Syokota
51642421Syokota	/*
51742421Syokota	 * NOTE: even when we have successfully claimed a keyboard,
51842421Syokota	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
51942421Syokota	 */
52042421Syokota
52142421Syokota#if 0
52242421Syokota	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
52342421Syokota#endif
52442421Syokota	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
52542421Syokota	sc->gkb_rsel.si_flags = 0;
52642421Syokota	sc->gkb_rsel.si_pid = 0;
52742421Syokota	splx(s);
52842421Syokota
52942421Syokota	return 0;
53042421Syokota}
53142421Syokota
53250154Syokotastatic int
53350154Syokotagenkbdclose(dev_t dev, int mode, int flag, struct proc *p)
53442421Syokota{
53550154Syokota	keyboard_t *kbd;
53650154Syokota	genkbd_softc_t *sc;
53742421Syokota	int s;
53842421Syokota
53942421Syokota	/*
54042421Syokota	 * NOTE: the device may have already become invalid.
54150154Syokota	 * kbd == NULL || !KBD_IS_VALID(kbd)
54242421Syokota	 */
54342421Syokota	s = spltty();
54450154Syokota	sc = dev->si_drv1;
54550154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
54650154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
54750154Syokota		/* XXX: we shall be forgiving and don't report error... */
54850154Syokota	} else {
54950154Syokota		kbd_release(kbd, (void *)sc);
55042421Syokota#if 0
55150154Syokota		clist_free_cblocks(&sc->gkb_q);
55242421Syokota#endif
55350154Syokota	}
55442421Syokota	splx(s);
55542421Syokota	return 0;
55642421Syokota}
55742421Syokota
55850154Syokotastatic int
55950154Syokotagenkbdread(dev_t dev, struct uio *uio, int flag)
56042421Syokota{
56150154Syokota	keyboard_t *kbd;
56250154Syokota	genkbd_softc_t *sc;
56342421Syokota	u_char buffer[KB_BUFSIZE];
56442421Syokota	int len;
56542421Syokota	int error;
56642421Syokota	int s;
56742421Syokota
56842421Syokota	/* wait for input */
56942421Syokota	s = spltty();
57050154Syokota	sc = dev->si_drv1;
57150154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
57250154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
57350154Syokota		splx(s);
57450154Syokota		return ENXIO;
57550154Syokota	}
57642421Syokota	while (sc->gkb_q.c_cc == 0) {
57742421Syokota		if (flag & IO_NDELAY) {
57842421Syokota			splx(s);
57942421Syokota			return EWOULDBLOCK;
58042421Syokota		}
58142421Syokota		sc->gkb_flags |= KB_ASLEEP;
58242421Syokota		error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
58350154Syokota		kbd = kbd_get_keyboard(KBD_INDEX(dev));
58450154Syokota		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
58550154Syokota			splx(s);
58650154Syokota			return ENXIO;	/* our keyboard has gone... */
58750154Syokota		}
58842421Syokota		if (error) {
58942421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
59042421Syokota			splx(s);
59142421Syokota			return error;
59242421Syokota		}
59342421Syokota	}
59442421Syokota	splx(s);
59542421Syokota
59642421Syokota	/* copy as much input as possible */
59742421Syokota	error = 0;
59842421Syokota	while (uio->uio_resid > 0) {
59942421Syokota		len = imin(uio->uio_resid, sizeof(buffer));
60042421Syokota		len = q_to_b(&sc->gkb_q, buffer, len);
60142421Syokota		if (len <= 0)
60242421Syokota			break;
60342421Syokota		error = uiomove(buffer, len, uio);
60442421Syokota		if (error)
60542421Syokota			break;
60642421Syokota	}
60742421Syokota
60842421Syokota	return error;
60942421Syokota}
61042421Syokota
61150154Syokotastatic int
61250154Syokotagenkbdwrite(dev_t dev, struct uio *uio, int flag)
61342421Syokota{
61450154Syokota	keyboard_t *kbd;
61550154Syokota
61650154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
61750154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
61842421Syokota		return ENXIO;
61942421Syokota	return ENODEV;
62042421Syokota}
62142421Syokota
62250154Syokotastatic int
62350154Syokotagenkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
62442421Syokota{
62550154Syokota	keyboard_t *kbd;
62642421Syokota	int error;
62742421Syokota
62850154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
62950154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
63042421Syokota		return ENXIO;
63142421Syokota	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
63242421Syokota	if (error == ENOIOCTL)
63342421Syokota		error = ENODEV;
63442421Syokota	return error;
63542421Syokota}
63642421Syokota
63750154Syokotastatic int
63850154Syokotagenkbdpoll(dev_t dev, int events, struct proc *p)
63942421Syokota{
64050154Syokota	keyboard_t *kbd;
64150154Syokota	genkbd_softc_t *sc;
64242421Syokota	int revents;
64342421Syokota	int s;
64442421Syokota
64542421Syokota	revents = 0;
64642421Syokota	s = spltty();
64750154Syokota	sc = dev->si_drv1;
64850154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
64950154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
65050154Syokota		revents =  POLLHUP;	/* the keyboard has gone */
65150154Syokota	} else if (events & (POLLIN | POLLRDNORM)) {
65250154Syokota		if (sc->gkb_q.c_cc > 0)
65350154Syokota			revents = events & (POLLIN | POLLRDNORM);
65442421Syokota		else
65542421Syokota			selrecord(p, &sc->gkb_rsel);
65642421Syokota	}
65742421Syokota	splx(s);
65842421Syokota	return revents;
65942421Syokota}
66042421Syokota
66142421Syokotastatic int
66242421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg)
66342421Syokota{
66442421Syokota	genkbd_softc_t *sc;
66542421Syokota	size_t len;
66642421Syokota	u_char *cp;
66742421Syokota	int mode;
66842421Syokota	int c;
66942421Syokota
67042421Syokota	/* assert(KBD_IS_VALID(kbd)) */
67142421Syokota	sc = (genkbd_softc_t *)arg;
67242421Syokota
67342421Syokota	switch (event) {
67442421Syokota	case KBDIO_KEYINPUT:
67542421Syokota		break;
67642421Syokota	case KBDIO_UNLOADING:
67742421Syokota		/* the keyboard is going... */
67842421Syokota		kbd_release(kbd, (void *)sc);
67950154Syokota		if (sc->gkb_flags & KB_ASLEEP) {
68050154Syokota			sc->gkb_flags &= ~KB_ASLEEP;
68150154Syokota			wakeup((caddr_t)sc);
68250154Syokota		}
68350154Syokota		selwakeup(&sc->gkb_rsel);
68442421Syokota		return 0;
68542421Syokota	default:
68642421Syokota		return EINVAL;
68742421Syokota	}
68842421Syokota
68942421Syokota	/* obtain the current key input mode */
69042421Syokota	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
69142421Syokota		mode = K_XLATE;
69242421Syokota
69342421Syokota	/* read all pending input */
69442421Syokota	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
69542421Syokota		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
69642421Syokota		if (c == NOKEY)
69742421Syokota			continue;
69842421Syokota		if (c == ERRKEY)	/* XXX: ring bell? */
69942421Syokota			continue;
70042421Syokota		if (!KBD_IS_BUSY(kbd))
70142421Syokota			/* the device is not open, discard the input */
70242421Syokota			continue;
70342421Syokota
70442421Syokota		/* store the byte as is for K_RAW and K_CODE modes */
70542421Syokota		if (mode != K_XLATE) {
70642421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
70742421Syokota			continue;
70842421Syokota		}
70942421Syokota
71042421Syokota		/* K_XLATE */
71142421Syokota		if (c & RELKEY)	/* key release is ignored */
71242421Syokota			continue;
71342421Syokota
71442421Syokota		/* process special keys; most of them are just ignored... */
71542421Syokota		if (c & SPCLKEY) {
71642421Syokota			switch (KEYCHAR(c)) {
71754382Syokota			default:
71842421Syokota				/* ignore them... */
71942421Syokota				continue;
72042421Syokota			case BTAB:	/* a backtab: ESC [ Z */
72142421Syokota				putc(0x1b, &sc->gkb_q);
72242421Syokota				putc('[', &sc->gkb_q);
72342421Syokota				putc('Z', &sc->gkb_q);
72442421Syokota				continue;
72542421Syokota			}
72642421Syokota		}
72742421Syokota
72842421Syokota		/* normal chars, normal chars with the META, function keys */
72942421Syokota		switch (KEYFLAGS(c)) {
73042421Syokota		case 0:			/* a normal char */
73142421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
73242421Syokota			break;
73342421Syokota		case MKEY:		/* the META flag: prepend ESC */
73442421Syokota			putc(0x1b, &sc->gkb_q);
73542421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
73642421Syokota			break;
73742421Syokota		case FKEY | SPCLKEY:	/* a function key, return string */
73842421Syokota			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
73942421Syokota							KEYCHAR(c), &len);
74042421Syokota			if (cp != NULL) {
74142421Syokota				while (len-- >  0)
74242421Syokota					putc(*cp++, &sc->gkb_q);
74342421Syokota			}
74442421Syokota			break;
74542421Syokota		}
74642421Syokota	}
74742421Syokota
74842421Syokota	/* wake up sleeping/polling processes */
74942421Syokota	if (sc->gkb_q.c_cc > 0) {
75042421Syokota		if (sc->gkb_flags & KB_ASLEEP) {
75142421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
75242421Syokota			wakeup((caddr_t)sc);
75342421Syokota		}
75442421Syokota		selwakeup(&sc->gkb_rsel);
75542421Syokota	}
75642421Syokota
75742421Syokota	return 0;
75842421Syokota}
75942421Syokota
76042421Syokota#endif /* KBD_INSTALL_CDEV */
76142421Syokota
76242421Syokota/*
76342421Syokota * Generic low-level keyboard functions
76442421Syokota * The low-level functions in the keyboard subdriver may use these
76542421Syokota * functions.
76642421Syokota */
76742421Syokota
76842421Syokotaint
76942421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
77042421Syokota{
77142421Syokota	keyarg_t *keyp;
77242421Syokota	fkeyarg_t *fkeyp;
77342421Syokota	int s;
77442421Syokota	int i;
77542421Syokota
77642421Syokota	s = spltty();
77742421Syokota	switch (cmd) {
77842421Syokota
77942421Syokota	case KDGKBINFO:		/* get keyboard information */
78042421Syokota		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
78142421Syokota		i = imin(strlen(kbd->kb_name) + 1,
78242421Syokota			 sizeof(((keyboard_info_t *)arg)->kb_name));
78342421Syokota		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
78442421Syokota		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
78542421Syokota		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
78642421Syokota		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
78742421Syokota		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
78842421Syokota		break;
78942421Syokota
79042421Syokota	case KDGKBTYPE:		/* get keyboard type */
79142421Syokota		*(int *)arg = kbd->kb_type;
79242421Syokota		break;
79342421Syokota
79454543Syokota	case KDGETREPEAT:	/* get keyboard repeat rate */
79554543Syokota		((int *)arg)[0] = kbd->kb_delay1;
79654543Syokota		((int *)arg)[1] = kbd->kb_delay2;
79754543Syokota		break;
79854543Syokota
79942421Syokota	case GIO_KEYMAP:	/* get keyboard translation table */
80042421Syokota		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
80142421Syokota		break;
80242421Syokota	case PIO_KEYMAP:	/* set keyboard translation table */
80344628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
80442421Syokota		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
80542421Syokota		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
80642421Syokota		break;
80744628Syokota#else
80844628Syokota		splx(s);
80944628Syokota		return ENODEV;
81044628Syokota#endif
81142421Syokota
81242421Syokota	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
81342421Syokota		keyp = (keyarg_t *)arg;
81442421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
81542421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
81642421Syokota			splx(s);
81742421Syokota			return EINVAL;
81842421Syokota		}
81942573Syokota		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
82042421Syokota		      sizeof(keyp->key));
82142421Syokota		break;
82242421Syokota	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
82344628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
82442421Syokota		keyp = (keyarg_t *)arg;
82542421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
82642421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
82742421Syokota			splx(s);
82842421Syokota			return EINVAL;
82942421Syokota		}
83042573Syokota		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
83142421Syokota		      sizeof(keyp->key));
83242421Syokota		break;
83344628Syokota#else
83444628Syokota		splx(s);
83544628Syokota		return ENODEV;
83644628Syokota#endif
83742421Syokota
83842421Syokota	case GIO_DEADKEYMAP:	/* get accent key translation table */
83942421Syokota		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
84042421Syokota		break;
84142421Syokota	case PIO_DEADKEYMAP:	/* set accent key translation table */
84244628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
84342421Syokota		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
84442421Syokota		break;
84544628Syokota#else
84644628Syokota		splx(s);
84744628Syokota		return ENODEV;
84844628Syokota#endif
84942421Syokota
85042421Syokota	case GETFKEY:		/* get functionkey string */
85142421Syokota		fkeyp = (fkeyarg_t *)arg;
85242421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
85342421Syokota			splx(s);
85442421Syokota			return EINVAL;
85542421Syokota		}
85642421Syokota		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
85742421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
85842421Syokota		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
85942421Syokota		break;
86042421Syokota	case SETFKEY:		/* set functionkey string */
86144628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
86242421Syokota		fkeyp = (fkeyarg_t *)arg;
86342421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
86442421Syokota			splx(s);
86542421Syokota			return EINVAL;
86642421Syokota		}
86742421Syokota		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
86842421Syokota		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
86942421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
87042421Syokota		break;
87144628Syokota#else
87244628Syokota		splx(s);
87344628Syokota		return ENODEV;
87444628Syokota#endif
87542421Syokota
87642421Syokota	default:
87742421Syokota		splx(s);
87842421Syokota		return ENOIOCTL;
87942421Syokota	}
88042421Syokota
88142421Syokota	splx(s);
88242421Syokota	return 0;
88342421Syokota}
88442421Syokota
88542421Syokota/* get a pointer to the string associated with the given function key */
88642421Syokotau_char
88742421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
88842421Syokota{
88942421Syokota	if (kbd == NULL)
89042421Syokota		return NULL;
89142421Syokota	fkey -= F_FN;
89242421Syokota	if (fkey > kbd->kb_fkeytab_size)
89342421Syokota		return NULL;
89442421Syokota	*len = kbd->kb_fkeytab[fkey].len;
89542421Syokota	return kbd->kb_fkeytab[fkey].str;
89642421Syokota}
89742421Syokota
89842421Syokota/* diagnostic dump */
89942421Syokotastatic char
90042421Syokota*get_kbd_type_name(int type)
90142421Syokota{
90242421Syokota	static struct {
90342421Syokota		int type;
90442421Syokota		char *name;
90542421Syokota	} name_table[] = {
90642421Syokota		{ KB_84,	"AT 84" },
90742421Syokota		{ KB_101,	"AT 101/102" },
90842421Syokota		{ KB_OTHER,	"generic" },
90942421Syokota	};
91042421Syokota	int i;
91142421Syokota
91242421Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
91342421Syokota		if (type == name_table[i].type)
91442421Syokota			return name_table[i].name;
91542421Syokota	}
91642421Syokota	return "unknown";
91742421Syokota}
91842421Syokota
91942421Syokotavoid
92042421Syokotagenkbd_diag(keyboard_t *kbd, int level)
92142421Syokota{
92242421Syokota	if (level > 0) {
92342421Syokota		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
92442421Syokota		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
92542421Syokota		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
92642421Syokota		       kbd->kb_config, kbd->kb_flags);
92742421Syokota		if (kbd->kb_io_base > 0)
92842421Syokota			printf(", port:0x%x-0x%x", kbd->kb_io_base,
92942421Syokota			       kbd->kb_io_base + kbd->kb_io_size - 1);
93042421Syokota		printf("\n");
93142421Syokota	}
93242421Syokota}
93342421Syokota
93442421Syokota#define set_lockkey_state(k, s, l)				\
93542421Syokota	if (!((s) & l ## DOWN)) {				\
93642421Syokota		int i;						\
93742421Syokota		(s) |= l ## DOWN;				\
93842421Syokota		(s) ^= l ## ED;					\
93942421Syokota		i = (s) & LOCK_MASK;				\
94042421Syokota		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
94142421Syokota	}
94242421Syokota
94342421Syokotastatic u_int
94442421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents)
94542421Syokota{
94642421Syokota	int i;
94742421Syokota
94842421Syokota	/* make an index into the accent map */
94942421Syokota	i = key - F_ACC + 1;
95042421Syokota	if ((i > kbd->kb_accentmap->n_accs)
95142421Syokota	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
95242421Syokota		/* the index is out of range or pointing to an empty entry */
95342421Syokota		*accents = 0;
95442421Syokota		return ERRKEY;
95542421Syokota	}
95642421Syokota
95742421Syokota	/*
95842421Syokota	 * If the same accent key has been hit twice, produce the accent char
95942421Syokota	 * itself.
96042421Syokota	 */
96142421Syokota	if (i == *accents) {
96242421Syokota		key = kbd->kb_accentmap->acc[i - 1].accchar;
96342421Syokota		*accents = 0;
96442421Syokota		return key;
96542421Syokota	}
96642421Syokota
96742421Syokota	/* remember the index and wait for the next key  */
96842421Syokota	*accents = i;
96942421Syokota	return NOKEY;
97042421Syokota}
97142421Syokota
97242421Syokotastatic u_int
97342421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents)
97442421Syokota{
97542421Syokota	struct acc_t *acc;
97642421Syokota	int i;
97742421Syokota
97842421Syokota	acc = &kbd->kb_accentmap->acc[*accents - 1];
97942421Syokota	*accents = 0;
98042421Syokota
98142421Syokota	/*
98242421Syokota	 * If the accent key is followed by the space key,
98342421Syokota	 * produce the accent char itself.
98442421Syokota	 */
98542421Syokota	if (ch == ' ')
98642421Syokota		return acc->accchar;
98742421Syokota
98842421Syokota	/* scan the accent map */
98942421Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
99042421Syokota		if (acc->map[i][0] == 0)	/* end of table */
99142421Syokota			break;
99242421Syokota		if (acc->map[i][0] == ch)
99342421Syokota			return acc->map[i][1];
99442421Syokota	}
99542421Syokota	/* this char cannot be accented... */
99642421Syokota	return ERRKEY;
99742421Syokota}
99842421Syokota
99942421Syokotaint
100042421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
100142421Syokota		 int *accents)
100242421Syokota{
100342421Syokota	struct keyent_t *key;
100442421Syokota	int state = *shiftstate;
100542421Syokota	int action;
100642421Syokota	int f;
100742421Syokota	int i;
100842421Syokota
100954382Syokota	i = keycode;
101042421Syokota	f = state & (AGRS | ALKED);
101142421Syokota	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
101254382Syokota		i += ALTGR_OFFSET;
101354382Syokota	key = &kbd->kb_keymap->key[i];
101442421Syokota	i = ((state & SHIFTS) ? 1 : 0)
101542421Syokota	    | ((state & CTLS) ? 2 : 0)
101642421Syokota	    | ((state & ALTS) ? 4 : 0);
101742421Syokota	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
101842421Syokota		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
101942421Syokota		i ^= 1;
102042421Syokota
102142421Syokota	action = key->map[i];
102242421Syokota	if (up) {	/* break: key released */
102342421Syokota		if (key->spcl & (0x80 >> i)) {
102442421Syokota			/* special keys */
102542421Syokota			switch (action) {
102654382Syokota			case LSHA:
102755820Syokota				if (state & SHIFTAON) {
102854382Syokota					set_lockkey_state(kbd, state, ALK);
102954382Syokota					state &= ~ALKDOWN;
103054382Syokota				}
103154382Syokota				action = LSH;
103254382Syokota				/* FALL THROUGH */
103342421Syokota			case LSH:
103442421Syokota				state &= ~SHIFTS1;
103542421Syokota				break;
103654382Syokota			case RSHA:
103755820Syokota				if (state & SHIFTAON) {
103854382Syokota					set_lockkey_state(kbd, state, ALK);
103954382Syokota					state &= ~ALKDOWN;
104054382Syokota				}
104154382Syokota				action = RSH;
104254382Syokota				/* FALL THROUGH */
104342421Syokota			case RSH:
104442421Syokota				state &= ~SHIFTS2;
104542421Syokota				break;
104654382Syokota			case LCTRA:
104755820Syokota				if (state & SHIFTAON) {
104854382Syokota					set_lockkey_state(kbd, state, ALK);
104954382Syokota					state &= ~ALKDOWN;
105054382Syokota				}
105154382Syokota				action = LCTR;
105254382Syokota				/* FALL THROUGH */
105342421Syokota			case LCTR:
105442421Syokota				state &= ~CTLS1;
105542421Syokota				break;
105654382Syokota			case RCTRA:
105755820Syokota				if (state & SHIFTAON) {
105854382Syokota					set_lockkey_state(kbd, state, ALK);
105954382Syokota					state &= ~ALKDOWN;
106054382Syokota				}
106154382Syokota				action = RCTR;
106254382Syokota				/* FALL THROUGH */
106342421Syokota			case RCTR:
106442421Syokota				state &= ~CTLS2;
106542421Syokota				break;
106654382Syokota			case LALTA:
106755820Syokota				if (state & SHIFTAON) {
106854382Syokota					set_lockkey_state(kbd, state, ALK);
106954382Syokota					state &= ~ALKDOWN;
107054382Syokota				}
107154382Syokota				action = LALT;
107254382Syokota				/* FALL THROUGH */
107342421Syokota			case LALT:
107442421Syokota				state &= ~ALTS1;
107542421Syokota				break;
107654382Syokota			case RALTA:
107755820Syokota				if (state & SHIFTAON) {
107854382Syokota					set_lockkey_state(kbd, state, ALK);
107954382Syokota					state &= ~ALKDOWN;
108054382Syokota				}
108154382Syokota				action = RALT;
108254382Syokota				/* FALL THROUGH */
108342421Syokota			case RALT:
108442421Syokota				state &= ~ALTS2;
108542421Syokota				break;
108642421Syokota			case ASH:
108742421Syokota				state &= ~AGRS1;
108842421Syokota				break;
108942421Syokota			case META:
109042421Syokota				state &= ~METAS1;
109142421Syokota				break;
109242421Syokota			case NLK:
109342421Syokota				state &= ~NLKDOWN;
109442421Syokota				break;
109542421Syokota			case CLK:
109642421Syokota#ifndef PC98
109742421Syokota				state &= ~CLKDOWN;
109842421Syokota#else
109942421Syokota				state &= ~CLKED;
110042421Syokota				i = state & LOCK_MASK;
110142421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
110242421Syokota							       (caddr_t)&i);
110342421Syokota#endif
110442421Syokota				break;
110542421Syokota			case SLK:
110642421Syokota				state &= ~SLKDOWN;
110742421Syokota				break;
110842421Syokota			case ALK:
110942421Syokota				state &= ~ALKDOWN;
111042421Syokota				break;
111142421Syokota			}
111255820Syokota			*shiftstate = state & ~SHIFTAON;
111342421Syokota			return (SPCLKEY | RELKEY | action);
111442421Syokota		}
111542421Syokota		/* release events of regular keys are not reported */
111655820Syokota		*shiftstate &= ~SHIFTAON;
111742421Syokota		return NOKEY;
111842421Syokota	} else {	/* make: key pressed */
111955820Syokota		state &= ~SHIFTAON;
112042421Syokota		if (key->spcl & (0x80 >> i)) {
112142421Syokota			/* special keys */
112242421Syokota			switch (action) {
112342421Syokota			/* LOCKING KEYS */
112442421Syokota			case NLK:
112542421Syokota				set_lockkey_state(kbd, state, NLK);
112642421Syokota				break;
112742421Syokota			case CLK:
112842421Syokota#ifndef PC98
112942421Syokota				set_lockkey_state(kbd, state, CLK);
113042421Syokota#else
113142421Syokota				state |= CLKED;
113242421Syokota				i = state & LOCK_MASK;
113342421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
113442421Syokota							       (caddr_t)&i);
113542421Syokota#endif
113642421Syokota				break;
113742421Syokota			case SLK:
113842421Syokota				set_lockkey_state(kbd, state, SLK);
113942421Syokota				break;
114042421Syokota			case ALK:
114142421Syokota				set_lockkey_state(kbd, state, ALK);
114242421Syokota				break;
114342421Syokota			/* NON-LOCKING KEYS */
114442421Syokota			case SPSC: case RBT:  case SUSP: case STBY:
114554382Syokota			case DBG:  case NEXT: case PREV: case PNC:
114665759Sdwmalone			case HALT: case PDWN:
114742421Syokota				*accents = 0;
114842421Syokota				break;
114942421Syokota			case BTAB:
115042421Syokota				*accents = 0;
115142421Syokota				action |= BKEY;
115242421Syokota				break;
115354382Syokota			case LSHA:
115455820Syokota				state |= SHIFTAON;
115554382Syokota				action = LSH;
115654382Syokota				/* FALL THROUGH */
115742421Syokota			case LSH:
115842421Syokota				state |= SHIFTS1;
115942421Syokota				break;
116054382Syokota			case RSHA:
116155820Syokota				state |= SHIFTAON;
116254382Syokota				action = RSH;
116354382Syokota				/* FALL THROUGH */
116442421Syokota			case RSH:
116542421Syokota				state |= SHIFTS2;
116642421Syokota				break;
116754382Syokota			case LCTRA:
116855820Syokota				state |= SHIFTAON;
116954382Syokota				action = LCTR;
117054382Syokota				/* FALL THROUGH */
117142421Syokota			case LCTR:
117242421Syokota				state |= CTLS1;
117342421Syokota				break;
117454382Syokota			case RCTRA:
117555820Syokota				state |= SHIFTAON;
117654382Syokota				action = RCTR;
117754382Syokota				/* FALL THROUGH */
117842421Syokota			case RCTR:
117942421Syokota				state |= CTLS2;
118042421Syokota				break;
118154382Syokota			case LALTA:
118255820Syokota				state |= SHIFTAON;
118354382Syokota				action = LALT;
118454382Syokota				/* FALL THROUGH */
118542421Syokota			case LALT:
118642421Syokota				state |= ALTS1;
118742421Syokota				break;
118854382Syokota			case RALTA:
118955820Syokota				state |= SHIFTAON;
119054382Syokota				action = RALT;
119154382Syokota				/* FALL THROUGH */
119242421Syokota			case RALT:
119342421Syokota				state |= ALTS2;
119442421Syokota				break;
119542421Syokota			case ASH:
119642421Syokota				state |= AGRS1;
119742421Syokota				break;
119842421Syokota			case META:
119942421Syokota				state |= METAS1;
120042421Syokota				break;
120142421Syokota			default:
120242421Syokota				/* is this an accent (dead) key? */
120355820Syokota				*shiftstate = state;
120442421Syokota				if (action >= F_ACC && action <= L_ACC) {
120542421Syokota					action = save_accent_key(kbd, action,
120642421Syokota								 accents);
120742421Syokota					switch (action) {
120842421Syokota					case NOKEY:
120942421Syokota					case ERRKEY:
121042421Syokota						return action;
121142421Syokota					default:
121242421Syokota						if (state & METAS)
121342421Syokota							return (action | MKEY);
121442421Syokota						else
121542421Syokota							return action;
121642421Syokota					}
121742421Syokota					/* NOT REACHED */
121842421Syokota				}
121942421Syokota				/* other special keys */
122042421Syokota				if (*accents > 0) {
122142421Syokota					*accents = 0;
122242421Syokota					return ERRKEY;
122342421Syokota				}
122442421Syokota				if (action >= F_FN && action <= L_FN)
122542421Syokota					action |= FKEY;
122642421Syokota				/* XXX: return fkey string for the FKEY? */
122755820Syokota				return (SPCLKEY | action);
122842421Syokota			}
122942421Syokota			*shiftstate = state;
123042421Syokota			return (SPCLKEY | action);
123142421Syokota		} else {
123242421Syokota			/* regular keys */
123355820Syokota			*shiftstate = state;
123442421Syokota			if (*accents > 0) {
123542421Syokota				/* make an accented char */
123642421Syokota				action = make_accent_char(kbd, action, accents);
123742421Syokota				if (action == ERRKEY)
123842421Syokota					return action;
123942421Syokota			}
124042421Syokota			if (state & METAS)
124142421Syokota				action |= MKEY;
124242421Syokota			return action;
124342421Syokota		}
124442421Syokota	}
124542421Syokota	/* NOT REACHED */
124642421Syokota}
1247