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