kbd.c revision 164033
142421Syokota/*-
242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
342421Syokota * All rights reserved.
442421Syokota *
542421Syokota * Redistribution and use in source and binary forms, with or without
642421Syokota * modification, are permitted provided that the following conditions
742421Syokota * are met:
842421Syokota * 1. Redistributions of source code must retain the above copyright
942421Syokota *    notice, this list of conditions and the following disclaimer as
1042421Syokota *    the first lines of this file unmodified.
1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright
1242421Syokota *    notice, this list of conditions and the following disclaimer in the
1342421Syokota *    documentation and/or other materials provided with the distribution.
1442421Syokota *
1542421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1642421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1742421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1842421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1942421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2042421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2142421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2242421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2342421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2442421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2542421Syokota *
2642421Syokota */
2742421Syokota
28119418Sobrien#include <sys/cdefs.h>
29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/kbd/kbd.c 164033 2006-11-06 13:42:10Z rwatson $");
30119418Sobrien
3142421Syokota#include "opt_kbd.h"
3242421Syokota
3342421Syokota#include <sys/param.h>
3442421Syokota#include <sys/systm.h>
3542421Syokota#include <sys/kernel.h>
3642421Syokota#include <sys/malloc.h>
3742421Syokota#include <sys/conf.h>
38139193Sphk#include <sys/fcntl.h>
3942421Syokota#include <sys/tty.h>
4042421Syokota#include <sys/poll.h>
41164033Srwatson#include <sys/priv.h>
42112050Sdwmalone#include <sys/proc.h>
43112050Sdwmalone#include <sys/sysctl.h>
4442421Syokota#include <sys/uio.h>
4542421Syokota
4666834Sphk#include <sys/kbio.h>
4742421Syokota
4842421Syokota#include <dev/kbd/kbdreg.h>
4942421Syokota
5050154Syokota#define KBD_INDEX(dev)	minor(dev)
5150154Syokota
5250154Syokotatypedef struct genkbd_softc {
5350154Syokota	int		gkb_flags;	/* flag/status bits */
5450154Syokota#define KB_ASLEEP	(1 << 0)
5550154Syokota	struct clist	gkb_q;		/* input queue */
5650154Syokota	struct selinfo	gkb_rsel;
5750154Syokota} genkbd_softc_t;
5850154Syokota
5960938Sjakestatic	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
60127751Sdes	SLIST_HEAD_INITIALIZER(keyboard_drivers);
6154545Syokota
6278161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t);
6378161Speter
6442421Syokota/* local arrays */
6542421Syokota
6642421Syokota/*
6742421Syokota * We need at least one entry each in order to initialize a keyboard
6842421Syokota * for the kernel console.  The arrays will be increased dynamically
6942421Syokota * when necessary.
7042421Syokota */
7142564Syokota
7242564Syokotastatic int		keyboards = 1;
7342421Syokotastatic keyboard_t	*kbd_ini;
7442564Syokotastatic keyboard_t	**keyboard = &kbd_ini;
7542421Syokotastatic keyboard_switch_t *kbdsw_ini;
7642421Syokota       keyboard_switch_t **kbdsw = &kbdsw_ini;
7742421Syokota
78112050Sdwmalonestatic int keymap_restrict_change;
79112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd");
80112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW,
81112050Sdwmalone    &keymap_restrict_change, 0, "restrict ability to change keymap");
82112050Sdwmalone
8342421Syokota#define ARRAY_DELTA	4
8442421Syokota
8544628Syokotastatic int
8642421Syokotakbd_realloc_array(void)
8742421Syokota{
8842421Syokota	keyboard_t **new_kbd;
8942421Syokota	keyboard_switch_t **new_kbdsw;
9042421Syokota	int newsize;
9142421Syokota	int s;
9242421Syokota
9342421Syokota	s = spltty();
9442421Syokota	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
9569781Sdwmalone	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO);
9644628Syokota	if (new_kbd == NULL) {
9744628Syokota		splx(s);
98127752Sdes		return (ENOMEM);
9944628Syokota	}
10069781Sdwmalone	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF,
10169781Sdwmalone			    M_NOWAIT|M_ZERO);
10244628Syokota	if (new_kbdsw == NULL) {
10344628Syokota		free(new_kbd, M_DEVBUF);
10444628Syokota		splx(s);
105127752Sdes		return (ENOMEM);
10644628Syokota	}
10742421Syokota	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
10842421Syokota	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
10942421Syokota	if (keyboards > 1) {
11042421Syokota		free(keyboard, M_DEVBUF);
11142421Syokota		free(kbdsw, M_DEVBUF);
11242421Syokota	}
11342421Syokota	keyboard = new_kbd;
11442421Syokota	kbdsw = new_kbdsw;
11542421Syokota	keyboards = newsize;
11642421Syokota	splx(s);
11742421Syokota
11842421Syokota	if (bootverbose)
11942421Syokota		printf("kbd: new array size %d\n", keyboards);
12044628Syokota
121127752Sdes	return (0);
12242421Syokota}
12342421Syokota
12442421Syokota/*
12542421Syokota * Low-level keyboard driver functions
12642421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
12742421Syokota * driver, call these functions to initialize the keyboard_t structure
12842421Syokota * and register it to the virtual keyboard driver `kbd'.
12942421Syokota */
13042421Syokota
13142421Syokota/* initialize the keyboard_t structure */
13242421Syokotavoid
13342421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
13442421Syokota		int port, int port_size)
13542421Syokota{
13642421Syokota	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
13742421Syokota	kbd->kb_name = name;
13842421Syokota	kbd->kb_type = type;
13942421Syokota	kbd->kb_unit = unit;
14044628Syokota	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
14142421Syokota	kbd->kb_led = 0;		/* unknown */
14242421Syokota	kbd->kb_io_base = port;
14342421Syokota	kbd->kb_io_size = port_size;
14442421Syokota	kbd->kb_data = NULL;
14542421Syokota	kbd->kb_keymap = NULL;
14642421Syokota	kbd->kb_accentmap = NULL;
14742421Syokota	kbd->kb_fkeytab = NULL;
14842421Syokota	kbd->kb_fkeytab_size = 0;
14944628Syokota	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
15044628Syokota	kbd->kb_delay2 = KB_DELAY2;
15154382Syokota	kbd->kb_count = 0L;
15280040Syokota	bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
15342421Syokota}
15442421Syokota
15542421Syokotavoid
15642421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
15742421Syokota	     fkeytab_t *fkeymap, int fkeymap_size)
15842421Syokota{
15942421Syokota	kbd->kb_keymap = keymap;
16042421Syokota	kbd->kb_accentmap = accmap;
16142421Syokota	kbd->kb_fkeytab = fkeymap;
16242421Syokota	kbd->kb_fkeytab_size = fkeymap_size;
16342421Syokota}
16442421Syokota
16554545Syokota/* declare a new keyboard driver */
16654545Syokotaint
16754545Syokotakbd_add_driver(keyboard_driver_t *driver)
16854545Syokota{
16954545Syokota	if (SLIST_NEXT(driver, link))
170127752Sdes		return (EINVAL);
17154545Syokota	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
172127752Sdes	return (0);
17354545Syokota}
17454545Syokota
17554545Syokotaint
17654545Syokotakbd_delete_driver(keyboard_driver_t *driver)
17754545Syokota{
17860938Sjake	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
17954545Syokota	SLIST_NEXT(driver, link) = NULL;
180127752Sdes	return (0);
18154545Syokota}
18254545Syokota
18342421Syokota/* register a keyboard and associate it with a function table */
18442421Syokotaint
18542421Syokotakbd_register(keyboard_t *kbd)
18642421Syokota{
18747295Syokota	const keyboard_driver_t **list;
18847295Syokota	const keyboard_driver_t *p;
189156126Semax	keyboard_t *mux;
190156126Semax	keyboard_info_t ki;
19142421Syokota	int index;
19242421Syokota
193156126Semax	mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1));
194156126Semax
19542421Syokota	for (index = 0; index < keyboards; ++index) {
19642421Syokota		if (keyboard[index] == NULL)
19742421Syokota			break;
19842421Syokota	}
19944628Syokota	if (index >= keyboards) {
20044628Syokota		if (kbd_realloc_array())
201127752Sdes			return (-1);
20244628Syokota	}
20342421Syokota
20442421Syokota	kbd->kb_index = index;
20542421Syokota	KBD_UNBUSY(kbd);
20642421Syokota	KBD_VALID(kbd);
20742421Syokota	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
20842421Syokota	kbd->kb_token = NULL;
20942421Syokota	kbd->kb_callback.kc_func = NULL;
21042421Syokota	kbd->kb_callback.kc_arg = NULL;
21142421Syokota
21254545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
21354545Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
21454545Syokota			keyboard[index] = kbd;
21554545Syokota			kbdsw[index] = p->kbdsw;
216156126Semax
217156126Semax			if (mux != NULL) {
218156126Semax				bzero(&ki, sizeof(ki));
219156126Semax				strcpy(ki.kb_name, kbd->kb_name);
220156126Semax				ki.kb_unit = kbd->kb_unit;
221156126Semax
222156126Semax				(*kbdsw[mux->kb_index]->ioctl)
223156126Semax					(mux, KBADDKBD, (caddr_t) &ki);
224156126Semax			}
225156126Semax
226127752Sdes			return (index);
22754545Syokota		}
22854545Syokota	}
22978161Speter	SET_FOREACH(list, kbddriver_set) {
23078161Speter		p = *list;
23142421Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
23242421Syokota			keyboard[index] = kbd;
23342421Syokota			kbdsw[index] = p->kbdsw;
234156126Semax
235156126Semax			if (mux != NULL) {
236156126Semax				bzero(&ki, sizeof(ki));
237156126Semax				strcpy(ki.kb_name, kbd->kb_name);
238156126Semax				ki.kb_unit = kbd->kb_unit;
239156126Semax
240156126Semax				(*kbdsw[mux->kb_index]->ioctl)
241156126Semax					(mux, KBADDKBD, (caddr_t) &ki);
242156126Semax			}
243156126Semax
244127752Sdes			return (index);
24542421Syokota		}
24642421Syokota	}
24742421Syokota
248127752Sdes	return (-1);
24942421Syokota}
25042421Syokota
25142421Syokotaint
25242421Syokotakbd_unregister(keyboard_t *kbd)
25342421Syokota{
25442421Syokota	int error;
25542421Syokota	int s;
25642421Syokota
25742421Syokota	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
258127752Sdes		return (ENOENT);
25942421Syokota	if (keyboard[kbd->kb_index] != kbd)
260127752Sdes		return (ENOENT);
26142421Syokota
26242421Syokota	s = spltty();
26342421Syokota	if (KBD_IS_BUSY(kbd)) {
26442421Syokota		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
265127752Sdes		    kbd->kb_callback.kc_arg);
26642421Syokota		if (error) {
26742421Syokota			splx(s);
268127752Sdes			return (error);
26942421Syokota		}
27042421Syokota		if (KBD_IS_BUSY(kbd)) {
27142421Syokota			splx(s);
272127752Sdes			return (EBUSY);
27342421Syokota		}
27442421Syokota	}
27542421Syokota	KBD_INVALID(kbd);
27642421Syokota	keyboard[kbd->kb_index] = NULL;
27742421Syokota	kbdsw[kbd->kb_index] = NULL;
27842421Syokota
27942421Syokota	splx(s);
280127752Sdes	return (0);
28142421Syokota}
28242421Syokota
28342421Syokota/* find a funciton table by the driver name */
28442421Syokotakeyboard_switch_t
28542421Syokota*kbd_get_switch(char *driver)
28642421Syokota{
28747295Syokota	const keyboard_driver_t **list;
28847295Syokota	const keyboard_driver_t *p;
28942421Syokota
29054545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
29154545Syokota		if (strcmp(p->name, driver) == 0)
292127752Sdes			return (p->kbdsw);
29354545Syokota	}
29478161Speter	SET_FOREACH(list, kbddriver_set) {
29578161Speter		p = *list;
29642421Syokota		if (strcmp(p->name, driver) == 0)
297127752Sdes			return (p->kbdsw);
29842421Syokota	}
29942421Syokota
300127752Sdes	return (NULL);
30142421Syokota}
30242421Syokota
30342421Syokota/*
30442421Syokota * Keyboard client functions
30542421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard
30642421Syokota * cdev driver, use these functions to claim and release a keyboard for
30742421Syokota * exclusive use.
30842421Syokota */
30942421Syokota
310147980Semax/*
311147980Semax * find the keyboard specified by a driver name and a unit number
312147980Semax * starting at given index
313147980Semax */
31442421Syokotaint
315147980Semaxkbd_find_keyboard2(char *driver, int unit, int index)
31642421Syokota{
31742421Syokota	int i;
31842421Syokota
319147980Semax	if ((index < 0) || (index >= keyboards))
320147980Semax		return (-1);
321147980Semax
322147980Semax	for (i = index; i < keyboards; ++i) {
32342421Syokota		if (keyboard[i] == NULL)
32442421Syokota			continue;
32542421Syokota		if (!KBD_IS_VALID(keyboard[i]))
32642421Syokota			continue;
32742421Syokota		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
32842421Syokota			continue;
32942421Syokota		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
33042421Syokota			continue;
331127752Sdes		return (i);
33242421Syokota	}
333147980Semax
334127752Sdes	return (-1);
33542421Syokota}
33642421Syokota
337147980Semax/* find the keyboard specified by a driver name and a unit number */
338147980Semaxint
339147980Semaxkbd_find_keyboard(char *driver, int unit)
340147980Semax{
341147980Semax	return (kbd_find_keyboard2(driver, unit, 0));
342147980Semax}
343147980Semax
34442421Syokota/* allocate a keyboard */
34542421Syokotaint
34642421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
34742421Syokota	     void *arg)
34842421Syokota{
34942421Syokota	int index;
35042421Syokota	int s;
35142421Syokota
35242421Syokota	if (func == NULL)
353127752Sdes		return (-1);
35442421Syokota
35542421Syokota	s = spltty();
35642421Syokota	index = kbd_find_keyboard(driver, unit);
35742421Syokota	if (index >= 0) {
35842421Syokota		if (KBD_IS_BUSY(keyboard[index])) {
35942421Syokota			splx(s);
360127752Sdes			return (-1);
36142421Syokota		}
36242421Syokota		keyboard[index]->kb_token = id;
36342421Syokota		KBD_BUSY(keyboard[index]);
36442421Syokota		keyboard[index]->kb_callback.kc_func = func;
36542421Syokota		keyboard[index]->kb_callback.kc_arg = arg;
36642421Syokota		(*kbdsw[index]->clear_state)(keyboard[index]);
36742421Syokota	}
36842421Syokota	splx(s);
369127752Sdes	return (index);
37042421Syokota}
37142421Syokota
37242421Syokotaint
37342421Syokotakbd_release(keyboard_t *kbd, void *id)
37442421Syokota{
37542421Syokota	int error;
37642421Syokota	int s;
37742421Syokota
37842421Syokota	s = spltty();
37942421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
38042421Syokota		error = EINVAL;
38142421Syokota	} else if (kbd->kb_token != id) {
38242421Syokota		error = EPERM;
38342421Syokota	} else {
38442421Syokota		kbd->kb_token = NULL;
38542421Syokota		KBD_UNBUSY(kbd);
38642421Syokota		kbd->kb_callback.kc_func = NULL;
38742421Syokota		kbd->kb_callback.kc_arg = NULL;
38842421Syokota		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
38942421Syokota		error = 0;
39042421Syokota	}
39142421Syokota	splx(s);
392127752Sdes	return (error);
39342421Syokota}
39442421Syokota
39542421Syokotaint
39642421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
39742421Syokota		    void *arg)
39842421Syokota{
39942421Syokota	int error;
40042421Syokota	int s;
40142421Syokota
40242421Syokota	s = spltty();
40342421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
40442421Syokota		error = EINVAL;
40542421Syokota	} else if (kbd->kb_token != id) {
40642421Syokota		error = EPERM;
40742421Syokota	} else if (func == NULL) {
40842421Syokota		error = EINVAL;
40942421Syokota	} else {
41042421Syokota		kbd->kb_callback.kc_func = func;
41142421Syokota		kbd->kb_callback.kc_arg = arg;
41242421Syokota		error = 0;
41342421Syokota	}
41442421Syokota	splx(s);
415127752Sdes	return (error);
41642421Syokota}
41742421Syokota
41842421Syokota/* get a keyboard structure */
41942421Syokotakeyboard_t
42042421Syokota*kbd_get_keyboard(int index)
42142421Syokota{
42242421Syokota	if ((index < 0) || (index >= keyboards))
423127752Sdes		return (NULL);
42450154Syokota	if (keyboard[index] == NULL)
425127752Sdes		return (NULL);
42642421Syokota	if (!KBD_IS_VALID(keyboard[index]))
427127752Sdes		return (NULL);
428127752Sdes	return (keyboard[index]);
42942421Syokota}
43042421Syokota
43142421Syokota/*
43242421Syokota * The back door for the console driver; configure keyboards
43342421Syokota * This function is for the kernel console to initialize keyboards
43442421Syokota * at very early stage.
43542421Syokota */
43642421Syokota
43742421Syokotaint
43842421Syokotakbd_configure(int flags)
43942421Syokota{
44047295Syokota	const keyboard_driver_t **list;
44147295Syokota	const keyboard_driver_t *p;
44242421Syokota
44354545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
44454545Syokota		if (p->configure != NULL)
44554545Syokota			(*p->configure)(flags);
44654545Syokota	}
44778161Speter	SET_FOREACH(list, kbddriver_set) {
44878161Speter		p = *list;
44942421Syokota		if (p->configure != NULL)
45042421Syokota			(*p->configure)(flags);
45142421Syokota	}
45242421Syokota
453127752Sdes	return (0);
45442421Syokota}
45542421Syokota
45642421Syokota#ifdef KBD_INSTALL_CDEV
45742421Syokota
45842421Syokota/*
45942421Syokota * Virtual keyboard cdev driver functions
46042421Syokota * The virtual keyboard driver dispatches driver functions to
46142421Syokota * appropriate subdrivers.
46242421Syokota */
46342421Syokota
46442421Syokota#define KBD_UNIT(dev)	minor(dev)
46542421Syokota
46650154Syokotastatic d_open_t		genkbdopen;
46750154Syokotastatic d_close_t	genkbdclose;
46850154Syokotastatic d_read_t		genkbdread;
46950154Syokotastatic d_write_t	genkbdwrite;
47050154Syokotastatic d_ioctl_t	genkbdioctl;
47150154Syokotastatic d_poll_t		genkbdpoll;
47242421Syokota
47342421Syokota
47442421Syokotastatic struct cdevsw kbd_cdevsw = {
475126080Sphk	.d_version =	D_VERSION,
476126080Sphk	.d_flags =	D_NEEDGIANT,
477111815Sphk	.d_open =	genkbdopen,
478111815Sphk	.d_close =	genkbdclose,
479111815Sphk	.d_read =	genkbdread,
480111815Sphk	.d_write =	genkbdwrite,
481111815Sphk	.d_ioctl =	genkbdioctl,
482111815Sphk	.d_poll =	genkbdpoll,
483111815Sphk	.d_name =	"kbd",
48442421Syokota};
48542421Syokota
48642421Syokotaint
48750154Syokotakbd_attach(keyboard_t *kbd)
48842421Syokota{
48942421Syokota
49042421Syokota	if (kbd->kb_index >= keyboards)
491127752Sdes		return (EINVAL);
49242421Syokota	if (keyboard[kbd->kb_index] != kbd)
493127752Sdes		return (EINVAL);
49442421Syokota
495127751Sdes	kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL,
496127751Sdes	    0600, "%s%r", kbd->kb_name, kbd->kb_unit);
497125087Sdes	make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index);
498120502Sphk	kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
499127751Sdes	    M_WAITOK | M_ZERO);
50042421Syokota	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
501127752Sdes	return (0);
50242421Syokota}
50342421Syokota
50442421Syokotaint
50550154Syokotakbd_detach(keyboard_t *kbd)
50642421Syokota{
50754545Syokota
50842421Syokota	if (kbd->kb_index >= keyboards)
509127752Sdes		return (EINVAL);
51042421Syokota	if (keyboard[kbd->kb_index] != kbd)
511127752Sdes		return (EINVAL);
51242421Syokota
513120502Sphk	free(kbd->kb_dev->si_drv1, M_DEVBUF);
514120502Sphk	destroy_dev(kbd->kb_dev);
51554545Syokota
516127752Sdes	return (0);
51742421Syokota}
51842421Syokota
51942421Syokota/*
52042421Syokota * Generic keyboard cdev driver functions
52142421Syokota * Keyboard subdrivers may call these functions to implement common
52242421Syokota * driver functions.
52342421Syokota */
52442421Syokota
52542421Syokota#define KB_QSIZE	512
52642421Syokota#define KB_BUFSIZE	64
52742421Syokota
52842421Syokotastatic kbd_callback_func_t genkbd_event;
52942421Syokota
53050154Syokotastatic int
531130585Sphkgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td)
53242421Syokota{
53350154Syokota	keyboard_t *kbd;
53450154Syokota	genkbd_softc_t *sc;
53542421Syokota	int s;
53642421Syokota	int i;
53742421Syokota
53842421Syokota	s = spltty();
53950154Syokota	sc = dev->si_drv1;
54050154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
54150154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
54242421Syokota		splx(s);
543127752Sdes		return (ENXIO);
54442421Syokota	}
54542421Syokota	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
546127751Sdes	    genkbd_event, (void *)sc);
54742421Syokota	if (i < 0) {
54842421Syokota		splx(s);
549127752Sdes		return (EBUSY);
55042421Syokota	}
55142421Syokota	/* assert(i == kbd->kb_index) */
55242421Syokota	/* assert(kbd == kbd_get_keyboard(i)) */
55342421Syokota
55442421Syokota	/*
55542421Syokota	 * NOTE: even when we have successfully claimed a keyboard,
55642421Syokota	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
55742421Syokota	 */
55842421Syokota
55942421Syokota#if 0
56042421Syokota	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
56142421Syokota#endif
56242421Syokota	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
56342421Syokota	splx(s);
56442421Syokota
565127752Sdes	return (0);
56642421Syokota}
56742421Syokota
56850154Syokotastatic int
569130585Sphkgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td)
57042421Syokota{
57150154Syokota	keyboard_t *kbd;
57250154Syokota	genkbd_softc_t *sc;
57342421Syokota	int s;
57442421Syokota
57542421Syokota	/*
57642421Syokota	 * NOTE: the device may have already become invalid.
57750154Syokota	 * kbd == NULL || !KBD_IS_VALID(kbd)
57842421Syokota	 */
57942421Syokota	s = spltty();
58050154Syokota	sc = dev->si_drv1;
58150154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
58250154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
58350154Syokota		/* XXX: we shall be forgiving and don't report error... */
58450154Syokota	} else {
58550154Syokota		kbd_release(kbd, (void *)sc);
58642421Syokota#if 0
58750154Syokota		clist_free_cblocks(&sc->gkb_q);
58842421Syokota#endif
58950154Syokota	}
59042421Syokota	splx(s);
591127752Sdes	return (0);
59242421Syokota}
59342421Syokota
59450154Syokotastatic int
595130585Sphkgenkbdread(struct cdev *dev, struct uio *uio, int flag)
59642421Syokota{
59750154Syokota	keyboard_t *kbd;
59850154Syokota	genkbd_softc_t *sc;
59942421Syokota	u_char buffer[KB_BUFSIZE];
60042421Syokota	int len;
60142421Syokota	int error;
60242421Syokota	int s;
60342421Syokota
60442421Syokota	/* wait for input */
60542421Syokota	s = spltty();
60650154Syokota	sc = dev->si_drv1;
60750154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
60850154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
60950154Syokota		splx(s);
610127752Sdes		return (ENXIO);
61150154Syokota	}
61242421Syokota	while (sc->gkb_q.c_cc == 0) {
613139193Sphk		if (flag & O_NONBLOCK) {
61442421Syokota			splx(s);
615127752Sdes			return (EWOULDBLOCK);
61642421Syokota		}
61742421Syokota		sc->gkb_flags |= KB_ASLEEP;
618111748Sdes		error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0);
61950154Syokota		kbd = kbd_get_keyboard(KBD_INDEX(dev));
62050154Syokota		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
62150154Syokota			splx(s);
622127752Sdes			return (ENXIO);	/* our keyboard has gone... */
62350154Syokota		}
62442421Syokota		if (error) {
62542421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
62642421Syokota			splx(s);
627127752Sdes			return (error);
62842421Syokota		}
62942421Syokota	}
63042421Syokota	splx(s);
63142421Syokota
63242421Syokota	/* copy as much input as possible */
63342421Syokota	error = 0;
63442421Syokota	while (uio->uio_resid > 0) {
63542421Syokota		len = imin(uio->uio_resid, sizeof(buffer));
63642421Syokota		len = q_to_b(&sc->gkb_q, buffer, len);
63742421Syokota		if (len <= 0)
63842421Syokota			break;
63942421Syokota		error = uiomove(buffer, len, uio);
64042421Syokota		if (error)
64142421Syokota			break;
64242421Syokota	}
64342421Syokota
644127752Sdes	return (error);
64542421Syokota}
64642421Syokota
64750154Syokotastatic int
648130585Sphkgenkbdwrite(struct cdev *dev, struct uio *uio, int flag)
64942421Syokota{
65050154Syokota	keyboard_t *kbd;
65150154Syokota
65250154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
65350154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
654127752Sdes		return (ENXIO);
655127752Sdes	return (ENODEV);
65642421Syokota}
65742421Syokota
65850154Syokotastatic int
659130585Sphkgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
66042421Syokota{
66150154Syokota	keyboard_t *kbd;
66242421Syokota	int error;
66342421Syokota
66450154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
66550154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
666127752Sdes		return (ENXIO);
66742421Syokota	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
66842421Syokota	if (error == ENOIOCTL)
66942421Syokota		error = ENODEV;
670127752Sdes	return (error);
67142421Syokota}
67242421Syokota
67350154Syokotastatic int
674130585Sphkgenkbdpoll(struct cdev *dev, int events, struct thread *td)
67542421Syokota{
67650154Syokota	keyboard_t *kbd;
67750154Syokota	genkbd_softc_t *sc;
67842421Syokota	int revents;
67942421Syokota	int s;
68042421Syokota
68142421Syokota	revents = 0;
68242421Syokota	s = spltty();
68350154Syokota	sc = dev->si_drv1;
68450154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
68550154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
68650154Syokota		revents =  POLLHUP;	/* the keyboard has gone */
68750154Syokota	} else if (events & (POLLIN | POLLRDNORM)) {
68850154Syokota		if (sc->gkb_q.c_cc > 0)
68950154Syokota			revents = events & (POLLIN | POLLRDNORM);
69042421Syokota		else
69183366Sjulian			selrecord(td, &sc->gkb_rsel);
69242421Syokota	}
69342421Syokota	splx(s);
694127752Sdes	return (revents);
69542421Syokota}
69642421Syokota
69742421Syokotastatic int
69842421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg)
69942421Syokota{
70042421Syokota	genkbd_softc_t *sc;
70142421Syokota	size_t len;
70242421Syokota	u_char *cp;
70342421Syokota	int mode;
70442421Syokota	int c;
70542421Syokota
70642421Syokota	/* assert(KBD_IS_VALID(kbd)) */
70742421Syokota	sc = (genkbd_softc_t *)arg;
70842421Syokota
70942421Syokota	switch (event) {
71042421Syokota	case KBDIO_KEYINPUT:
71142421Syokota		break;
71242421Syokota	case KBDIO_UNLOADING:
71342421Syokota		/* the keyboard is going... */
71442421Syokota		kbd_release(kbd, (void *)sc);
71550154Syokota		if (sc->gkb_flags & KB_ASLEEP) {
71650154Syokota			sc->gkb_flags &= ~KB_ASLEEP;
717111748Sdes			wakeup(sc);
71850154Syokota		}
719122352Stanimura		selwakeuppri(&sc->gkb_rsel, PZERO);
720127752Sdes		return (0);
72142421Syokota	default:
722127752Sdes		return (EINVAL);
72342421Syokota	}
72442421Syokota
72542421Syokota	/* obtain the current key input mode */
72642421Syokota	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
72742421Syokota		mode = K_XLATE;
72842421Syokota
72942421Syokota	/* read all pending input */
73042421Syokota	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
73142421Syokota		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
73242421Syokota		if (c == NOKEY)
73342421Syokota			continue;
73442421Syokota		if (c == ERRKEY)	/* XXX: ring bell? */
73542421Syokota			continue;
73642421Syokota		if (!KBD_IS_BUSY(kbd))
73742421Syokota			/* the device is not open, discard the input */
73842421Syokota			continue;
73942421Syokota
74042421Syokota		/* store the byte as is for K_RAW and K_CODE modes */
74142421Syokota		if (mode != K_XLATE) {
74242421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
74342421Syokota			continue;
74442421Syokota		}
74542421Syokota
74642421Syokota		/* K_XLATE */
74742421Syokota		if (c & RELKEY)	/* key release is ignored */
74842421Syokota			continue;
74942421Syokota
75042421Syokota		/* process special keys; most of them are just ignored... */
75142421Syokota		if (c & SPCLKEY) {
75242421Syokota			switch (KEYCHAR(c)) {
75354382Syokota			default:
75442421Syokota				/* ignore them... */
75542421Syokota				continue;
75642421Syokota			case BTAB:	/* a backtab: ESC [ Z */
75742421Syokota				putc(0x1b, &sc->gkb_q);
75842421Syokota				putc('[', &sc->gkb_q);
75942421Syokota				putc('Z', &sc->gkb_q);
76042421Syokota				continue;
76142421Syokota			}
76242421Syokota		}
76342421Syokota
76442421Syokota		/* normal chars, normal chars with the META, function keys */
76542421Syokota		switch (KEYFLAGS(c)) {
76642421Syokota		case 0:			/* a normal char */
76742421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
76842421Syokota			break;
76942421Syokota		case MKEY:		/* the META flag: prepend ESC */
77042421Syokota			putc(0x1b, &sc->gkb_q);
77142421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
77242421Syokota			break;
77342421Syokota		case FKEY | SPCLKEY:	/* a function key, return string */
77442421Syokota			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
775127751Sdes			    KEYCHAR(c), &len);
77642421Syokota			if (cp != NULL) {
77742421Syokota				while (len-- >  0)
77842421Syokota					putc(*cp++, &sc->gkb_q);
77942421Syokota			}
78042421Syokota			break;
78142421Syokota		}
78242421Syokota	}
78342421Syokota
78442421Syokota	/* wake up sleeping/polling processes */
78542421Syokota	if (sc->gkb_q.c_cc > 0) {
78642421Syokota		if (sc->gkb_flags & KB_ASLEEP) {
78742421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
788111748Sdes			wakeup(sc);
78942421Syokota		}
790122352Stanimura		selwakeuppri(&sc->gkb_rsel, PZERO);
79142421Syokota	}
79242421Syokota
793127752Sdes	return (0);
79442421Syokota}
79542421Syokota
79642421Syokota#endif /* KBD_INSTALL_CDEV */
79742421Syokota
79842421Syokota/*
79942421Syokota * Generic low-level keyboard functions
80042421Syokota * The low-level functions in the keyboard subdriver may use these
80142421Syokota * functions.
80242421Syokota */
80342421Syokota
804112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
805112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *);
806112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *);
807112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *);
808112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *);
809112050Sdwmalone#endif
810112050Sdwmalone
81142421Syokotaint
81242421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
81342421Syokota{
81442421Syokota	keyarg_t *keyp;
81542421Syokota	fkeyarg_t *fkeyp;
81642421Syokota	int s;
81742421Syokota	int i;
818112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
819112050Sdwmalone	int error;
820112050Sdwmalone#endif
82142421Syokota
82242421Syokota	s = spltty();
82342421Syokota	switch (cmd) {
82442421Syokota
82542421Syokota	case KDGKBINFO:		/* get keyboard information */
82642421Syokota		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
82742421Syokota		i = imin(strlen(kbd->kb_name) + 1,
828127751Sdes		    sizeof(((keyboard_info_t *)arg)->kb_name));
82942421Syokota		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
83042421Syokota		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
83142421Syokota		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
83242421Syokota		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
83342421Syokota		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
83442421Syokota		break;
83542421Syokota
83642421Syokota	case KDGKBTYPE:		/* get keyboard type */
83742421Syokota		*(int *)arg = kbd->kb_type;
83842421Syokota		break;
83942421Syokota
84054543Syokota	case KDGETREPEAT:	/* get keyboard repeat rate */
84154543Syokota		((int *)arg)[0] = kbd->kb_delay1;
842127751Sdes		((int *)arg)[1] = kbd->kb_delay2;
84354543Syokota		break;
84454543Syokota
84542421Syokota	case GIO_KEYMAP:	/* get keyboard translation table */
84642421Syokota		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
84742421Syokota		break;
84842421Syokota	case PIO_KEYMAP:	/* set keyboard translation table */
84944628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
850112050Sdwmalone		error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg,
851112050Sdwmalone		    curthread);
852112050Sdwmalone		if (error != 0) {
853112050Sdwmalone			splx(s);
854127752Sdes			return (error);
855112050Sdwmalone		}
85642421Syokota		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
85742421Syokota		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
85842421Syokota		break;
85944628Syokota#else
86044628Syokota		splx(s);
861127752Sdes		return (ENODEV);
86244628Syokota#endif
86342421Syokota
86442421Syokota	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
86542421Syokota		keyp = (keyarg_t *)arg;
866127751Sdes		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
867127751Sdes		    sizeof(kbd->kb_keymap->key[0])) {
86842421Syokota			splx(s);
869127752Sdes			return (EINVAL);
87042421Syokota		}
87142573Syokota		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
872127751Sdes		    sizeof(keyp->key));
87342421Syokota		break;
87442421Syokota	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
87544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
87642421Syokota		keyp = (keyarg_t *)arg;
877127751Sdes		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
878127751Sdes		    sizeof(kbd->kb_keymap->key[0])) {
87942421Syokota			splx(s);
880127752Sdes			return (EINVAL);
88142421Syokota		}
882112050Sdwmalone		error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum],
883112050Sdwmalone		    &keyp->key, curthread);
884112050Sdwmalone		if (error != 0) {
885112050Sdwmalone			splx(s);
886127752Sdes			return (error);
887112050Sdwmalone		}
88842573Syokota		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
889127751Sdes		    sizeof(keyp->key));
89042421Syokota		break;
89144628Syokota#else
89244628Syokota		splx(s);
893127752Sdes		return (ENODEV);
89444628Syokota#endif
89542421Syokota
89642421Syokota	case GIO_DEADKEYMAP:	/* get accent key translation table */
89742421Syokota		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
89842421Syokota		break;
89942421Syokota	case PIO_DEADKEYMAP:	/* set accent key translation table */
90044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
901112050Sdwmalone		error = accent_change_ok(kbd->kb_accentmap,
902112050Sdwmalone		    (accentmap_t *)arg, curthread);
903112050Sdwmalone		if (error != 0) {
904112050Sdwmalone			splx(s);
905127752Sdes			return (error);
906112050Sdwmalone		}
90742421Syokota		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
90842421Syokota		break;
90944628Syokota#else
91044628Syokota		splx(s);
911127752Sdes		return (ENODEV);
91244628Syokota#endif
91342421Syokota
91442421Syokota	case GETFKEY:		/* get functionkey string */
91542421Syokota		fkeyp = (fkeyarg_t *)arg;
91642421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
91742421Syokota			splx(s);
918127752Sdes			return (EINVAL);
91942421Syokota		}
92042421Syokota		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
921127751Sdes		    kbd->kb_fkeytab[fkeyp->keynum].len);
92242421Syokota		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
92342421Syokota		break;
92442421Syokota	case SETFKEY:		/* set functionkey string */
92544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
92642421Syokota		fkeyp = (fkeyarg_t *)arg;
92742421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
92842421Syokota			splx(s);
929127752Sdes			return (EINVAL);
93042421Syokota		}
931112050Sdwmalone		error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum],
932112050Sdwmalone		    fkeyp, curthread);
933112050Sdwmalone		if (error != 0) {
934112050Sdwmalone			splx(s);
935127752Sdes			return (error);
936112050Sdwmalone		}
93742421Syokota		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
93842421Syokota		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
939127751Sdes		    kbd->kb_fkeytab[fkeyp->keynum].len);
94042421Syokota		break;
94144628Syokota#else
94244628Syokota		splx(s);
943127752Sdes		return (ENODEV);
94444628Syokota#endif
94542421Syokota
94642421Syokota	default:
94742421Syokota		splx(s);
948127752Sdes		return (ENOIOCTL);
94942421Syokota	}
95042421Syokota
95142421Syokota	splx(s);
952127752Sdes	return (0);
95342421Syokota}
95442421Syokota
955112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
956112050Sdwmalone#define RESTRICTED_KEY(key, i) \
957112050Sdwmalone	((key->spcl & (0x80 >> i)) && \
958112050Sdwmalone		(key->map[i] == RBT || key->map[i] == SUSP || \
959112050Sdwmalone		 key->map[i] == STBY || key->map[i] == DBG || \
960112050Sdwmalone		 key->map[i] == PNC || key->map[i] == HALT || \
961112050Sdwmalone		 key->map[i] == PDWN))
962112050Sdwmalone
963112050Sdwmalonestatic int
964112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td)
965112050Sdwmalone{
966112050Sdwmalone	int i;
967112050Sdwmalone
968112050Sdwmalone	/* Low keymap_restrict_change means any changes are OK. */
969112050Sdwmalone	if (keymap_restrict_change <= 0)
970127752Sdes		return (0);
971112050Sdwmalone
972112050Sdwmalone	/* High keymap_restrict_change means only root can change the keymap. */
973112050Sdwmalone	if (keymap_restrict_change >= 2) {
974112050Sdwmalone		for (i = 0; i < NUM_STATES; i++)
975112050Sdwmalone			if (oldkey->map[i] != newkey->map[i])
976164033Srwatson				return priv_check(td, PRIV_KEYBOARD);
977112050Sdwmalone		if (oldkey->spcl != newkey->spcl)
978164033Srwatson			return priv_check(td, PRIV_KEYBOARD);
979112050Sdwmalone		if (oldkey->flgs != newkey->flgs)
980164033Srwatson			return priv_check(td, PRIV_KEYBOARD);
981127752Sdes		return (0);
982112050Sdwmalone	}
983112050Sdwmalone
984112050Sdwmalone	/* Otherwise we have to see if any special keys are being changed. */
985112050Sdwmalone	for (i = 0; i < NUM_STATES; i++) {
986112050Sdwmalone		/*
987112050Sdwmalone		 * If either the oldkey or the newkey action is restricted
988112050Sdwmalone		 * then we must make sure that the action doesn't change.
989112050Sdwmalone		 */
990112050Sdwmalone		if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i))
991112050Sdwmalone			continue;
992112050Sdwmalone		if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i))
993112050Sdwmalone		    && oldkey->map[i] == newkey->map[i])
994112050Sdwmalone			continue;
995164033Srwatson		return priv_check(td, PRIV_KEYBOARD);
996112050Sdwmalone	}
997112050Sdwmalone
998127752Sdes	return (0);
999112050Sdwmalone}
1000112050Sdwmalone
1001112050Sdwmalonestatic int
1002112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td)
1003112050Sdwmalone{
1004112050Sdwmalone	int keycode, error;
1005112050Sdwmalone
1006112050Sdwmalone	for (keycode = 0; keycode < NUM_KEYS; keycode++) {
1007112050Sdwmalone		if ((error = key_change_ok(&oldmap->key[keycode],
1008112050Sdwmalone		    &newmap->key[keycode], td)) != 0)
1009127752Sdes			return (error);
1010112050Sdwmalone	}
1011127752Sdes	return (0);
1012112050Sdwmalone}
1013112050Sdwmalone
1014112050Sdwmalonestatic int
1015112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td)
1016112050Sdwmalone{
1017112050Sdwmalone	struct acc_t *oldacc, *newacc;
1018112050Sdwmalone	int accent, i;
1019112050Sdwmalone
1020112050Sdwmalone	if (keymap_restrict_change <= 2)
1021127752Sdes		return (0);
1022112050Sdwmalone
1023112050Sdwmalone	if (oldmap->n_accs != newmap->n_accs)
1024164033Srwatson		return priv_check(td, PRIV_KEYBOARD);
1025112050Sdwmalone
1026112050Sdwmalone	for (accent = 0; accent < oldmap->n_accs; accent++) {
1027112050Sdwmalone		oldacc = &oldmap->acc[accent];
1028112050Sdwmalone		newacc = &newmap->acc[accent];
1029112050Sdwmalone		if (oldacc->accchar != newacc->accchar)
1030164033Srwatson			return priv_check(td, PRIV_KEYBOARD);
1031112050Sdwmalone		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1032112050Sdwmalone			if (oldacc->map[i][0] != newacc->map[i][0])
1033164033Srwatson				return priv_check(td, PRIV_KEYBOARD);
1034112050Sdwmalone			if (oldacc->map[i][0] == 0)	/* end of table */
1035112050Sdwmalone				break;
1036112050Sdwmalone			if (oldacc->map[i][1] != newacc->map[i][1])
1037164033Srwatson				return priv_check(td, PRIV_KEYBOARD);
1038112050Sdwmalone		}
1039112050Sdwmalone	}
1040112050Sdwmalone
1041127752Sdes	return (0);
1042112050Sdwmalone}
1043112050Sdwmalone
1044112050Sdwmalonestatic int
1045112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td)
1046112050Sdwmalone{
1047112050Sdwmalone	if (keymap_restrict_change <= 3)
1048127752Sdes		return (0);
1049112050Sdwmalone
1050112050Sdwmalone	if (oldkey->len != newkey->flen ||
1051112050Sdwmalone	    bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0)
1052164033Srwatson		return priv_check(td, PRIV_KEYBOARD);
1053112050Sdwmalone
1054127752Sdes	return (0);
1055112050Sdwmalone}
1056112050Sdwmalone#endif
1057112050Sdwmalone
105842421Syokota/* get a pointer to the string associated with the given function key */
105942421Syokotau_char
106042421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
106142421Syokota{
106242421Syokota	if (kbd == NULL)
1063127752Sdes		return (NULL);
106442421Syokota	fkey -= F_FN;
106542421Syokota	if (fkey > kbd->kb_fkeytab_size)
1066127752Sdes		return (NULL);
106742421Syokota	*len = kbd->kb_fkeytab[fkey].len;
1068127752Sdes	return (kbd->kb_fkeytab[fkey].str);
106942421Syokota}
107042421Syokota
107142421Syokota/* diagnostic dump */
107242421Syokotastatic char
107342421Syokota*get_kbd_type_name(int type)
107442421Syokota{
107542421Syokota	static struct {
107642421Syokota		int type;
107742421Syokota		char *name;
107842421Syokota	} name_table[] = {
107942421Syokota		{ KB_84,	"AT 84" },
108042421Syokota		{ KB_101,	"AT 101/102" },
108142421Syokota		{ KB_OTHER,	"generic" },
108242421Syokota	};
108342421Syokota	int i;
108442421Syokota
108542421Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
108642421Syokota		if (type == name_table[i].type)
1087127752Sdes			return (name_table[i].name);
108842421Syokota	}
1089127752Sdes	return ("unknown");
109042421Syokota}
109142421Syokota
109242421Syokotavoid
109342421Syokotagenkbd_diag(keyboard_t *kbd, int level)
109442421Syokota{
109542421Syokota	if (level > 0) {
1096127751Sdes		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
1097127751Sdes		    kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1098127751Sdes		    get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1099127751Sdes		    kbd->kb_config, kbd->kb_flags);
110042421Syokota		if (kbd->kb_io_base > 0)
1101127751Sdes			printf(", port:0x%x-0x%x", kbd->kb_io_base,
1102127751Sdes			    kbd->kb_io_base + kbd->kb_io_size - 1);
110342421Syokota		printf("\n");
110442421Syokota	}
110542421Syokota}
110642421Syokota
110742421Syokota#define set_lockkey_state(k, s, l)				\
110842421Syokota	if (!((s) & l ## DOWN)) {				\
110942421Syokota		int i;						\
111042421Syokota		(s) |= l ## DOWN;				\
111142421Syokota		(s) ^= l ## ED;					\
111242421Syokota		i = (s) & LOCK_MASK;				\
111342421Syokota		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
111442421Syokota	}
111542421Syokota
111642421Syokotastatic u_int
111742421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents)
111842421Syokota{
111942421Syokota	int i;
112042421Syokota
112142421Syokota	/* make an index into the accent map */
112242421Syokota	i = key - F_ACC + 1;
112342421Syokota	if ((i > kbd->kb_accentmap->n_accs)
112442421Syokota	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
112542421Syokota		/* the index is out of range or pointing to an empty entry */
112642421Syokota		*accents = 0;
1127127752Sdes		return (ERRKEY);
112842421Syokota	}
112942421Syokota
1130127751Sdes	/*
1131127751Sdes	 * If the same accent key has been hit twice, produce the accent
1132127751Sdes	 * char itself.
113342421Syokota	 */
113442421Syokota	if (i == *accents) {
113542421Syokota		key = kbd->kb_accentmap->acc[i - 1].accchar;
113642421Syokota		*accents = 0;
1137127752Sdes		return (key);
113842421Syokota	}
113942421Syokota
114042421Syokota	/* remember the index and wait for the next key  */
1141127751Sdes	*accents = i;
1142127752Sdes	return (NOKEY);
114342421Syokota}
114442421Syokota
114542421Syokotastatic u_int
114642421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents)
114742421Syokota{
114842421Syokota	struct acc_t *acc;
114942421Syokota	int i;
115042421Syokota
115142421Syokota	acc = &kbd->kb_accentmap->acc[*accents - 1];
115242421Syokota	*accents = 0;
115342421Syokota
1154127751Sdes	/*
115542421Syokota	 * If the accent key is followed by the space key,
115642421Syokota	 * produce the accent char itself.
115742421Syokota	 */
115842421Syokota	if (ch == ' ')
1159127752Sdes		return (acc->accchar);
116042421Syokota
116142421Syokota	/* scan the accent map */
116242421Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
116342421Syokota		if (acc->map[i][0] == 0)	/* end of table */
116442421Syokota			break;
116542421Syokota		if (acc->map[i][0] == ch)
1166127752Sdes			return (acc->map[i][1]);
116742421Syokota	}
116842421Syokota	/* this char cannot be accented... */
1169127752Sdes	return (ERRKEY);
117042421Syokota}
117142421Syokota
117242421Syokotaint
117342421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
117442421Syokota		 int *accents)
117542421Syokota{
117642421Syokota	struct keyent_t *key;
117742421Syokota	int state = *shiftstate;
117842421Syokota	int action;
117942421Syokota	int f;
118042421Syokota	int i;
118142421Syokota
118254382Syokota	i = keycode;
118342421Syokota	f = state & (AGRS | ALKED);
118442421Syokota	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
118554382Syokota		i += ALTGR_OFFSET;
118654382Syokota	key = &kbd->kb_keymap->key[i];
118742421Syokota	i = ((state & SHIFTS) ? 1 : 0)
118842421Syokota	    | ((state & CTLS) ? 2 : 0)
118942421Syokota	    | ((state & ALTS) ? 4 : 0);
119042421Syokota	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
119142421Syokota		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
119242421Syokota		i ^= 1;
119342421Syokota
119442421Syokota	if (up) {	/* break: key released */
119580040Syokota		action = kbd->kb_lastact[keycode];
119680040Syokota		kbd->kb_lastact[keycode] = NOP;
119780040Syokota		switch (action) {
119880040Syokota		case LSHA:
119980040Syokota			if (state & SHIFTAON) {
120080040Syokota				set_lockkey_state(kbd, state, ALK);
120180040Syokota				state &= ~ALKDOWN;
120280040Syokota			}
120380040Syokota			action = LSH;
120480040Syokota			/* FALL THROUGH */
120580040Syokota		case LSH:
120680040Syokota			state &= ~SHIFTS1;
120780040Syokota			break;
120880040Syokota		case RSHA:
120980040Syokota			if (state & SHIFTAON) {
121080040Syokota				set_lockkey_state(kbd, state, ALK);
121180040Syokota				state &= ~ALKDOWN;
121280040Syokota			}
121380040Syokota			action = RSH;
121480040Syokota			/* FALL THROUGH */
121580040Syokota		case RSH:
121680040Syokota			state &= ~SHIFTS2;
121780040Syokota			break;
121880040Syokota		case LCTRA:
121980040Syokota			if (state & SHIFTAON) {
122080040Syokota				set_lockkey_state(kbd, state, ALK);
122180040Syokota				state &= ~ALKDOWN;
122280040Syokota			}
122380040Syokota			action = LCTR;
122480040Syokota			/* FALL THROUGH */
122580040Syokota		case LCTR:
122680040Syokota			state &= ~CTLS1;
122780040Syokota			break;
122880040Syokota		case RCTRA:
122980040Syokota			if (state & SHIFTAON) {
123080040Syokota				set_lockkey_state(kbd, state, ALK);
123180040Syokota				state &= ~ALKDOWN;
123280040Syokota			}
123380040Syokota			action = RCTR;
123480040Syokota			/* FALL THROUGH */
123580040Syokota		case RCTR:
123680040Syokota			state &= ~CTLS2;
123780040Syokota			break;
123880040Syokota		case LALTA:
123980040Syokota			if (state & SHIFTAON) {
124080040Syokota				set_lockkey_state(kbd, state, ALK);
124180040Syokota				state &= ~ALKDOWN;
124280040Syokota			}
124380040Syokota			action = LALT;
124480040Syokota			/* FALL THROUGH */
124580040Syokota		case LALT:
124680040Syokota			state &= ~ALTS1;
124780040Syokota			break;
124880040Syokota		case RALTA:
124980040Syokota			if (state & SHIFTAON) {
125080040Syokota				set_lockkey_state(kbd, state, ALK);
125180040Syokota				state &= ~ALKDOWN;
125280040Syokota			}
125380040Syokota			action = RALT;
125480040Syokota			/* FALL THROUGH */
125580040Syokota		case RALT:
125680040Syokota			state &= ~ALTS2;
125780040Syokota			break;
125880040Syokota		case ASH:
125980040Syokota			state &= ~AGRS1;
126080040Syokota			break;
126180040Syokota		case META:
126280040Syokota			state &= ~METAS1;
126380040Syokota			break;
126480040Syokota		case NLK:
126580040Syokota			state &= ~NLKDOWN;
126680040Syokota			break;
126780040Syokota		case CLK:
126842421Syokota#ifndef PC98
126980040Syokota			state &= ~CLKDOWN;
127042421Syokota#else
127180040Syokota			state &= ~CLKED;
127280040Syokota			i = state & LOCK_MASK;
127380040Syokota			(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
127480040Syokota						       (caddr_t)&i);
127542421Syokota#endif
127680040Syokota			break;
127780040Syokota		case SLK:
127880040Syokota			state &= ~SLKDOWN;
127980040Syokota			break;
128080040Syokota		case ALK:
128180040Syokota			state &= ~ALKDOWN;
128280040Syokota			break;
128380040Syokota		case NOP:
128480040Syokota			/* release events of regular keys are not reported */
128580040Syokota			*shiftstate &= ~SHIFTAON;
1286127752Sdes			return (NOKEY);
128742421Syokota		}
128880040Syokota		*shiftstate = state & ~SHIFTAON;
128980040Syokota		return (SPCLKEY | RELKEY | action);
129042421Syokota	} else {	/* make: key pressed */
129180040Syokota		action = key->map[i];
129255820Syokota		state &= ~SHIFTAON;
129342421Syokota		if (key->spcl & (0x80 >> i)) {
129442421Syokota			/* special keys */
129580040Syokota			if (kbd->kb_lastact[keycode] == NOP)
129680040Syokota				kbd->kb_lastact[keycode] = action;
129780040Syokota			if (kbd->kb_lastact[keycode] != action)
129880040Syokota				action = NOP;
129942421Syokota			switch (action) {
130042421Syokota			/* LOCKING KEYS */
130142421Syokota			case NLK:
130242421Syokota				set_lockkey_state(kbd, state, NLK);
130342421Syokota				break;
130442421Syokota			case CLK:
130542421Syokota#ifndef PC98
130642421Syokota				set_lockkey_state(kbd, state, CLK);
130742421Syokota#else
130842421Syokota				state |= CLKED;
130942421Syokota				i = state & LOCK_MASK;
131042421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
131142421Syokota							       (caddr_t)&i);
131242421Syokota#endif
131342421Syokota				break;
131442421Syokota			case SLK:
131542421Syokota				set_lockkey_state(kbd, state, SLK);
131642421Syokota				break;
131742421Syokota			case ALK:
131842421Syokota				set_lockkey_state(kbd, state, ALK);
131942421Syokota				break;
132042421Syokota			/* NON-LOCKING KEYS */
132142421Syokota			case SPSC: case RBT:  case SUSP: case STBY:
132254382Syokota			case DBG:  case NEXT: case PREV: case PNC:
132365759Sdwmalone			case HALT: case PDWN:
132442421Syokota				*accents = 0;
132542421Syokota				break;
132642421Syokota			case BTAB:
132742421Syokota				*accents = 0;
132842421Syokota				action |= BKEY;
132942421Syokota				break;
133054382Syokota			case LSHA:
133155820Syokota				state |= SHIFTAON;
133254382Syokota				action = LSH;
133354382Syokota				/* FALL THROUGH */
133442421Syokota			case LSH:
133542421Syokota				state |= SHIFTS1;
133642421Syokota				break;
133754382Syokota			case RSHA:
133855820Syokota				state |= SHIFTAON;
133954382Syokota				action = RSH;
134054382Syokota				/* FALL THROUGH */
134142421Syokota			case RSH:
134242421Syokota				state |= SHIFTS2;
134342421Syokota				break;
134454382Syokota			case LCTRA:
134555820Syokota				state |= SHIFTAON;
134654382Syokota				action = LCTR;
134754382Syokota				/* FALL THROUGH */
134842421Syokota			case LCTR:
134942421Syokota				state |= CTLS1;
135042421Syokota				break;
135154382Syokota			case RCTRA:
135255820Syokota				state |= SHIFTAON;
135354382Syokota				action = RCTR;
135454382Syokota				/* FALL THROUGH */
135542421Syokota			case RCTR:
135642421Syokota				state |= CTLS2;
135742421Syokota				break;
135854382Syokota			case LALTA:
135955820Syokota				state |= SHIFTAON;
136054382Syokota				action = LALT;
136154382Syokota				/* FALL THROUGH */
136242421Syokota			case LALT:
136342421Syokota				state |= ALTS1;
136442421Syokota				break;
136554382Syokota			case RALTA:
136655820Syokota				state |= SHIFTAON;
136754382Syokota				action = RALT;
136854382Syokota				/* FALL THROUGH */
136942421Syokota			case RALT:
137042421Syokota				state |= ALTS2;
137142421Syokota				break;
137242421Syokota			case ASH:
137342421Syokota				state |= AGRS1;
137442421Syokota				break;
137542421Syokota			case META:
137642421Syokota				state |= METAS1;
137742421Syokota				break;
137880040Syokota			case NOP:
137980040Syokota				*shiftstate = state;
1380127752Sdes				return (NOKEY);
138142421Syokota			default:
138242421Syokota				/* is this an accent (dead) key? */
138355820Syokota				*shiftstate = state;
138442421Syokota				if (action >= F_ACC && action <= L_ACC) {
138542421Syokota					action = save_accent_key(kbd, action,
138642421Syokota								 accents);
138742421Syokota					switch (action) {
138842421Syokota					case NOKEY:
138942421Syokota					case ERRKEY:
1390127752Sdes						return (action);
139142421Syokota					default:
139242421Syokota						if (state & METAS)
139342421Syokota							return (action | MKEY);
139442421Syokota						else
1395127752Sdes							return (action);
139642421Syokota					}
139742421Syokota					/* NOT REACHED */
139842421Syokota				}
139942421Syokota				/* other special keys */
140042421Syokota				if (*accents > 0) {
140142421Syokota					*accents = 0;
1402127752Sdes					return (ERRKEY);
140342421Syokota				}
140442421Syokota				if (action >= F_FN && action <= L_FN)
140542421Syokota					action |= FKEY;
140642421Syokota				/* XXX: return fkey string for the FKEY? */
140755820Syokota				return (SPCLKEY | action);
140842421Syokota			}
140942421Syokota			*shiftstate = state;
141042421Syokota			return (SPCLKEY | action);
141142421Syokota		} else {
141242421Syokota			/* regular keys */
141380040Syokota			kbd->kb_lastact[keycode] = NOP;
141455820Syokota			*shiftstate = state;
141542421Syokota			if (*accents > 0) {
141642421Syokota				/* make an accented char */
141742421Syokota				action = make_accent_char(kbd, action, accents);
141842421Syokota				if (action == ERRKEY)
1419127752Sdes					return (action);
142042421Syokota			}
142142421Syokota			if (state & METAS)
142242421Syokota				action |= MKEY;
1423127752Sdes			return (action);
142442421Syokota		}
142542421Syokota	}
142642421Syokota	/* NOT REACHED */
142742421Syokota}
1428