kbd.c revision 112050
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 112050 2003-03-09 22:49:48Z dwmalone $
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>
38112050Sdwmalone#include <sys/proc.h>
39112050Sdwmalone#include <sys/sysctl.h>
4042421Syokota#include <sys/vnode.h>
4142421Syokota#include <sys/uio.h>
4242421Syokota
4366834Sphk#include <sys/kbio.h>
4442421Syokota
4542421Syokota#include <dev/kbd/kbdreg.h>
4642421Syokota
4750154Syokota#define KBD_INDEX(dev)	minor(dev)
4850154Syokota
4950154Syokotatypedef struct genkbd_softc {
5050154Syokota	int		gkb_flags;	/* flag/status bits */
5150154Syokota#define KB_ASLEEP	(1 << 0)
5250154Syokota	struct clist	gkb_q;		/* input queue */
5350154Syokota	struct selinfo	gkb_rsel;
5450154Syokota} genkbd_softc_t;
5550154Syokota
5660938Sjakestatic	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
5754545Syokota 	SLIST_HEAD_INITIALIZER(keyboard_drivers);
5854545Syokota
5978161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t);
6078161Speter
6142421Syokota/* local arrays */
6242421Syokota
6342421Syokota/*
6442421Syokota * We need at least one entry each in order to initialize a keyboard
6542421Syokota * for the kernel console.  The arrays will be increased dynamically
6642421Syokota * when necessary.
6742421Syokota */
6842564Syokota
6942564Syokotastatic int		keyboards = 1;
7042421Syokotastatic keyboard_t	*kbd_ini;
7142564Syokotastatic keyboard_t	**keyboard = &kbd_ini;
7242421Syokotastatic keyboard_switch_t *kbdsw_ini;
7342421Syokota       keyboard_switch_t **kbdsw = &kbdsw_ini;
7442421Syokota
75112050Sdwmalonestatic int keymap_restrict_change;
76112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd");
77112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW,
78112050Sdwmalone    &keymap_restrict_change, 0, "restrict ability to change keymap");
79112050Sdwmalone
8042421Syokota#define ARRAY_DELTA	4
8142421Syokota
8244628Syokotastatic int
8342421Syokotakbd_realloc_array(void)
8442421Syokota{
8542421Syokota	keyboard_t **new_kbd;
8642421Syokota	keyboard_switch_t **new_kbdsw;
8742421Syokota	int newsize;
8842421Syokota	int s;
8942421Syokota
9042421Syokota	s = spltty();
9142421Syokota	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
9269781Sdwmalone	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO);
9344628Syokota	if (new_kbd == NULL) {
9444628Syokota		splx(s);
9544628Syokota		return ENOMEM;
9644628Syokota	}
9769781Sdwmalone	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF,
9869781Sdwmalone			    M_NOWAIT|M_ZERO);
9944628Syokota	if (new_kbdsw == NULL) {
10044628Syokota		free(new_kbd, M_DEVBUF);
10144628Syokota		splx(s);
10244628Syokota		return ENOMEM;
10344628Syokota	}
10442421Syokota	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
10542421Syokota	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
10642421Syokota	if (keyboards > 1) {
10742421Syokota		free(keyboard, M_DEVBUF);
10842421Syokota		free(kbdsw, M_DEVBUF);
10942421Syokota	}
11042421Syokota	keyboard = new_kbd;
11142421Syokota	kbdsw = new_kbdsw;
11242421Syokota	keyboards = newsize;
11342421Syokota	splx(s);
11442421Syokota
11542421Syokota	if (bootverbose)
11642421Syokota		printf("kbd: new array size %d\n", keyboards);
11744628Syokota
11844628Syokota	return 0;
11942421Syokota}
12042421Syokota
12142421Syokota/*
12242421Syokota * Low-level keyboard driver functions
12342421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
12442421Syokota * driver, call these functions to initialize the keyboard_t structure
12542421Syokota * and register it to the virtual keyboard driver `kbd'.
12642421Syokota */
12742421Syokota
12842421Syokota/* initialize the keyboard_t structure */
12942421Syokotavoid
13042421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
13142421Syokota		int port, int port_size)
13242421Syokota{
13342421Syokota	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
13442421Syokota	kbd->kb_name = name;
13542421Syokota	kbd->kb_type = type;
13642421Syokota	kbd->kb_unit = unit;
13744628Syokota	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
13842421Syokota	kbd->kb_led = 0;		/* unknown */
13942421Syokota	kbd->kb_io_base = port;
14042421Syokota	kbd->kb_io_size = port_size;
14142421Syokota	kbd->kb_data = NULL;
14242421Syokota	kbd->kb_keymap = NULL;
14342421Syokota	kbd->kb_accentmap = NULL;
14442421Syokota	kbd->kb_fkeytab = NULL;
14542421Syokota	kbd->kb_fkeytab_size = 0;
14644628Syokota	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
14744628Syokota	kbd->kb_delay2 = KB_DELAY2;
14854382Syokota	kbd->kb_count = 0L;
14980040Syokota	bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
15042421Syokota}
15142421Syokota
15242421Syokotavoid
15342421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
15442421Syokota	     fkeytab_t *fkeymap, int fkeymap_size)
15542421Syokota{
15642421Syokota	kbd->kb_keymap = keymap;
15742421Syokota	kbd->kb_accentmap = accmap;
15842421Syokota	kbd->kb_fkeytab = fkeymap;
15942421Syokota	kbd->kb_fkeytab_size = fkeymap_size;
16042421Syokota}
16142421Syokota
16254545Syokota/* declare a new keyboard driver */
16354545Syokotaint
16454545Syokotakbd_add_driver(keyboard_driver_t *driver)
16554545Syokota{
16654545Syokota	if (SLIST_NEXT(driver, link))
16754545Syokota		return EINVAL;
16854545Syokota	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
16954545Syokota	return 0;
17054545Syokota}
17154545Syokota
17254545Syokotaint
17354545Syokotakbd_delete_driver(keyboard_driver_t *driver)
17454545Syokota{
17560938Sjake	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
17654545Syokota	SLIST_NEXT(driver, link) = NULL;
17754545Syokota	return 0;
17854545Syokota}
17954545Syokota
18042421Syokota/* register a keyboard and associate it with a function table */
18142421Syokotaint
18242421Syokotakbd_register(keyboard_t *kbd)
18342421Syokota{
18447295Syokota	const keyboard_driver_t **list;
18547295Syokota	const keyboard_driver_t *p;
18642421Syokota	int index;
18742421Syokota
18842421Syokota	for (index = 0; index < keyboards; ++index) {
18942421Syokota		if (keyboard[index] == NULL)
19042421Syokota			break;
19142421Syokota	}
19244628Syokota	if (index >= keyboards) {
19344628Syokota		if (kbd_realloc_array())
19444628Syokota			return -1;
19544628Syokota	}
19642421Syokota
19742421Syokota	kbd->kb_index = index;
19842421Syokota	KBD_UNBUSY(kbd);
19942421Syokota	KBD_VALID(kbd);
20042421Syokota	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
20142421Syokota	kbd->kb_token = NULL;
20242421Syokota	kbd->kb_callback.kc_func = NULL;
20342421Syokota	kbd->kb_callback.kc_arg = NULL;
20442421Syokota
20554545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
20654545Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
20754545Syokota			keyboard[index] = kbd;
20854545Syokota			kbdsw[index] = p->kbdsw;
20954545Syokota			return index;
21054545Syokota		}
21154545Syokota	}
21278161Speter	SET_FOREACH(list, kbddriver_set) {
21378161Speter		p = *list;
21442421Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
21542421Syokota			keyboard[index] = kbd;
21642421Syokota			kbdsw[index] = p->kbdsw;
21742421Syokota			return index;
21842421Syokota		}
21942421Syokota	}
22042421Syokota
22142421Syokota	return -1;
22242421Syokota}
22342421Syokota
22442421Syokotaint
22542421Syokotakbd_unregister(keyboard_t *kbd)
22642421Syokota{
22742421Syokota	int error;
22842421Syokota	int s;
22942421Syokota
23042421Syokota	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
23142421Syokota		return ENOENT;
23242421Syokota	if (keyboard[kbd->kb_index] != kbd)
23342421Syokota		return ENOENT;
23442421Syokota
23542421Syokota	s = spltty();
23642421Syokota	if (KBD_IS_BUSY(kbd)) {
23742421Syokota		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
23842421Syokota						    kbd->kb_callback.kc_arg);
23942421Syokota		if (error) {
24042421Syokota			splx(s);
24142421Syokota			return error;
24242421Syokota		}
24342421Syokota		if (KBD_IS_BUSY(kbd)) {
24442421Syokota			splx(s);
24542421Syokota			return EBUSY;
24642421Syokota		}
24742421Syokota	}
24842421Syokota	KBD_INVALID(kbd);
24942421Syokota	keyboard[kbd->kb_index] = NULL;
25042421Syokota	kbdsw[kbd->kb_index] = NULL;
25142421Syokota
25242421Syokota	splx(s);
25342421Syokota	return 0;
25442421Syokota}
25542421Syokota
25642421Syokota/* find a funciton table by the driver name */
25742421Syokotakeyboard_switch_t
25842421Syokota*kbd_get_switch(char *driver)
25942421Syokota{
26047295Syokota	const keyboard_driver_t **list;
26147295Syokota	const keyboard_driver_t *p;
26242421Syokota
26354545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
26454545Syokota		if (strcmp(p->name, driver) == 0)
26554545Syokota			return p->kbdsw;
26654545Syokota	}
26778161Speter	SET_FOREACH(list, kbddriver_set) {
26878161Speter		p = *list;
26942421Syokota		if (strcmp(p->name, driver) == 0)
27042421Syokota			return p->kbdsw;
27142421Syokota	}
27242421Syokota
27342421Syokota	return NULL;
27442421Syokota}
27542421Syokota
27642421Syokota/*
27742421Syokota * Keyboard client functions
27842421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard
27942421Syokota * cdev driver, use these functions to claim and release a keyboard for
28042421Syokota * exclusive use.
28142421Syokota */
28242421Syokota
28342421Syokota/* find the keyboard specified by a driver name and a unit number */
28442421Syokotaint
28542421Syokotakbd_find_keyboard(char *driver, int unit)
28642421Syokota{
28742421Syokota	int i;
28842421Syokota
28942421Syokota	for (i = 0; i < keyboards; ++i) {
29042421Syokota		if (keyboard[i] == NULL)
29142421Syokota			continue;
29242421Syokota		if (!KBD_IS_VALID(keyboard[i]))
29342421Syokota			continue;
29442421Syokota		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
29542421Syokota			continue;
29642421Syokota		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
29742421Syokota			continue;
29842421Syokota		return i;
29942421Syokota	}
30042421Syokota	return -1;
30142421Syokota}
30242421Syokota
30342421Syokota/* allocate a keyboard */
30442421Syokotaint
30542421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
30642421Syokota	     void *arg)
30742421Syokota{
30842421Syokota	int index;
30942421Syokota	int s;
31042421Syokota
31142421Syokota	if (func == NULL)
31242421Syokota		return -1;
31342421Syokota
31442421Syokota	s = spltty();
31542421Syokota	index = kbd_find_keyboard(driver, unit);
31642421Syokota	if (index >= 0) {
31742421Syokota		if (KBD_IS_BUSY(keyboard[index])) {
31842421Syokota			splx(s);
31942421Syokota			return -1;
32042421Syokota		}
32142421Syokota		keyboard[index]->kb_token = id;
32242421Syokota		KBD_BUSY(keyboard[index]);
32342421Syokota		keyboard[index]->kb_callback.kc_func = func;
32442421Syokota		keyboard[index]->kb_callback.kc_arg = arg;
32542421Syokota		(*kbdsw[index]->clear_state)(keyboard[index]);
32642421Syokota	}
32742421Syokota	splx(s);
32842421Syokota	return index;
32942421Syokota}
33042421Syokota
33142421Syokotaint
33242421Syokotakbd_release(keyboard_t *kbd, void *id)
33342421Syokota{
33442421Syokota	int error;
33542421Syokota	int s;
33642421Syokota
33742421Syokota	s = spltty();
33842421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
33942421Syokota		error = EINVAL;
34042421Syokota	} else if (kbd->kb_token != id) {
34142421Syokota		error = EPERM;
34242421Syokota	} else {
34342421Syokota		kbd->kb_token = NULL;
34442421Syokota		KBD_UNBUSY(kbd);
34542421Syokota		kbd->kb_callback.kc_func = NULL;
34642421Syokota		kbd->kb_callback.kc_arg = NULL;
34742421Syokota		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
34842421Syokota		error = 0;
34942421Syokota	}
35042421Syokota	splx(s);
35142421Syokota	return error;
35242421Syokota}
35342421Syokota
35442421Syokotaint
35542421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
35642421Syokota		    void *arg)
35742421Syokota{
35842421Syokota	int error;
35942421Syokota	int s;
36042421Syokota
36142421Syokota	s = spltty();
36242421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
36342421Syokota		error = EINVAL;
36442421Syokota	} else if (kbd->kb_token != id) {
36542421Syokota		error = EPERM;
36642421Syokota	} else if (func == NULL) {
36742421Syokota		error = EINVAL;
36842421Syokota	} else {
36942421Syokota		kbd->kb_callback.kc_func = func;
37042421Syokota		kbd->kb_callback.kc_arg = arg;
37142421Syokota		error = 0;
37242421Syokota	}
37342421Syokota	splx(s);
37442421Syokota	return error;
37542421Syokota}
37642421Syokota
37742421Syokota/* get a keyboard structure */
37842421Syokotakeyboard_t
37942421Syokota*kbd_get_keyboard(int index)
38042421Syokota{
38142421Syokota	if ((index < 0) || (index >= keyboards))
38242421Syokota		return NULL;
38350154Syokota	if (keyboard[index] == NULL)
38450154Syokota		return NULL;
38542421Syokota	if (!KBD_IS_VALID(keyboard[index]))
38642421Syokota		return NULL;
38742421Syokota	return keyboard[index];
38842421Syokota}
38942421Syokota
39042421Syokota/*
39142421Syokota * The back door for the console driver; configure keyboards
39242421Syokota * This function is for the kernel console to initialize keyboards
39342421Syokota * at very early stage.
39442421Syokota */
39542421Syokota
39642421Syokotaint
39742421Syokotakbd_configure(int flags)
39842421Syokota{
39947295Syokota	const keyboard_driver_t **list;
40047295Syokota	const keyboard_driver_t *p;
40142421Syokota
40254545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
40354545Syokota		if (p->configure != NULL)
40454545Syokota			(*p->configure)(flags);
40554545Syokota	}
40678161Speter	SET_FOREACH(list, kbddriver_set) {
40778161Speter		p = *list;
40842421Syokota		if (p->configure != NULL)
40942421Syokota			(*p->configure)(flags);
41042421Syokota	}
41142421Syokota
41242421Syokota	return 0;
41342421Syokota}
41442421Syokota
41542421Syokota#ifdef KBD_INSTALL_CDEV
41642421Syokota
41742421Syokota/*
41842421Syokota * Virtual keyboard cdev driver functions
41942421Syokota * The virtual keyboard driver dispatches driver functions to
42042421Syokota * appropriate subdrivers.
42142421Syokota */
42242421Syokota
42342421Syokota#define KBD_UNIT(dev)	minor(dev)
42442421Syokota
42550154Syokotastatic d_open_t		genkbdopen;
42650154Syokotastatic d_close_t	genkbdclose;
42750154Syokotastatic d_read_t		genkbdread;
42850154Syokotastatic d_write_t	genkbdwrite;
42950154Syokotastatic d_ioctl_t	genkbdioctl;
43050154Syokotastatic d_poll_t		genkbdpoll;
43142421Syokota
43242421Syokota#define CDEV_MAJOR	112
43342421Syokota
43442421Syokotastatic struct cdevsw kbd_cdevsw = {
435111815Sphk	.d_open =	genkbdopen,
436111815Sphk	.d_close =	genkbdclose,
437111815Sphk	.d_read =	genkbdread,
438111815Sphk	.d_write =	genkbdwrite,
439111815Sphk	.d_ioctl =	genkbdioctl,
440111815Sphk	.d_poll =	genkbdpoll,
441111815Sphk	.d_name =	"kbd",
442111815Sphk	.d_maj =	CDEV_MAJOR,
44342421Syokota};
44442421Syokota
44542421Syokotaint
44650154Syokotakbd_attach(keyboard_t *kbd)
44742421Syokota{
44850154Syokota	dev_t dev;
44942421Syokota
45042421Syokota	if (kbd->kb_index >= keyboards)
45142421Syokota		return EINVAL;
45242421Syokota	if (keyboard[kbd->kb_index] != kbd)
45342421Syokota		return EINVAL;
45442421Syokota
45550154Syokota	dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
45650154Syokota		       "kbd%r", kbd->kb_index);
45750154Syokota	if (dev->si_drv1 == NULL)
45850154Syokota		dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
459111119Simp				      M_WAITOK);
46050154Syokota	bzero(dev->si_drv1, sizeof(genkbd_softc_t));
46142421Syokota
46242421Syokota	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
46342421Syokota	return 0;
46442421Syokota}
46542421Syokota
46642421Syokotaint
46750154Syokotakbd_detach(keyboard_t *kbd)
46842421Syokota{
46954545Syokota	dev_t dev;
47054545Syokota
47142421Syokota	if (kbd->kb_index >= keyboards)
47242421Syokota		return EINVAL;
47342421Syokota	if (keyboard[kbd->kb_index] != kbd)
47442421Syokota		return EINVAL;
47542421Syokota
47654545Syokota	dev = makedev(kbd_cdevsw.d_maj, kbd->kb_index);
47754545Syokota	if (dev->si_drv1)
47854545Syokota		free(dev->si_drv1, M_DEVBUF);
47954545Syokota	destroy_dev(dev);
48054545Syokota
48142421Syokota	return 0;
48242421Syokota}
48342421Syokota
48442421Syokota/*
48542421Syokota * Generic keyboard cdev driver functions
48642421Syokota * Keyboard subdrivers may call these functions to implement common
48742421Syokota * driver functions.
48842421Syokota */
48942421Syokota
49042421Syokota#define KB_QSIZE	512
49142421Syokota#define KB_BUFSIZE	64
49242421Syokota
49342421Syokotastatic kbd_callback_func_t genkbd_event;
49442421Syokota
49550154Syokotastatic int
49683366Sjuliangenkbdopen(dev_t dev, int mode, int flag, struct thread *td)
49742421Syokota{
49850154Syokota	keyboard_t *kbd;
49950154Syokota	genkbd_softc_t *sc;
50042421Syokota	int s;
50142421Syokota	int i;
50242421Syokota
50342421Syokota	s = spltty();
50450154Syokota	sc = dev->si_drv1;
50550154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
50650154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
50742421Syokota		splx(s);
50842421Syokota		return ENXIO;
50942421Syokota	}
51042421Syokota	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
51142421Syokota			 genkbd_event, (void *)sc);
51242421Syokota	if (i < 0) {
51342421Syokota		splx(s);
51442421Syokota		return EBUSY;
51542421Syokota	}
51642421Syokota	/* assert(i == kbd->kb_index) */
51742421Syokota	/* assert(kbd == kbd_get_keyboard(i)) */
51842421Syokota
51942421Syokota	/*
52042421Syokota	 * NOTE: even when we have successfully claimed a keyboard,
52142421Syokota	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
52242421Syokota	 */
52342421Syokota
52442421Syokota#if 0
52542421Syokota	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
52642421Syokota#endif
52742421Syokota	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
52842421Syokota	splx(s);
52942421Syokota
53042421Syokota	return 0;
53142421Syokota}
53242421Syokota
53350154Syokotastatic int
53483366Sjuliangenkbdclose(dev_t dev, int mode, int flag, struct thread *td)
53542421Syokota{
53650154Syokota	keyboard_t *kbd;
53750154Syokota	genkbd_softc_t *sc;
53842421Syokota	int s;
53942421Syokota
54042421Syokota	/*
54142421Syokota	 * NOTE: the device may have already become invalid.
54250154Syokota	 * kbd == NULL || !KBD_IS_VALID(kbd)
54342421Syokota	 */
54442421Syokota	s = spltty();
54550154Syokota	sc = dev->si_drv1;
54650154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
54750154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
54850154Syokota		/* XXX: we shall be forgiving and don't report error... */
54950154Syokota	} else {
55050154Syokota		kbd_release(kbd, (void *)sc);
55142421Syokota#if 0
55250154Syokota		clist_free_cblocks(&sc->gkb_q);
55342421Syokota#endif
55450154Syokota	}
55542421Syokota	splx(s);
55642421Syokota	return 0;
55742421Syokota}
55842421Syokota
55950154Syokotastatic int
56050154Syokotagenkbdread(dev_t dev, struct uio *uio, int flag)
56142421Syokota{
56250154Syokota	keyboard_t *kbd;
56350154Syokota	genkbd_softc_t *sc;
56442421Syokota	u_char buffer[KB_BUFSIZE];
56542421Syokota	int len;
56642421Syokota	int error;
56742421Syokota	int s;
56842421Syokota
56942421Syokota	/* wait for input */
57042421Syokota	s = spltty();
57150154Syokota	sc = dev->si_drv1;
57250154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
57350154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
57450154Syokota		splx(s);
57550154Syokota		return ENXIO;
57650154Syokota	}
57742421Syokota	while (sc->gkb_q.c_cc == 0) {
57842421Syokota		if (flag & IO_NDELAY) {
57942421Syokota			splx(s);
58042421Syokota			return EWOULDBLOCK;
58142421Syokota		}
58242421Syokota		sc->gkb_flags |= KB_ASLEEP;
583111748Sdes		error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0);
58450154Syokota		kbd = kbd_get_keyboard(KBD_INDEX(dev));
58550154Syokota		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
58650154Syokota			splx(s);
58750154Syokota			return ENXIO;	/* our keyboard has gone... */
58850154Syokota		}
58942421Syokota		if (error) {
59042421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
59142421Syokota			splx(s);
59242421Syokota			return error;
59342421Syokota		}
59442421Syokota	}
59542421Syokota	splx(s);
59642421Syokota
59742421Syokota	/* copy as much input as possible */
59842421Syokota	error = 0;
59942421Syokota	while (uio->uio_resid > 0) {
60042421Syokota		len = imin(uio->uio_resid, sizeof(buffer));
60142421Syokota		len = q_to_b(&sc->gkb_q, buffer, len);
60242421Syokota		if (len <= 0)
60342421Syokota			break;
60442421Syokota		error = uiomove(buffer, len, uio);
60542421Syokota		if (error)
60642421Syokota			break;
60742421Syokota	}
60842421Syokota
60942421Syokota	return error;
61042421Syokota}
61142421Syokota
61250154Syokotastatic int
61350154Syokotagenkbdwrite(dev_t dev, struct uio *uio, int flag)
61442421Syokota{
61550154Syokota	keyboard_t *kbd;
61650154Syokota
61750154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
61850154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
61942421Syokota		return ENXIO;
62042421Syokota	return ENODEV;
62142421Syokota}
62242421Syokota
62350154Syokotastatic int
62483366Sjuliangenkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
62542421Syokota{
62650154Syokota	keyboard_t *kbd;
62742421Syokota	int error;
62842421Syokota
62950154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
63050154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
63142421Syokota		return ENXIO;
63242421Syokota	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
63342421Syokota	if (error == ENOIOCTL)
63442421Syokota		error = ENODEV;
63542421Syokota	return error;
63642421Syokota}
63742421Syokota
63850154Syokotastatic int
63983366Sjuliangenkbdpoll(dev_t dev, int events, struct thread *td)
64042421Syokota{
64150154Syokota	keyboard_t *kbd;
64250154Syokota	genkbd_softc_t *sc;
64342421Syokota	int revents;
64442421Syokota	int s;
64542421Syokota
64642421Syokota	revents = 0;
64742421Syokota	s = spltty();
64850154Syokota	sc = dev->si_drv1;
64950154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
65050154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
65150154Syokota		revents =  POLLHUP;	/* the keyboard has gone */
65250154Syokota	} else if (events & (POLLIN | POLLRDNORM)) {
65350154Syokota		if (sc->gkb_q.c_cc > 0)
65450154Syokota			revents = events & (POLLIN | POLLRDNORM);
65542421Syokota		else
65683366Sjulian			selrecord(td, &sc->gkb_rsel);
65742421Syokota	}
65842421Syokota	splx(s);
65942421Syokota	return revents;
66042421Syokota}
66142421Syokota
66242421Syokotastatic int
66342421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg)
66442421Syokota{
66542421Syokota	genkbd_softc_t *sc;
66642421Syokota	size_t len;
66742421Syokota	u_char *cp;
66842421Syokota	int mode;
66942421Syokota	int c;
67042421Syokota
67142421Syokota	/* assert(KBD_IS_VALID(kbd)) */
67242421Syokota	sc = (genkbd_softc_t *)arg;
67342421Syokota
67442421Syokota	switch (event) {
67542421Syokota	case KBDIO_KEYINPUT:
67642421Syokota		break;
67742421Syokota	case KBDIO_UNLOADING:
67842421Syokota		/* the keyboard is going... */
67942421Syokota		kbd_release(kbd, (void *)sc);
68050154Syokota		if (sc->gkb_flags & KB_ASLEEP) {
68150154Syokota			sc->gkb_flags &= ~KB_ASLEEP;
682111748Sdes			wakeup(sc);
68350154Syokota		}
68450154Syokota		selwakeup(&sc->gkb_rsel);
68542421Syokota		return 0;
68642421Syokota	default:
68742421Syokota		return EINVAL;
68842421Syokota	}
68942421Syokota
69042421Syokota	/* obtain the current key input mode */
69142421Syokota	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
69242421Syokota		mode = K_XLATE;
69342421Syokota
69442421Syokota	/* read all pending input */
69542421Syokota	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
69642421Syokota		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
69742421Syokota		if (c == NOKEY)
69842421Syokota			continue;
69942421Syokota		if (c == ERRKEY)	/* XXX: ring bell? */
70042421Syokota			continue;
70142421Syokota		if (!KBD_IS_BUSY(kbd))
70242421Syokota			/* the device is not open, discard the input */
70342421Syokota			continue;
70442421Syokota
70542421Syokota		/* store the byte as is for K_RAW and K_CODE modes */
70642421Syokota		if (mode != K_XLATE) {
70742421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
70842421Syokota			continue;
70942421Syokota		}
71042421Syokota
71142421Syokota		/* K_XLATE */
71242421Syokota		if (c & RELKEY)	/* key release is ignored */
71342421Syokota			continue;
71442421Syokota
71542421Syokota		/* process special keys; most of them are just ignored... */
71642421Syokota		if (c & SPCLKEY) {
71742421Syokota			switch (KEYCHAR(c)) {
71854382Syokota			default:
71942421Syokota				/* ignore them... */
72042421Syokota				continue;
72142421Syokota			case BTAB:	/* a backtab: ESC [ Z */
72242421Syokota				putc(0x1b, &sc->gkb_q);
72342421Syokota				putc('[', &sc->gkb_q);
72442421Syokota				putc('Z', &sc->gkb_q);
72542421Syokota				continue;
72642421Syokota			}
72742421Syokota		}
72842421Syokota
72942421Syokota		/* normal chars, normal chars with the META, function keys */
73042421Syokota		switch (KEYFLAGS(c)) {
73142421Syokota		case 0:			/* a normal char */
73242421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
73342421Syokota			break;
73442421Syokota		case MKEY:		/* the META flag: prepend ESC */
73542421Syokota			putc(0x1b, &sc->gkb_q);
73642421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
73742421Syokota			break;
73842421Syokota		case FKEY | SPCLKEY:	/* a function key, return string */
73942421Syokota			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
74042421Syokota							KEYCHAR(c), &len);
74142421Syokota			if (cp != NULL) {
74242421Syokota				while (len-- >  0)
74342421Syokota					putc(*cp++, &sc->gkb_q);
74442421Syokota			}
74542421Syokota			break;
74642421Syokota		}
74742421Syokota	}
74842421Syokota
74942421Syokota	/* wake up sleeping/polling processes */
75042421Syokota	if (sc->gkb_q.c_cc > 0) {
75142421Syokota		if (sc->gkb_flags & KB_ASLEEP) {
75242421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
753111748Sdes			wakeup(sc);
75442421Syokota		}
75542421Syokota		selwakeup(&sc->gkb_rsel);
75642421Syokota	}
75742421Syokota
75842421Syokota	return 0;
75942421Syokota}
76042421Syokota
76142421Syokota#endif /* KBD_INSTALL_CDEV */
76242421Syokota
76342421Syokota/*
76442421Syokota * Generic low-level keyboard functions
76542421Syokota * The low-level functions in the keyboard subdriver may use these
76642421Syokota * functions.
76742421Syokota */
76842421Syokota
769112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
770112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *);
771112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *);
772112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *);
773112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *);
774112050Sdwmalone#endif
775112050Sdwmalone
77642421Syokotaint
77742421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
77842421Syokota{
77942421Syokota	keyarg_t *keyp;
78042421Syokota	fkeyarg_t *fkeyp;
78142421Syokota	int s;
78242421Syokota	int i;
783112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
784112050Sdwmalone	int error;
785112050Sdwmalone#endif
78642421Syokota
78742421Syokota	s = spltty();
78842421Syokota	switch (cmd) {
78942421Syokota
79042421Syokota	case KDGKBINFO:		/* get keyboard information */
79142421Syokota		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
79242421Syokota		i = imin(strlen(kbd->kb_name) + 1,
79342421Syokota			 sizeof(((keyboard_info_t *)arg)->kb_name));
79442421Syokota		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
79542421Syokota		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
79642421Syokota		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
79742421Syokota		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
79842421Syokota		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
79942421Syokota		break;
80042421Syokota
80142421Syokota	case KDGKBTYPE:		/* get keyboard type */
80242421Syokota		*(int *)arg = kbd->kb_type;
80342421Syokota		break;
80442421Syokota
80554543Syokota	case KDGETREPEAT:	/* get keyboard repeat rate */
80654543Syokota		((int *)arg)[0] = kbd->kb_delay1;
80754543Syokota		((int *)arg)[1] = kbd->kb_delay2;
80854543Syokota		break;
80954543Syokota
81042421Syokota	case GIO_KEYMAP:	/* get keyboard translation table */
81142421Syokota		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
81242421Syokota		break;
81342421Syokota	case PIO_KEYMAP:	/* set keyboard translation table */
81444628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
815112050Sdwmalone		error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg,
816112050Sdwmalone		    curthread);
817112050Sdwmalone		if (error != 0) {
818112050Sdwmalone			splx(s);
819112050Sdwmalone			return error;
820112050Sdwmalone		}
82142421Syokota		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
82242421Syokota		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
82342421Syokota		break;
82444628Syokota#else
82544628Syokota		splx(s);
82644628Syokota		return ENODEV;
82744628Syokota#endif
82842421Syokota
82942421Syokota	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
83042421Syokota		keyp = (keyarg_t *)arg;
83142421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
83242421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
83342421Syokota			splx(s);
83442421Syokota			return EINVAL;
83542421Syokota		}
83642573Syokota		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
83742421Syokota		      sizeof(keyp->key));
83842421Syokota		break;
83942421Syokota	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
84044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
84142421Syokota		keyp = (keyarg_t *)arg;
84242421Syokota		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
84342421Syokota					/sizeof(kbd->kb_keymap->key[0])) {
84442421Syokota			splx(s);
84542421Syokota			return EINVAL;
84642421Syokota		}
847112050Sdwmalone		error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum],
848112050Sdwmalone		    &keyp->key, curthread);
849112050Sdwmalone		if (error != 0) {
850112050Sdwmalone			splx(s);
851112050Sdwmalone			return error;
852112050Sdwmalone		}
85342573Syokota		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
85442421Syokota		      sizeof(keyp->key));
85542421Syokota		break;
85644628Syokota#else
85744628Syokota		splx(s);
85844628Syokota		return ENODEV;
85944628Syokota#endif
86042421Syokota
86142421Syokota	case GIO_DEADKEYMAP:	/* get accent key translation table */
86242421Syokota		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
86342421Syokota		break;
86442421Syokota	case PIO_DEADKEYMAP:	/* set accent key translation table */
86544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
866112050Sdwmalone		error = accent_change_ok(kbd->kb_accentmap,
867112050Sdwmalone		    (accentmap_t *)arg, curthread);
868112050Sdwmalone		if (error != 0) {
869112050Sdwmalone			splx(s);
870112050Sdwmalone			return error;
871112050Sdwmalone		}
87242421Syokota		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
87342421Syokota		break;
87444628Syokota#else
87544628Syokota		splx(s);
87644628Syokota		return ENODEV;
87744628Syokota#endif
87842421Syokota
87942421Syokota	case GETFKEY:		/* get functionkey string */
88042421Syokota		fkeyp = (fkeyarg_t *)arg;
88142421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
88242421Syokota			splx(s);
88342421Syokota			return EINVAL;
88442421Syokota		}
88542421Syokota		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
88642421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
88742421Syokota		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
88842421Syokota		break;
88942421Syokota	case SETFKEY:		/* set functionkey string */
89044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
89142421Syokota		fkeyp = (fkeyarg_t *)arg;
89242421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
89342421Syokota			splx(s);
89442421Syokota			return EINVAL;
89542421Syokota		}
896112050Sdwmalone		error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum],
897112050Sdwmalone		    fkeyp, curthread);
898112050Sdwmalone		if (error != 0) {
899112050Sdwmalone			splx(s);
900112050Sdwmalone			return error;
901112050Sdwmalone		}
90242421Syokota		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
90342421Syokota		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
90442421Syokota		      kbd->kb_fkeytab[fkeyp->keynum].len);
90542421Syokota		break;
90644628Syokota#else
90744628Syokota		splx(s);
90844628Syokota		return ENODEV;
90944628Syokota#endif
91042421Syokota
91142421Syokota	default:
91242421Syokota		splx(s);
91342421Syokota		return ENOIOCTL;
91442421Syokota	}
91542421Syokota
91642421Syokota	splx(s);
91742421Syokota	return 0;
91842421Syokota}
91942421Syokota
920112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
921112050Sdwmalone#define RESTRICTED_KEY(key, i) \
922112050Sdwmalone	((key->spcl & (0x80 >> i)) && \
923112050Sdwmalone		(key->map[i] == RBT || key->map[i] == SUSP || \
924112050Sdwmalone		 key->map[i] == STBY || key->map[i] == DBG || \
925112050Sdwmalone		 key->map[i] == PNC || key->map[i] == HALT || \
926112050Sdwmalone		 key->map[i] == PDWN))
927112050Sdwmalone
928112050Sdwmalonestatic int
929112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td)
930112050Sdwmalone{
931112050Sdwmalone	int i;
932112050Sdwmalone
933112050Sdwmalone	/* Low keymap_restrict_change means any changes are OK. */
934112050Sdwmalone	if (keymap_restrict_change <= 0)
935112050Sdwmalone		return 0;
936112050Sdwmalone
937112050Sdwmalone	/* High keymap_restrict_change means only root can change the keymap. */
938112050Sdwmalone	if (keymap_restrict_change >= 2) {
939112050Sdwmalone		for (i = 0; i < NUM_STATES; i++)
940112050Sdwmalone			if (oldkey->map[i] != newkey->map[i])
941112050Sdwmalone				return suser(td);
942112050Sdwmalone		if (oldkey->spcl != newkey->spcl)
943112050Sdwmalone			return suser(td);
944112050Sdwmalone		if (oldkey->flgs != newkey->flgs)
945112050Sdwmalone			return suser(td);
946112050Sdwmalone		return 0;
947112050Sdwmalone	}
948112050Sdwmalone
949112050Sdwmalone	/* Otherwise we have to see if any special keys are being changed. */
950112050Sdwmalone	for (i = 0; i < NUM_STATES; i++) {
951112050Sdwmalone		/*
952112050Sdwmalone		 * If either the oldkey or the newkey action is restricted
953112050Sdwmalone		 * then we must make sure that the action doesn't change.
954112050Sdwmalone		 */
955112050Sdwmalone		if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i))
956112050Sdwmalone			continue;
957112050Sdwmalone		if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i))
958112050Sdwmalone		    && oldkey->map[i] == newkey->map[i])
959112050Sdwmalone			continue;
960112050Sdwmalone		return suser(td);
961112050Sdwmalone	}
962112050Sdwmalone
963112050Sdwmalone	return 0;
964112050Sdwmalone}
965112050Sdwmalone
966112050Sdwmalonestatic int
967112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td)
968112050Sdwmalone{
969112050Sdwmalone	int keycode, error;
970112050Sdwmalone
971112050Sdwmalone	for (keycode = 0; keycode < NUM_KEYS; keycode++) {
972112050Sdwmalone		if ((error = key_change_ok(&oldmap->key[keycode],
973112050Sdwmalone		    &newmap->key[keycode], td)) != 0)
974112050Sdwmalone			return error;
975112050Sdwmalone	}
976112050Sdwmalone	return 0;
977112050Sdwmalone}
978112050Sdwmalone
979112050Sdwmalonestatic int
980112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td)
981112050Sdwmalone{
982112050Sdwmalone	struct acc_t *oldacc, *newacc;
983112050Sdwmalone	int accent, i;
984112050Sdwmalone
985112050Sdwmalone	if (keymap_restrict_change <= 2)
986112050Sdwmalone		return 0;
987112050Sdwmalone
988112050Sdwmalone	if (oldmap->n_accs != newmap->n_accs)
989112050Sdwmalone		return suser(td);
990112050Sdwmalone
991112050Sdwmalone	for (accent = 0; accent < oldmap->n_accs; accent++) {
992112050Sdwmalone		oldacc = &oldmap->acc[accent];
993112050Sdwmalone		newacc = &newmap->acc[accent];
994112050Sdwmalone		if (oldacc->accchar != newacc->accchar)
995112050Sdwmalone			return suser(td);
996112050Sdwmalone		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
997112050Sdwmalone			if (oldacc->map[i][0] != newacc->map[i][0])
998112050Sdwmalone				return suser(td);
999112050Sdwmalone			if (oldacc->map[i][0] == 0)	/* end of table */
1000112050Sdwmalone				break;
1001112050Sdwmalone			if (oldacc->map[i][1] != newacc->map[i][1])
1002112050Sdwmalone				return suser(td);
1003112050Sdwmalone		}
1004112050Sdwmalone	}
1005112050Sdwmalone
1006112050Sdwmalone	return 0;
1007112050Sdwmalone}
1008112050Sdwmalone
1009112050Sdwmalonestatic int
1010112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td)
1011112050Sdwmalone{
1012112050Sdwmalone	if (keymap_restrict_change <= 3)
1013112050Sdwmalone		return 0;
1014112050Sdwmalone
1015112050Sdwmalone	if (oldkey->len != newkey->flen ||
1016112050Sdwmalone	    bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0)
1017112050Sdwmalone		return suser(td);
1018112050Sdwmalone
1019112050Sdwmalone	return 0;
1020112050Sdwmalone}
1021112050Sdwmalone#endif
1022112050Sdwmalone
102342421Syokota/* get a pointer to the string associated with the given function key */
102442421Syokotau_char
102542421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
102642421Syokota{
102742421Syokota	if (kbd == NULL)
102842421Syokota		return NULL;
102942421Syokota	fkey -= F_FN;
103042421Syokota	if (fkey > kbd->kb_fkeytab_size)
103142421Syokota		return NULL;
103242421Syokota	*len = kbd->kb_fkeytab[fkey].len;
103342421Syokota	return kbd->kb_fkeytab[fkey].str;
103442421Syokota}
103542421Syokota
103642421Syokota/* diagnostic dump */
103742421Syokotastatic char
103842421Syokota*get_kbd_type_name(int type)
103942421Syokota{
104042421Syokota	static struct {
104142421Syokota		int type;
104242421Syokota		char *name;
104342421Syokota	} name_table[] = {
104442421Syokota		{ KB_84,	"AT 84" },
104542421Syokota		{ KB_101,	"AT 101/102" },
104642421Syokota		{ KB_OTHER,	"generic" },
104742421Syokota	};
104842421Syokota	int i;
104942421Syokota
105042421Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
105142421Syokota		if (type == name_table[i].type)
105242421Syokota			return name_table[i].name;
105342421Syokota	}
105442421Syokota	return "unknown";
105542421Syokota}
105642421Syokota
105742421Syokotavoid
105842421Syokotagenkbd_diag(keyboard_t *kbd, int level)
105942421Syokota{
106042421Syokota	if (level > 0) {
106142421Syokota		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
106242421Syokota		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
106342421Syokota		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
106442421Syokota		       kbd->kb_config, kbd->kb_flags);
106542421Syokota		if (kbd->kb_io_base > 0)
106642421Syokota			printf(", port:0x%x-0x%x", kbd->kb_io_base,
106742421Syokota			       kbd->kb_io_base + kbd->kb_io_size - 1);
106842421Syokota		printf("\n");
106942421Syokota	}
107042421Syokota}
107142421Syokota
107242421Syokota#define set_lockkey_state(k, s, l)				\
107342421Syokota	if (!((s) & l ## DOWN)) {				\
107442421Syokota		int i;						\
107542421Syokota		(s) |= l ## DOWN;				\
107642421Syokota		(s) ^= l ## ED;					\
107742421Syokota		i = (s) & LOCK_MASK;				\
107842421Syokota		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
107942421Syokota	}
108042421Syokota
108142421Syokotastatic u_int
108242421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents)
108342421Syokota{
108442421Syokota	int i;
108542421Syokota
108642421Syokota	/* make an index into the accent map */
108742421Syokota	i = key - F_ACC + 1;
108842421Syokota	if ((i > kbd->kb_accentmap->n_accs)
108942421Syokota	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
109042421Syokota		/* the index is out of range or pointing to an empty entry */
109142421Syokota		*accents = 0;
109242421Syokota		return ERRKEY;
109342421Syokota	}
109442421Syokota
109542421Syokota	/*
109642421Syokota	 * If the same accent key has been hit twice, produce the accent char
109742421Syokota	 * itself.
109842421Syokota	 */
109942421Syokota	if (i == *accents) {
110042421Syokota		key = kbd->kb_accentmap->acc[i - 1].accchar;
110142421Syokota		*accents = 0;
110242421Syokota		return key;
110342421Syokota	}
110442421Syokota
110542421Syokota	/* remember the index and wait for the next key  */
110642421Syokota	*accents = i;
110742421Syokota	return NOKEY;
110842421Syokota}
110942421Syokota
111042421Syokotastatic u_int
111142421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents)
111242421Syokota{
111342421Syokota	struct acc_t *acc;
111442421Syokota	int i;
111542421Syokota
111642421Syokota	acc = &kbd->kb_accentmap->acc[*accents - 1];
111742421Syokota	*accents = 0;
111842421Syokota
111942421Syokota	/*
112042421Syokota	 * If the accent key is followed by the space key,
112142421Syokota	 * produce the accent char itself.
112242421Syokota	 */
112342421Syokota	if (ch == ' ')
112442421Syokota		return acc->accchar;
112542421Syokota
112642421Syokota	/* scan the accent map */
112742421Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
112842421Syokota		if (acc->map[i][0] == 0)	/* end of table */
112942421Syokota			break;
113042421Syokota		if (acc->map[i][0] == ch)
113142421Syokota			return acc->map[i][1];
113242421Syokota	}
113342421Syokota	/* this char cannot be accented... */
113442421Syokota	return ERRKEY;
113542421Syokota}
113642421Syokota
113742421Syokotaint
113842421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
113942421Syokota		 int *accents)
114042421Syokota{
114142421Syokota	struct keyent_t *key;
114242421Syokota	int state = *shiftstate;
114342421Syokota	int action;
114442421Syokota	int f;
114542421Syokota	int i;
114642421Syokota
114754382Syokota	i = keycode;
114842421Syokota	f = state & (AGRS | ALKED);
114942421Syokota	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
115054382Syokota		i += ALTGR_OFFSET;
115154382Syokota	key = &kbd->kb_keymap->key[i];
115242421Syokota	i = ((state & SHIFTS) ? 1 : 0)
115342421Syokota	    | ((state & CTLS) ? 2 : 0)
115442421Syokota	    | ((state & ALTS) ? 4 : 0);
115542421Syokota	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
115642421Syokota		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
115742421Syokota		i ^= 1;
115842421Syokota
115942421Syokota	if (up) {	/* break: key released */
116080040Syokota		action = kbd->kb_lastact[keycode];
116180040Syokota		kbd->kb_lastact[keycode] = NOP;
116280040Syokota		switch (action) {
116380040Syokota		case LSHA:
116480040Syokota			if (state & SHIFTAON) {
116580040Syokota				set_lockkey_state(kbd, state, ALK);
116680040Syokota				state &= ~ALKDOWN;
116780040Syokota			}
116880040Syokota			action = LSH;
116980040Syokota			/* FALL THROUGH */
117080040Syokota		case LSH:
117180040Syokota			state &= ~SHIFTS1;
117280040Syokota			break;
117380040Syokota		case RSHA:
117480040Syokota			if (state & SHIFTAON) {
117580040Syokota				set_lockkey_state(kbd, state, ALK);
117680040Syokota				state &= ~ALKDOWN;
117780040Syokota			}
117880040Syokota			action = RSH;
117980040Syokota			/* FALL THROUGH */
118080040Syokota		case RSH:
118180040Syokota			state &= ~SHIFTS2;
118280040Syokota			break;
118380040Syokota		case LCTRA:
118480040Syokota			if (state & SHIFTAON) {
118580040Syokota				set_lockkey_state(kbd, state, ALK);
118680040Syokota				state &= ~ALKDOWN;
118780040Syokota			}
118880040Syokota			action = LCTR;
118980040Syokota			/* FALL THROUGH */
119080040Syokota		case LCTR:
119180040Syokota			state &= ~CTLS1;
119280040Syokota			break;
119380040Syokota		case RCTRA:
119480040Syokota			if (state & SHIFTAON) {
119580040Syokota				set_lockkey_state(kbd, state, ALK);
119680040Syokota				state &= ~ALKDOWN;
119780040Syokota			}
119880040Syokota			action = RCTR;
119980040Syokota			/* FALL THROUGH */
120080040Syokota		case RCTR:
120180040Syokota			state &= ~CTLS2;
120280040Syokota			break;
120380040Syokota		case LALTA:
120480040Syokota			if (state & SHIFTAON) {
120580040Syokota				set_lockkey_state(kbd, state, ALK);
120680040Syokota				state &= ~ALKDOWN;
120780040Syokota			}
120880040Syokota			action = LALT;
120980040Syokota			/* FALL THROUGH */
121080040Syokota		case LALT:
121180040Syokota			state &= ~ALTS1;
121280040Syokota			break;
121380040Syokota		case RALTA:
121480040Syokota			if (state & SHIFTAON) {
121580040Syokota				set_lockkey_state(kbd, state, ALK);
121680040Syokota				state &= ~ALKDOWN;
121780040Syokota			}
121880040Syokota			action = RALT;
121980040Syokota			/* FALL THROUGH */
122080040Syokota		case RALT:
122180040Syokota			state &= ~ALTS2;
122280040Syokota			break;
122380040Syokota		case ASH:
122480040Syokota			state &= ~AGRS1;
122580040Syokota			break;
122680040Syokota		case META:
122780040Syokota			state &= ~METAS1;
122880040Syokota			break;
122980040Syokota		case NLK:
123080040Syokota			state &= ~NLKDOWN;
123180040Syokota			break;
123280040Syokota		case CLK:
123342421Syokota#ifndef PC98
123480040Syokota			state &= ~CLKDOWN;
123542421Syokota#else
123680040Syokota			state &= ~CLKED;
123780040Syokota			i = state & LOCK_MASK;
123880040Syokota			(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
123980040Syokota						       (caddr_t)&i);
124042421Syokota#endif
124180040Syokota			break;
124280040Syokota		case SLK:
124380040Syokota			state &= ~SLKDOWN;
124480040Syokota			break;
124580040Syokota		case ALK:
124680040Syokota			state &= ~ALKDOWN;
124780040Syokota			break;
124880040Syokota		case NOP:
124980040Syokota			/* release events of regular keys are not reported */
125080040Syokota			*shiftstate &= ~SHIFTAON;
125180040Syokota			return NOKEY;
125242421Syokota		}
125380040Syokota		*shiftstate = state & ~SHIFTAON;
125480040Syokota		return (SPCLKEY | RELKEY | action);
125542421Syokota	} else {	/* make: key pressed */
125680040Syokota		action = key->map[i];
125755820Syokota		state &= ~SHIFTAON;
125842421Syokota		if (key->spcl & (0x80 >> i)) {
125942421Syokota			/* special keys */
126080040Syokota			if (kbd->kb_lastact[keycode] == NOP)
126180040Syokota				kbd->kb_lastact[keycode] = action;
126280040Syokota			if (kbd->kb_lastact[keycode] != action)
126380040Syokota				action = NOP;
126442421Syokota			switch (action) {
126542421Syokota			/* LOCKING KEYS */
126642421Syokota			case NLK:
126742421Syokota				set_lockkey_state(kbd, state, NLK);
126842421Syokota				break;
126942421Syokota			case CLK:
127042421Syokota#ifndef PC98
127142421Syokota				set_lockkey_state(kbd, state, CLK);
127242421Syokota#else
127342421Syokota				state |= CLKED;
127442421Syokota				i = state & LOCK_MASK;
127542421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
127642421Syokota							       (caddr_t)&i);
127742421Syokota#endif
127842421Syokota				break;
127942421Syokota			case SLK:
128042421Syokota				set_lockkey_state(kbd, state, SLK);
128142421Syokota				break;
128242421Syokota			case ALK:
128342421Syokota				set_lockkey_state(kbd, state, ALK);
128442421Syokota				break;
128542421Syokota			/* NON-LOCKING KEYS */
128642421Syokota			case SPSC: case RBT:  case SUSP: case STBY:
128754382Syokota			case DBG:  case NEXT: case PREV: case PNC:
128865759Sdwmalone			case HALT: case PDWN:
128942421Syokota				*accents = 0;
129042421Syokota				break;
129142421Syokota			case BTAB:
129242421Syokota				*accents = 0;
129342421Syokota				action |= BKEY;
129442421Syokota				break;
129554382Syokota			case LSHA:
129655820Syokota				state |= SHIFTAON;
129754382Syokota				action = LSH;
129854382Syokota				/* FALL THROUGH */
129942421Syokota			case LSH:
130042421Syokota				state |= SHIFTS1;
130142421Syokota				break;
130254382Syokota			case RSHA:
130355820Syokota				state |= SHIFTAON;
130454382Syokota				action = RSH;
130554382Syokota				/* FALL THROUGH */
130642421Syokota			case RSH:
130742421Syokota				state |= SHIFTS2;
130842421Syokota				break;
130954382Syokota			case LCTRA:
131055820Syokota				state |= SHIFTAON;
131154382Syokota				action = LCTR;
131254382Syokota				/* FALL THROUGH */
131342421Syokota			case LCTR:
131442421Syokota				state |= CTLS1;
131542421Syokota				break;
131654382Syokota			case RCTRA:
131755820Syokota				state |= SHIFTAON;
131854382Syokota				action = RCTR;
131954382Syokota				/* FALL THROUGH */
132042421Syokota			case RCTR:
132142421Syokota				state |= CTLS2;
132242421Syokota				break;
132354382Syokota			case LALTA:
132455820Syokota				state |= SHIFTAON;
132554382Syokota				action = LALT;
132654382Syokota				/* FALL THROUGH */
132742421Syokota			case LALT:
132842421Syokota				state |= ALTS1;
132942421Syokota				break;
133054382Syokota			case RALTA:
133155820Syokota				state |= SHIFTAON;
133254382Syokota				action = RALT;
133354382Syokota				/* FALL THROUGH */
133442421Syokota			case RALT:
133542421Syokota				state |= ALTS2;
133642421Syokota				break;
133742421Syokota			case ASH:
133842421Syokota				state |= AGRS1;
133942421Syokota				break;
134042421Syokota			case META:
134142421Syokota				state |= METAS1;
134242421Syokota				break;
134380040Syokota			case NOP:
134480040Syokota				*shiftstate = state;
134580040Syokota				return NOKEY;
134642421Syokota			default:
134742421Syokota				/* is this an accent (dead) key? */
134855820Syokota				*shiftstate = state;
134942421Syokota				if (action >= F_ACC && action <= L_ACC) {
135042421Syokota					action = save_accent_key(kbd, action,
135142421Syokota								 accents);
135242421Syokota					switch (action) {
135342421Syokota					case NOKEY:
135442421Syokota					case ERRKEY:
135542421Syokota						return action;
135642421Syokota					default:
135742421Syokota						if (state & METAS)
135842421Syokota							return (action | MKEY);
135942421Syokota						else
136042421Syokota							return action;
136142421Syokota					}
136242421Syokota					/* NOT REACHED */
136342421Syokota				}
136442421Syokota				/* other special keys */
136542421Syokota				if (*accents > 0) {
136642421Syokota					*accents = 0;
136742421Syokota					return ERRKEY;
136842421Syokota				}
136942421Syokota				if (action >= F_FN && action <= L_FN)
137042421Syokota					action |= FKEY;
137142421Syokota				/* XXX: return fkey string for the FKEY? */
137255820Syokota				return (SPCLKEY | action);
137342421Syokota			}
137442421Syokota			*shiftstate = state;
137542421Syokota			return (SPCLKEY | action);
137642421Syokota		} else {
137742421Syokota			/* regular keys */
137880040Syokota			kbd->kb_lastact[keycode] = NOP;
137955820Syokota			*shiftstate = state;
138042421Syokota			if (*accents > 0) {
138142421Syokota				/* make an accented char */
138242421Syokota				action = make_accent_char(kbd, action, accents);
138342421Syokota				if (action == ERRKEY)
138442421Syokota					return action;
138542421Syokota			}
138642421Syokota			if (state & METAS)
138742421Syokota				action |= MKEY;
138842421Syokota			return action;
138942421Syokota		}
139042421Syokota	}
139142421Syokota	/* NOT REACHED */
139242421Syokota}
1393