kbd.c revision 147980
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 147980 2005-07-13 23:58:57Z emax $");
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>
41112050Sdwmalone#include <sys/proc.h>
42112050Sdwmalone#include <sys/sysctl.h>
4342421Syokota#include <sys/uio.h>
4442421Syokota
4566834Sphk#include <sys/kbio.h>
4642421Syokota
4742421Syokota#include <dev/kbd/kbdreg.h>
4842421Syokota
4950154Syokota#define KBD_INDEX(dev)	minor(dev)
5050154Syokota
5150154Syokotatypedef struct genkbd_softc {
5250154Syokota	int		gkb_flags;	/* flag/status bits */
5350154Syokota#define KB_ASLEEP	(1 << 0)
5450154Syokota	struct clist	gkb_q;		/* input queue */
5550154Syokota	struct selinfo	gkb_rsel;
5650154Syokota} genkbd_softc_t;
5750154Syokota
5860938Sjakestatic	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
59127751Sdes	SLIST_HEAD_INITIALIZER(keyboard_drivers);
6054545Syokota
6178161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t);
6278161Speter
6342421Syokota/* local arrays */
6442421Syokota
6542421Syokota/*
6642421Syokota * We need at least one entry each in order to initialize a keyboard
6742421Syokota * for the kernel console.  The arrays will be increased dynamically
6842421Syokota * when necessary.
6942421Syokota */
7042564Syokota
7142564Syokotastatic int		keyboards = 1;
7242421Syokotastatic keyboard_t	*kbd_ini;
7342564Syokotastatic keyboard_t	**keyboard = &kbd_ini;
7442421Syokotastatic keyboard_switch_t *kbdsw_ini;
7542421Syokota       keyboard_switch_t **kbdsw = &kbdsw_ini;
7642421Syokota
77112050Sdwmalonestatic int keymap_restrict_change;
78112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd");
79112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW,
80112050Sdwmalone    &keymap_restrict_change, 0, "restrict ability to change keymap");
81112050Sdwmalone
8242421Syokota#define ARRAY_DELTA	4
8342421Syokota
8444628Syokotastatic int
8542421Syokotakbd_realloc_array(void)
8642421Syokota{
8742421Syokota	keyboard_t **new_kbd;
8842421Syokota	keyboard_switch_t **new_kbdsw;
8942421Syokota	int newsize;
9042421Syokota	int s;
9142421Syokota
9242421Syokota	s = spltty();
9342421Syokota	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
9469781Sdwmalone	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO);
9544628Syokota	if (new_kbd == NULL) {
9644628Syokota		splx(s);
97127752Sdes		return (ENOMEM);
9844628Syokota	}
9969781Sdwmalone	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF,
10069781Sdwmalone			    M_NOWAIT|M_ZERO);
10144628Syokota	if (new_kbdsw == NULL) {
10244628Syokota		free(new_kbd, M_DEVBUF);
10344628Syokota		splx(s);
104127752Sdes		return (ENOMEM);
10544628Syokota	}
10642421Syokota	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
10742421Syokota	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
10842421Syokota	if (keyboards > 1) {
10942421Syokota		free(keyboard, M_DEVBUF);
11042421Syokota		free(kbdsw, M_DEVBUF);
11142421Syokota	}
11242421Syokota	keyboard = new_kbd;
11342421Syokota	kbdsw = new_kbdsw;
11442421Syokota	keyboards = newsize;
11542421Syokota	splx(s);
11642421Syokota
11742421Syokota	if (bootverbose)
11842421Syokota		printf("kbd: new array size %d\n", keyboards);
11944628Syokota
120127752Sdes	return (0);
12142421Syokota}
12242421Syokota
12342421Syokota/*
12442421Syokota * Low-level keyboard driver functions
12542421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
12642421Syokota * driver, call these functions to initialize the keyboard_t structure
12742421Syokota * and register it to the virtual keyboard driver `kbd'.
12842421Syokota */
12942421Syokota
13042421Syokota/* initialize the keyboard_t structure */
13142421Syokotavoid
13242421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
13342421Syokota		int port, int port_size)
13442421Syokota{
13542421Syokota	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
13642421Syokota	kbd->kb_name = name;
13742421Syokota	kbd->kb_type = type;
13842421Syokota	kbd->kb_unit = unit;
13944628Syokota	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
14042421Syokota	kbd->kb_led = 0;		/* unknown */
14142421Syokota	kbd->kb_io_base = port;
14242421Syokota	kbd->kb_io_size = port_size;
14342421Syokota	kbd->kb_data = NULL;
14442421Syokota	kbd->kb_keymap = NULL;
14542421Syokota	kbd->kb_accentmap = NULL;
14642421Syokota	kbd->kb_fkeytab = NULL;
14742421Syokota	kbd->kb_fkeytab_size = 0;
14844628Syokota	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
14944628Syokota	kbd->kb_delay2 = KB_DELAY2;
15054382Syokota	kbd->kb_count = 0L;
15180040Syokota	bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
15242421Syokota}
15342421Syokota
15442421Syokotavoid
15542421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
15642421Syokota	     fkeytab_t *fkeymap, int fkeymap_size)
15742421Syokota{
15842421Syokota	kbd->kb_keymap = keymap;
15942421Syokota	kbd->kb_accentmap = accmap;
16042421Syokota	kbd->kb_fkeytab = fkeymap;
16142421Syokota	kbd->kb_fkeytab_size = fkeymap_size;
16242421Syokota}
16342421Syokota
16454545Syokota/* declare a new keyboard driver */
16554545Syokotaint
16654545Syokotakbd_add_driver(keyboard_driver_t *driver)
16754545Syokota{
16854545Syokota	if (SLIST_NEXT(driver, link))
169127752Sdes		return (EINVAL);
17054545Syokota	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
171127752Sdes	return (0);
17254545Syokota}
17354545Syokota
17454545Syokotaint
17554545Syokotakbd_delete_driver(keyboard_driver_t *driver)
17654545Syokota{
17760938Sjake	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
17854545Syokota	SLIST_NEXT(driver, link) = NULL;
179127752Sdes	return (0);
18054545Syokota}
18154545Syokota
18242421Syokota/* register a keyboard and associate it with a function table */
18342421Syokotaint
18442421Syokotakbd_register(keyboard_t *kbd)
18542421Syokota{
18647295Syokota	const keyboard_driver_t **list;
18747295Syokota	const keyboard_driver_t *p;
18842421Syokota	int index;
18942421Syokota
19042421Syokota	for (index = 0; index < keyboards; ++index) {
19142421Syokota		if (keyboard[index] == NULL)
19242421Syokota			break;
19342421Syokota	}
19444628Syokota	if (index >= keyboards) {
19544628Syokota		if (kbd_realloc_array())
196127752Sdes			return (-1);
19744628Syokota	}
19842421Syokota
19942421Syokota	kbd->kb_index = index;
20042421Syokota	KBD_UNBUSY(kbd);
20142421Syokota	KBD_VALID(kbd);
20242421Syokota	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
20342421Syokota	kbd->kb_token = NULL;
20442421Syokota	kbd->kb_callback.kc_func = NULL;
20542421Syokota	kbd->kb_callback.kc_arg = NULL;
20642421Syokota
20754545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
20854545Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
20954545Syokota			keyboard[index] = kbd;
21054545Syokota			kbdsw[index] = p->kbdsw;
211127752Sdes			return (index);
21254545Syokota		}
21354545Syokota	}
21478161Speter	SET_FOREACH(list, kbddriver_set) {
21578161Speter		p = *list;
21642421Syokota		if (strcmp(p->name, kbd->kb_name) == 0) {
21742421Syokota			keyboard[index] = kbd;
21842421Syokota			kbdsw[index] = p->kbdsw;
219127752Sdes			return (index);
22042421Syokota		}
22142421Syokota	}
22242421Syokota
223127752Sdes	return (-1);
22442421Syokota}
22542421Syokota
22642421Syokotaint
22742421Syokotakbd_unregister(keyboard_t *kbd)
22842421Syokota{
22942421Syokota	int error;
23042421Syokota	int s;
23142421Syokota
23242421Syokota	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
233127752Sdes		return (ENOENT);
23442421Syokota	if (keyboard[kbd->kb_index] != kbd)
235127752Sdes		return (ENOENT);
23642421Syokota
23742421Syokota	s = spltty();
23842421Syokota	if (KBD_IS_BUSY(kbd)) {
23942421Syokota		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
240127752Sdes		    kbd->kb_callback.kc_arg);
24142421Syokota		if (error) {
24242421Syokota			splx(s);
243127752Sdes			return (error);
24442421Syokota		}
24542421Syokota		if (KBD_IS_BUSY(kbd)) {
24642421Syokota			splx(s);
247127752Sdes			return (EBUSY);
24842421Syokota		}
24942421Syokota	}
25042421Syokota	KBD_INVALID(kbd);
25142421Syokota	keyboard[kbd->kb_index] = NULL;
25242421Syokota	kbdsw[kbd->kb_index] = NULL;
25342421Syokota
25442421Syokota	splx(s);
255127752Sdes	return (0);
25642421Syokota}
25742421Syokota
25842421Syokota/* find a funciton table by the driver name */
25942421Syokotakeyboard_switch_t
26042421Syokota*kbd_get_switch(char *driver)
26142421Syokota{
26247295Syokota	const keyboard_driver_t **list;
26347295Syokota	const keyboard_driver_t *p;
26442421Syokota
26554545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
26654545Syokota		if (strcmp(p->name, driver) == 0)
267127752Sdes			return (p->kbdsw);
26854545Syokota	}
26978161Speter	SET_FOREACH(list, kbddriver_set) {
27078161Speter		p = *list;
27142421Syokota		if (strcmp(p->name, driver) == 0)
272127752Sdes			return (p->kbdsw);
27342421Syokota	}
27442421Syokota
275127752Sdes	return (NULL);
27642421Syokota}
27742421Syokota
27842421Syokota/*
27942421Syokota * Keyboard client functions
28042421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard
28142421Syokota * cdev driver, use these functions to claim and release a keyboard for
28242421Syokota * exclusive use.
28342421Syokota */
28442421Syokota
285147980Semax/*
286147980Semax * find the keyboard specified by a driver name and a unit number
287147980Semax * starting at given index
288147980Semax */
28942421Syokotaint
290147980Semaxkbd_find_keyboard2(char *driver, int unit, int index)
29142421Syokota{
29242421Syokota	int i;
29342421Syokota
294147980Semax	if ((index < 0) || (index >= keyboards))
295147980Semax		return (-1);
296147980Semax
297147980Semax	for (i = index; i < keyboards; ++i) {
29842421Syokota		if (keyboard[i] == NULL)
29942421Syokota			continue;
30042421Syokota		if (!KBD_IS_VALID(keyboard[i]))
30142421Syokota			continue;
30242421Syokota		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
30342421Syokota			continue;
30442421Syokota		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
30542421Syokota			continue;
306127752Sdes		return (i);
30742421Syokota	}
308147980Semax
309127752Sdes	return (-1);
31042421Syokota}
31142421Syokota
312147980Semax/* find the keyboard specified by a driver name and a unit number */
313147980Semaxint
314147980Semaxkbd_find_keyboard(char *driver, int unit)
315147980Semax{
316147980Semax	return (kbd_find_keyboard2(driver, unit, 0));
317147980Semax}
318147980Semax
31942421Syokota/* allocate a keyboard */
32042421Syokotaint
32142421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
32242421Syokota	     void *arg)
32342421Syokota{
32442421Syokota	int index;
32542421Syokota	int s;
32642421Syokota
32742421Syokota	if (func == NULL)
328127752Sdes		return (-1);
32942421Syokota
33042421Syokota	s = spltty();
33142421Syokota	index = kbd_find_keyboard(driver, unit);
33242421Syokota	if (index >= 0) {
33342421Syokota		if (KBD_IS_BUSY(keyboard[index])) {
33442421Syokota			splx(s);
335127752Sdes			return (-1);
33642421Syokota		}
33742421Syokota		keyboard[index]->kb_token = id;
33842421Syokota		KBD_BUSY(keyboard[index]);
33942421Syokota		keyboard[index]->kb_callback.kc_func = func;
34042421Syokota		keyboard[index]->kb_callback.kc_arg = arg;
34142421Syokota		(*kbdsw[index]->clear_state)(keyboard[index]);
34242421Syokota	}
34342421Syokota	splx(s);
344127752Sdes	return (index);
34542421Syokota}
34642421Syokota
34742421Syokotaint
34842421Syokotakbd_release(keyboard_t *kbd, void *id)
34942421Syokota{
35042421Syokota	int error;
35142421Syokota	int s;
35242421Syokota
35342421Syokota	s = spltty();
35442421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
35542421Syokota		error = EINVAL;
35642421Syokota	} else if (kbd->kb_token != id) {
35742421Syokota		error = EPERM;
35842421Syokota	} else {
35942421Syokota		kbd->kb_token = NULL;
36042421Syokota		KBD_UNBUSY(kbd);
36142421Syokota		kbd->kb_callback.kc_func = NULL;
36242421Syokota		kbd->kb_callback.kc_arg = NULL;
36342421Syokota		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
36442421Syokota		error = 0;
36542421Syokota	}
36642421Syokota	splx(s);
367127752Sdes	return (error);
36842421Syokota}
36942421Syokota
37042421Syokotaint
37142421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
37242421Syokota		    void *arg)
37342421Syokota{
37442421Syokota	int error;
37542421Syokota	int s;
37642421Syokota
37742421Syokota	s = spltty();
37842421Syokota	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
37942421Syokota		error = EINVAL;
38042421Syokota	} else if (kbd->kb_token != id) {
38142421Syokota		error = EPERM;
38242421Syokota	} else if (func == NULL) {
38342421Syokota		error = EINVAL;
38442421Syokota	} else {
38542421Syokota		kbd->kb_callback.kc_func = func;
38642421Syokota		kbd->kb_callback.kc_arg = arg;
38742421Syokota		error = 0;
38842421Syokota	}
38942421Syokota	splx(s);
390127752Sdes	return (error);
39142421Syokota}
39242421Syokota
39342421Syokota/* get a keyboard structure */
39442421Syokotakeyboard_t
39542421Syokota*kbd_get_keyboard(int index)
39642421Syokota{
39742421Syokota	if ((index < 0) || (index >= keyboards))
398127752Sdes		return (NULL);
39950154Syokota	if (keyboard[index] == NULL)
400127752Sdes		return (NULL);
40142421Syokota	if (!KBD_IS_VALID(keyboard[index]))
402127752Sdes		return (NULL);
403127752Sdes	return (keyboard[index]);
40442421Syokota}
40542421Syokota
40642421Syokota/*
40742421Syokota * The back door for the console driver; configure keyboards
40842421Syokota * This function is for the kernel console to initialize keyboards
40942421Syokota * at very early stage.
41042421Syokota */
41142421Syokota
41242421Syokotaint
41342421Syokotakbd_configure(int flags)
41442421Syokota{
41547295Syokota	const keyboard_driver_t **list;
41647295Syokota	const keyboard_driver_t *p;
41742421Syokota
41854545Syokota	SLIST_FOREACH(p, &keyboard_drivers, link) {
41954545Syokota		if (p->configure != NULL)
42054545Syokota			(*p->configure)(flags);
42154545Syokota	}
42278161Speter	SET_FOREACH(list, kbddriver_set) {
42378161Speter		p = *list;
42442421Syokota		if (p->configure != NULL)
42542421Syokota			(*p->configure)(flags);
42642421Syokota	}
42742421Syokota
428127752Sdes	return (0);
42942421Syokota}
43042421Syokota
43142421Syokota#ifdef KBD_INSTALL_CDEV
43242421Syokota
43342421Syokota/*
43442421Syokota * Virtual keyboard cdev driver functions
43542421Syokota * The virtual keyboard driver dispatches driver functions to
43642421Syokota * appropriate subdrivers.
43742421Syokota */
43842421Syokota
43942421Syokota#define KBD_UNIT(dev)	minor(dev)
44042421Syokota
44150154Syokotastatic d_open_t		genkbdopen;
44250154Syokotastatic d_close_t	genkbdclose;
44350154Syokotastatic d_read_t		genkbdread;
44450154Syokotastatic d_write_t	genkbdwrite;
44550154Syokotastatic d_ioctl_t	genkbdioctl;
44650154Syokotastatic d_poll_t		genkbdpoll;
44742421Syokota
44842421Syokota
44942421Syokotastatic struct cdevsw kbd_cdevsw = {
450126080Sphk	.d_version =	D_VERSION,
451126080Sphk	.d_flags =	D_NEEDGIANT,
452111815Sphk	.d_open =	genkbdopen,
453111815Sphk	.d_close =	genkbdclose,
454111815Sphk	.d_read =	genkbdread,
455111815Sphk	.d_write =	genkbdwrite,
456111815Sphk	.d_ioctl =	genkbdioctl,
457111815Sphk	.d_poll =	genkbdpoll,
458111815Sphk	.d_name =	"kbd",
45942421Syokota};
46042421Syokota
46142421Syokotaint
46250154Syokotakbd_attach(keyboard_t *kbd)
46342421Syokota{
46442421Syokota
46542421Syokota	if (kbd->kb_index >= keyboards)
466127752Sdes		return (EINVAL);
46742421Syokota	if (keyboard[kbd->kb_index] != kbd)
468127752Sdes		return (EINVAL);
46942421Syokota
470127751Sdes	kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL,
471127751Sdes	    0600, "%s%r", kbd->kb_name, kbd->kb_unit);
472125087Sdes	make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index);
473120502Sphk	kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
474127751Sdes	    M_WAITOK | M_ZERO);
47542421Syokota	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
476127752Sdes	return (0);
47742421Syokota}
47842421Syokota
47942421Syokotaint
48050154Syokotakbd_detach(keyboard_t *kbd)
48142421Syokota{
48254545Syokota
48342421Syokota	if (kbd->kb_index >= keyboards)
484127752Sdes		return (EINVAL);
48542421Syokota	if (keyboard[kbd->kb_index] != kbd)
486127752Sdes		return (EINVAL);
48742421Syokota
488120502Sphk	free(kbd->kb_dev->si_drv1, M_DEVBUF);
489120502Sphk	destroy_dev(kbd->kb_dev);
49054545Syokota
491127752Sdes	return (0);
49242421Syokota}
49342421Syokota
49442421Syokota/*
49542421Syokota * Generic keyboard cdev driver functions
49642421Syokota * Keyboard subdrivers may call these functions to implement common
49742421Syokota * driver functions.
49842421Syokota */
49942421Syokota
50042421Syokota#define KB_QSIZE	512
50142421Syokota#define KB_BUFSIZE	64
50242421Syokota
50342421Syokotastatic kbd_callback_func_t genkbd_event;
50442421Syokota
50550154Syokotastatic int
506130585Sphkgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td)
50742421Syokota{
50850154Syokota	keyboard_t *kbd;
50950154Syokota	genkbd_softc_t *sc;
51042421Syokota	int s;
51142421Syokota	int i;
51242421Syokota
51342421Syokota	s = spltty();
51450154Syokota	sc = dev->si_drv1;
51550154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
51650154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
51742421Syokota		splx(s);
518127752Sdes		return (ENXIO);
51942421Syokota	}
52042421Syokota	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
521127751Sdes	    genkbd_event, (void *)sc);
52242421Syokota	if (i < 0) {
52342421Syokota		splx(s);
524127752Sdes		return (EBUSY);
52542421Syokota	}
52642421Syokota	/* assert(i == kbd->kb_index) */
52742421Syokota	/* assert(kbd == kbd_get_keyboard(i)) */
52842421Syokota
52942421Syokota	/*
53042421Syokota	 * NOTE: even when we have successfully claimed a keyboard,
53142421Syokota	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
53242421Syokota	 */
53342421Syokota
53442421Syokota#if 0
53542421Syokota	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
53642421Syokota#endif
53742421Syokota	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
53842421Syokota	splx(s);
53942421Syokota
540127752Sdes	return (0);
54142421Syokota}
54242421Syokota
54350154Syokotastatic int
544130585Sphkgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td)
54542421Syokota{
54650154Syokota	keyboard_t *kbd;
54750154Syokota	genkbd_softc_t *sc;
54842421Syokota	int s;
54942421Syokota
55042421Syokota	/*
55142421Syokota	 * NOTE: the device may have already become invalid.
55250154Syokota	 * kbd == NULL || !KBD_IS_VALID(kbd)
55342421Syokota	 */
55442421Syokota	s = spltty();
55550154Syokota	sc = dev->si_drv1;
55650154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
55750154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
55850154Syokota		/* XXX: we shall be forgiving and don't report error... */
55950154Syokota	} else {
56050154Syokota		kbd_release(kbd, (void *)sc);
56142421Syokota#if 0
56250154Syokota		clist_free_cblocks(&sc->gkb_q);
56342421Syokota#endif
56450154Syokota	}
56542421Syokota	splx(s);
566127752Sdes	return (0);
56742421Syokota}
56842421Syokota
56950154Syokotastatic int
570130585Sphkgenkbdread(struct cdev *dev, struct uio *uio, int flag)
57142421Syokota{
57250154Syokota	keyboard_t *kbd;
57350154Syokota	genkbd_softc_t *sc;
57442421Syokota	u_char buffer[KB_BUFSIZE];
57542421Syokota	int len;
57642421Syokota	int error;
57742421Syokota	int s;
57842421Syokota
57942421Syokota	/* wait for input */
58042421Syokota	s = spltty();
58150154Syokota	sc = dev->si_drv1;
58250154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
58350154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
58450154Syokota		splx(s);
585127752Sdes		return (ENXIO);
58650154Syokota	}
58742421Syokota	while (sc->gkb_q.c_cc == 0) {
588139193Sphk		if (flag & O_NONBLOCK) {
58942421Syokota			splx(s);
590127752Sdes			return (EWOULDBLOCK);
59142421Syokota		}
59242421Syokota		sc->gkb_flags |= KB_ASLEEP;
593111748Sdes		error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0);
59450154Syokota		kbd = kbd_get_keyboard(KBD_INDEX(dev));
59550154Syokota		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
59650154Syokota			splx(s);
597127752Sdes			return (ENXIO);	/* our keyboard has gone... */
59850154Syokota		}
59942421Syokota		if (error) {
60042421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
60142421Syokota			splx(s);
602127752Sdes			return (error);
60342421Syokota		}
60442421Syokota	}
60542421Syokota	splx(s);
60642421Syokota
60742421Syokota	/* copy as much input as possible */
60842421Syokota	error = 0;
60942421Syokota	while (uio->uio_resid > 0) {
61042421Syokota		len = imin(uio->uio_resid, sizeof(buffer));
61142421Syokota		len = q_to_b(&sc->gkb_q, buffer, len);
61242421Syokota		if (len <= 0)
61342421Syokota			break;
61442421Syokota		error = uiomove(buffer, len, uio);
61542421Syokota		if (error)
61642421Syokota			break;
61742421Syokota	}
61842421Syokota
619127752Sdes	return (error);
62042421Syokota}
62142421Syokota
62250154Syokotastatic int
623130585Sphkgenkbdwrite(struct cdev *dev, struct uio *uio, int flag)
62442421Syokota{
62550154Syokota	keyboard_t *kbd;
62650154Syokota
62750154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
62850154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
629127752Sdes		return (ENXIO);
630127752Sdes	return (ENODEV);
63142421Syokota}
63242421Syokota
63350154Syokotastatic int
634130585Sphkgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
63542421Syokota{
63650154Syokota	keyboard_t *kbd;
63742421Syokota	int error;
63842421Syokota
63950154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
64050154Syokota	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
641127752Sdes		return (ENXIO);
64242421Syokota	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
64342421Syokota	if (error == ENOIOCTL)
64442421Syokota		error = ENODEV;
645127752Sdes	return (error);
64642421Syokota}
64742421Syokota
64850154Syokotastatic int
649130585Sphkgenkbdpoll(struct cdev *dev, int events, struct thread *td)
65042421Syokota{
65150154Syokota	keyboard_t *kbd;
65250154Syokota	genkbd_softc_t *sc;
65342421Syokota	int revents;
65442421Syokota	int s;
65542421Syokota
65642421Syokota	revents = 0;
65742421Syokota	s = spltty();
65850154Syokota	sc = dev->si_drv1;
65950154Syokota	kbd = kbd_get_keyboard(KBD_INDEX(dev));
66050154Syokota	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
66150154Syokota		revents =  POLLHUP;	/* the keyboard has gone */
66250154Syokota	} else if (events & (POLLIN | POLLRDNORM)) {
66350154Syokota		if (sc->gkb_q.c_cc > 0)
66450154Syokota			revents = events & (POLLIN | POLLRDNORM);
66542421Syokota		else
66683366Sjulian			selrecord(td, &sc->gkb_rsel);
66742421Syokota	}
66842421Syokota	splx(s);
669127752Sdes	return (revents);
67042421Syokota}
67142421Syokota
67242421Syokotastatic int
67342421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg)
67442421Syokota{
67542421Syokota	genkbd_softc_t *sc;
67642421Syokota	size_t len;
67742421Syokota	u_char *cp;
67842421Syokota	int mode;
67942421Syokota	int c;
68042421Syokota
68142421Syokota	/* assert(KBD_IS_VALID(kbd)) */
68242421Syokota	sc = (genkbd_softc_t *)arg;
68342421Syokota
68442421Syokota	switch (event) {
68542421Syokota	case KBDIO_KEYINPUT:
68642421Syokota		break;
68742421Syokota	case KBDIO_UNLOADING:
68842421Syokota		/* the keyboard is going... */
68942421Syokota		kbd_release(kbd, (void *)sc);
69050154Syokota		if (sc->gkb_flags & KB_ASLEEP) {
69150154Syokota			sc->gkb_flags &= ~KB_ASLEEP;
692111748Sdes			wakeup(sc);
69350154Syokota		}
694122352Stanimura		selwakeuppri(&sc->gkb_rsel, PZERO);
695127752Sdes		return (0);
69642421Syokota	default:
697127752Sdes		return (EINVAL);
69842421Syokota	}
69942421Syokota
70042421Syokota	/* obtain the current key input mode */
70142421Syokota	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
70242421Syokota		mode = K_XLATE;
70342421Syokota
70442421Syokota	/* read all pending input */
70542421Syokota	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
70642421Syokota		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
70742421Syokota		if (c == NOKEY)
70842421Syokota			continue;
70942421Syokota		if (c == ERRKEY)	/* XXX: ring bell? */
71042421Syokota			continue;
71142421Syokota		if (!KBD_IS_BUSY(kbd))
71242421Syokota			/* the device is not open, discard the input */
71342421Syokota			continue;
71442421Syokota
71542421Syokota		/* store the byte as is for K_RAW and K_CODE modes */
71642421Syokota		if (mode != K_XLATE) {
71742421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
71842421Syokota			continue;
71942421Syokota		}
72042421Syokota
72142421Syokota		/* K_XLATE */
72242421Syokota		if (c & RELKEY)	/* key release is ignored */
72342421Syokota			continue;
72442421Syokota
72542421Syokota		/* process special keys; most of them are just ignored... */
72642421Syokota		if (c & SPCLKEY) {
72742421Syokota			switch (KEYCHAR(c)) {
72854382Syokota			default:
72942421Syokota				/* ignore them... */
73042421Syokota				continue;
73142421Syokota			case BTAB:	/* a backtab: ESC [ Z */
73242421Syokota				putc(0x1b, &sc->gkb_q);
73342421Syokota				putc('[', &sc->gkb_q);
73442421Syokota				putc('Z', &sc->gkb_q);
73542421Syokota				continue;
73642421Syokota			}
73742421Syokota		}
73842421Syokota
73942421Syokota		/* normal chars, normal chars with the META, function keys */
74042421Syokota		switch (KEYFLAGS(c)) {
74142421Syokota		case 0:			/* a normal char */
74242421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
74342421Syokota			break;
74442421Syokota		case MKEY:		/* the META flag: prepend ESC */
74542421Syokota			putc(0x1b, &sc->gkb_q);
74642421Syokota			putc(KEYCHAR(c), &sc->gkb_q);
74742421Syokota			break;
74842421Syokota		case FKEY | SPCLKEY:	/* a function key, return string */
74942421Syokota			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
750127751Sdes			    KEYCHAR(c), &len);
75142421Syokota			if (cp != NULL) {
75242421Syokota				while (len-- >  0)
75342421Syokota					putc(*cp++, &sc->gkb_q);
75442421Syokota			}
75542421Syokota			break;
75642421Syokota		}
75742421Syokota	}
75842421Syokota
75942421Syokota	/* wake up sleeping/polling processes */
76042421Syokota	if (sc->gkb_q.c_cc > 0) {
76142421Syokota		if (sc->gkb_flags & KB_ASLEEP) {
76242421Syokota			sc->gkb_flags &= ~KB_ASLEEP;
763111748Sdes			wakeup(sc);
76442421Syokota		}
765122352Stanimura		selwakeuppri(&sc->gkb_rsel, PZERO);
76642421Syokota	}
76742421Syokota
768127752Sdes	return (0);
76942421Syokota}
77042421Syokota
77142421Syokota#endif /* KBD_INSTALL_CDEV */
77242421Syokota
77342421Syokota/*
77442421Syokota * Generic low-level keyboard functions
77542421Syokota * The low-level functions in the keyboard subdriver may use these
77642421Syokota * functions.
77742421Syokota */
77842421Syokota
779112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
780112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *);
781112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *);
782112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *);
783112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *);
784112050Sdwmalone#endif
785112050Sdwmalone
78642421Syokotaint
78742421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
78842421Syokota{
78942421Syokota	keyarg_t *keyp;
79042421Syokota	fkeyarg_t *fkeyp;
79142421Syokota	int s;
79242421Syokota	int i;
793112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
794112050Sdwmalone	int error;
795112050Sdwmalone#endif
79642421Syokota
79742421Syokota	s = spltty();
79842421Syokota	switch (cmd) {
79942421Syokota
80042421Syokota	case KDGKBINFO:		/* get keyboard information */
80142421Syokota		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
80242421Syokota		i = imin(strlen(kbd->kb_name) + 1,
803127751Sdes		    sizeof(((keyboard_info_t *)arg)->kb_name));
80442421Syokota		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
80542421Syokota		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
80642421Syokota		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
80742421Syokota		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
80842421Syokota		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
80942421Syokota		break;
81042421Syokota
81142421Syokota	case KDGKBTYPE:		/* get keyboard type */
81242421Syokota		*(int *)arg = kbd->kb_type;
81342421Syokota		break;
81442421Syokota
81554543Syokota	case KDGETREPEAT:	/* get keyboard repeat rate */
81654543Syokota		((int *)arg)[0] = kbd->kb_delay1;
817127751Sdes		((int *)arg)[1] = kbd->kb_delay2;
81854543Syokota		break;
81954543Syokota
82042421Syokota	case GIO_KEYMAP:	/* get keyboard translation table */
82142421Syokota		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
82242421Syokota		break;
82342421Syokota	case PIO_KEYMAP:	/* set keyboard translation table */
82444628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
825112050Sdwmalone		error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg,
826112050Sdwmalone		    curthread);
827112050Sdwmalone		if (error != 0) {
828112050Sdwmalone			splx(s);
829127752Sdes			return (error);
830112050Sdwmalone		}
83142421Syokota		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
83242421Syokota		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
83342421Syokota		break;
83444628Syokota#else
83544628Syokota		splx(s);
836127752Sdes		return (ENODEV);
83744628Syokota#endif
83842421Syokota
83942421Syokota	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
84042421Syokota		keyp = (keyarg_t *)arg;
841127751Sdes		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
842127751Sdes		    sizeof(kbd->kb_keymap->key[0])) {
84342421Syokota			splx(s);
844127752Sdes			return (EINVAL);
84542421Syokota		}
84642573Syokota		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
847127751Sdes		    sizeof(keyp->key));
84842421Syokota		break;
84942421Syokota	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
85044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
85142421Syokota		keyp = (keyarg_t *)arg;
852127751Sdes		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
853127751Sdes		    sizeof(kbd->kb_keymap->key[0])) {
85442421Syokota			splx(s);
855127752Sdes			return (EINVAL);
85642421Syokota		}
857112050Sdwmalone		error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum],
858112050Sdwmalone		    &keyp->key, curthread);
859112050Sdwmalone		if (error != 0) {
860112050Sdwmalone			splx(s);
861127752Sdes			return (error);
862112050Sdwmalone		}
86342573Syokota		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
864127751Sdes		    sizeof(keyp->key));
86542421Syokota		break;
86644628Syokota#else
86744628Syokota		splx(s);
868127752Sdes		return (ENODEV);
86944628Syokota#endif
87042421Syokota
87142421Syokota	case GIO_DEADKEYMAP:	/* get accent key translation table */
87242421Syokota		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
87342421Syokota		break;
87442421Syokota	case PIO_DEADKEYMAP:	/* set accent key translation table */
87544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
876112050Sdwmalone		error = accent_change_ok(kbd->kb_accentmap,
877112050Sdwmalone		    (accentmap_t *)arg, curthread);
878112050Sdwmalone		if (error != 0) {
879112050Sdwmalone			splx(s);
880127752Sdes			return (error);
881112050Sdwmalone		}
88242421Syokota		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
88342421Syokota		break;
88444628Syokota#else
88544628Syokota		splx(s);
886127752Sdes		return (ENODEV);
88744628Syokota#endif
88842421Syokota
88942421Syokota	case GETFKEY:		/* get functionkey string */
89042421Syokota		fkeyp = (fkeyarg_t *)arg;
89142421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
89242421Syokota			splx(s);
893127752Sdes			return (EINVAL);
89442421Syokota		}
89542421Syokota		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
896127751Sdes		    kbd->kb_fkeytab[fkeyp->keynum].len);
89742421Syokota		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
89842421Syokota		break;
89942421Syokota	case SETFKEY:		/* set functionkey string */
90044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD
90142421Syokota		fkeyp = (fkeyarg_t *)arg;
90242421Syokota		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
90342421Syokota			splx(s);
904127752Sdes			return (EINVAL);
90542421Syokota		}
906112050Sdwmalone		error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum],
907112050Sdwmalone		    fkeyp, curthread);
908112050Sdwmalone		if (error != 0) {
909112050Sdwmalone			splx(s);
910127752Sdes			return (error);
911112050Sdwmalone		}
91242421Syokota		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
91342421Syokota		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
914127751Sdes		    kbd->kb_fkeytab[fkeyp->keynum].len);
91542421Syokota		break;
91644628Syokota#else
91744628Syokota		splx(s);
918127752Sdes		return (ENODEV);
91944628Syokota#endif
92042421Syokota
92142421Syokota	default:
92242421Syokota		splx(s);
923127752Sdes		return (ENOIOCTL);
92442421Syokota	}
92542421Syokota
92642421Syokota	splx(s);
927127752Sdes	return (0);
92842421Syokota}
92942421Syokota
930112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD
931112050Sdwmalone#define RESTRICTED_KEY(key, i) \
932112050Sdwmalone	((key->spcl & (0x80 >> i)) && \
933112050Sdwmalone		(key->map[i] == RBT || key->map[i] == SUSP || \
934112050Sdwmalone		 key->map[i] == STBY || key->map[i] == DBG || \
935112050Sdwmalone		 key->map[i] == PNC || key->map[i] == HALT || \
936112050Sdwmalone		 key->map[i] == PDWN))
937112050Sdwmalone
938112050Sdwmalonestatic int
939112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td)
940112050Sdwmalone{
941112050Sdwmalone	int i;
942112050Sdwmalone
943112050Sdwmalone	/* Low keymap_restrict_change means any changes are OK. */
944112050Sdwmalone	if (keymap_restrict_change <= 0)
945127752Sdes		return (0);
946112050Sdwmalone
947112050Sdwmalone	/* High keymap_restrict_change means only root can change the keymap. */
948112050Sdwmalone	if (keymap_restrict_change >= 2) {
949112050Sdwmalone		for (i = 0; i < NUM_STATES; i++)
950112050Sdwmalone			if (oldkey->map[i] != newkey->map[i])
951112050Sdwmalone				return suser(td);
952112050Sdwmalone		if (oldkey->spcl != newkey->spcl)
953112050Sdwmalone			return suser(td);
954112050Sdwmalone		if (oldkey->flgs != newkey->flgs)
955112050Sdwmalone			return suser(td);
956127752Sdes		return (0);
957112050Sdwmalone	}
958112050Sdwmalone
959112050Sdwmalone	/* Otherwise we have to see if any special keys are being changed. */
960112050Sdwmalone	for (i = 0; i < NUM_STATES; i++) {
961112050Sdwmalone		/*
962112050Sdwmalone		 * If either the oldkey or the newkey action is restricted
963112050Sdwmalone		 * then we must make sure that the action doesn't change.
964112050Sdwmalone		 */
965112050Sdwmalone		if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i))
966112050Sdwmalone			continue;
967112050Sdwmalone		if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i))
968112050Sdwmalone		    && oldkey->map[i] == newkey->map[i])
969112050Sdwmalone			continue;
970112050Sdwmalone		return suser(td);
971112050Sdwmalone	}
972112050Sdwmalone
973127752Sdes	return (0);
974112050Sdwmalone}
975112050Sdwmalone
976112050Sdwmalonestatic int
977112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td)
978112050Sdwmalone{
979112050Sdwmalone	int keycode, error;
980112050Sdwmalone
981112050Sdwmalone	for (keycode = 0; keycode < NUM_KEYS; keycode++) {
982112050Sdwmalone		if ((error = key_change_ok(&oldmap->key[keycode],
983112050Sdwmalone		    &newmap->key[keycode], td)) != 0)
984127752Sdes			return (error);
985112050Sdwmalone	}
986127752Sdes	return (0);
987112050Sdwmalone}
988112050Sdwmalone
989112050Sdwmalonestatic int
990112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td)
991112050Sdwmalone{
992112050Sdwmalone	struct acc_t *oldacc, *newacc;
993112050Sdwmalone	int accent, i;
994112050Sdwmalone
995112050Sdwmalone	if (keymap_restrict_change <= 2)
996127752Sdes		return (0);
997112050Sdwmalone
998112050Sdwmalone	if (oldmap->n_accs != newmap->n_accs)
999112050Sdwmalone		return suser(td);
1000112050Sdwmalone
1001112050Sdwmalone	for (accent = 0; accent < oldmap->n_accs; accent++) {
1002112050Sdwmalone		oldacc = &oldmap->acc[accent];
1003112050Sdwmalone		newacc = &newmap->acc[accent];
1004112050Sdwmalone		if (oldacc->accchar != newacc->accchar)
1005112050Sdwmalone			return suser(td);
1006112050Sdwmalone		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1007112050Sdwmalone			if (oldacc->map[i][0] != newacc->map[i][0])
1008112050Sdwmalone				return suser(td);
1009112050Sdwmalone			if (oldacc->map[i][0] == 0)	/* end of table */
1010112050Sdwmalone				break;
1011112050Sdwmalone			if (oldacc->map[i][1] != newacc->map[i][1])
1012112050Sdwmalone				return suser(td);
1013112050Sdwmalone		}
1014112050Sdwmalone	}
1015112050Sdwmalone
1016127752Sdes	return (0);
1017112050Sdwmalone}
1018112050Sdwmalone
1019112050Sdwmalonestatic int
1020112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td)
1021112050Sdwmalone{
1022112050Sdwmalone	if (keymap_restrict_change <= 3)
1023127752Sdes		return (0);
1024112050Sdwmalone
1025112050Sdwmalone	if (oldkey->len != newkey->flen ||
1026112050Sdwmalone	    bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0)
1027112050Sdwmalone		return suser(td);
1028112050Sdwmalone
1029127752Sdes	return (0);
1030112050Sdwmalone}
1031112050Sdwmalone#endif
1032112050Sdwmalone
103342421Syokota/* get a pointer to the string associated with the given function key */
103442421Syokotau_char
103542421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
103642421Syokota{
103742421Syokota	if (kbd == NULL)
1038127752Sdes		return (NULL);
103942421Syokota	fkey -= F_FN;
104042421Syokota	if (fkey > kbd->kb_fkeytab_size)
1041127752Sdes		return (NULL);
104242421Syokota	*len = kbd->kb_fkeytab[fkey].len;
1043127752Sdes	return (kbd->kb_fkeytab[fkey].str);
104442421Syokota}
104542421Syokota
104642421Syokota/* diagnostic dump */
104742421Syokotastatic char
104842421Syokota*get_kbd_type_name(int type)
104942421Syokota{
105042421Syokota	static struct {
105142421Syokota		int type;
105242421Syokota		char *name;
105342421Syokota	} name_table[] = {
105442421Syokota		{ KB_84,	"AT 84" },
105542421Syokota		{ KB_101,	"AT 101/102" },
105642421Syokota		{ KB_OTHER,	"generic" },
105742421Syokota	};
105842421Syokota	int i;
105942421Syokota
106042421Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
106142421Syokota		if (type == name_table[i].type)
1062127752Sdes			return (name_table[i].name);
106342421Syokota	}
1064127752Sdes	return ("unknown");
106542421Syokota}
106642421Syokota
106742421Syokotavoid
106842421Syokotagenkbd_diag(keyboard_t *kbd, int level)
106942421Syokota{
107042421Syokota	if (level > 0) {
1071127751Sdes		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
1072127751Sdes		    kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1073127751Sdes		    get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1074127751Sdes		    kbd->kb_config, kbd->kb_flags);
107542421Syokota		if (kbd->kb_io_base > 0)
1076127751Sdes			printf(", port:0x%x-0x%x", kbd->kb_io_base,
1077127751Sdes			    kbd->kb_io_base + kbd->kb_io_size - 1);
107842421Syokota		printf("\n");
107942421Syokota	}
108042421Syokota}
108142421Syokota
108242421Syokota#define set_lockkey_state(k, s, l)				\
108342421Syokota	if (!((s) & l ## DOWN)) {				\
108442421Syokota		int i;						\
108542421Syokota		(s) |= l ## DOWN;				\
108642421Syokota		(s) ^= l ## ED;					\
108742421Syokota		i = (s) & LOCK_MASK;				\
108842421Syokota		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
108942421Syokota	}
109042421Syokota
109142421Syokotastatic u_int
109242421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents)
109342421Syokota{
109442421Syokota	int i;
109542421Syokota
109642421Syokota	/* make an index into the accent map */
109742421Syokota	i = key - F_ACC + 1;
109842421Syokota	if ((i > kbd->kb_accentmap->n_accs)
109942421Syokota	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
110042421Syokota		/* the index is out of range or pointing to an empty entry */
110142421Syokota		*accents = 0;
1102127752Sdes		return (ERRKEY);
110342421Syokota	}
110442421Syokota
1105127751Sdes	/*
1106127751Sdes	 * If the same accent key has been hit twice, produce the accent
1107127751Sdes	 * char itself.
110842421Syokota	 */
110942421Syokota	if (i == *accents) {
111042421Syokota		key = kbd->kb_accentmap->acc[i - 1].accchar;
111142421Syokota		*accents = 0;
1112127752Sdes		return (key);
111342421Syokota	}
111442421Syokota
111542421Syokota	/* remember the index and wait for the next key  */
1116127751Sdes	*accents = i;
1117127752Sdes	return (NOKEY);
111842421Syokota}
111942421Syokota
112042421Syokotastatic u_int
112142421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents)
112242421Syokota{
112342421Syokota	struct acc_t *acc;
112442421Syokota	int i;
112542421Syokota
112642421Syokota	acc = &kbd->kb_accentmap->acc[*accents - 1];
112742421Syokota	*accents = 0;
112842421Syokota
1129127751Sdes	/*
113042421Syokota	 * If the accent key is followed by the space key,
113142421Syokota	 * produce the accent char itself.
113242421Syokota	 */
113342421Syokota	if (ch == ' ')
1134127752Sdes		return (acc->accchar);
113542421Syokota
113642421Syokota	/* scan the accent map */
113742421Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
113842421Syokota		if (acc->map[i][0] == 0)	/* end of table */
113942421Syokota			break;
114042421Syokota		if (acc->map[i][0] == ch)
1141127752Sdes			return (acc->map[i][1]);
114242421Syokota	}
114342421Syokota	/* this char cannot be accented... */
1144127752Sdes	return (ERRKEY);
114542421Syokota}
114642421Syokota
114742421Syokotaint
114842421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
114942421Syokota		 int *accents)
115042421Syokota{
115142421Syokota	struct keyent_t *key;
115242421Syokota	int state = *shiftstate;
115342421Syokota	int action;
115442421Syokota	int f;
115542421Syokota	int i;
115642421Syokota
115754382Syokota	i = keycode;
115842421Syokota	f = state & (AGRS | ALKED);
115942421Syokota	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
116054382Syokota		i += ALTGR_OFFSET;
116154382Syokota	key = &kbd->kb_keymap->key[i];
116242421Syokota	i = ((state & SHIFTS) ? 1 : 0)
116342421Syokota	    | ((state & CTLS) ? 2 : 0)
116442421Syokota	    | ((state & ALTS) ? 4 : 0);
116542421Syokota	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
116642421Syokota		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
116742421Syokota		i ^= 1;
116842421Syokota
116942421Syokota	if (up) {	/* break: key released */
117080040Syokota		action = kbd->kb_lastact[keycode];
117180040Syokota		kbd->kb_lastact[keycode] = NOP;
117280040Syokota		switch (action) {
117380040Syokota		case LSHA:
117480040Syokota			if (state & SHIFTAON) {
117580040Syokota				set_lockkey_state(kbd, state, ALK);
117680040Syokota				state &= ~ALKDOWN;
117780040Syokota			}
117880040Syokota			action = LSH;
117980040Syokota			/* FALL THROUGH */
118080040Syokota		case LSH:
118180040Syokota			state &= ~SHIFTS1;
118280040Syokota			break;
118380040Syokota		case RSHA:
118480040Syokota			if (state & SHIFTAON) {
118580040Syokota				set_lockkey_state(kbd, state, ALK);
118680040Syokota				state &= ~ALKDOWN;
118780040Syokota			}
118880040Syokota			action = RSH;
118980040Syokota			/* FALL THROUGH */
119080040Syokota		case RSH:
119180040Syokota			state &= ~SHIFTS2;
119280040Syokota			break;
119380040Syokota		case LCTRA:
119480040Syokota			if (state & SHIFTAON) {
119580040Syokota				set_lockkey_state(kbd, state, ALK);
119680040Syokota				state &= ~ALKDOWN;
119780040Syokota			}
119880040Syokota			action = LCTR;
119980040Syokota			/* FALL THROUGH */
120080040Syokota		case LCTR:
120180040Syokota			state &= ~CTLS1;
120280040Syokota			break;
120380040Syokota		case RCTRA:
120480040Syokota			if (state & SHIFTAON) {
120580040Syokota				set_lockkey_state(kbd, state, ALK);
120680040Syokota				state &= ~ALKDOWN;
120780040Syokota			}
120880040Syokota			action = RCTR;
120980040Syokota			/* FALL THROUGH */
121080040Syokota		case RCTR:
121180040Syokota			state &= ~CTLS2;
121280040Syokota			break;
121380040Syokota		case LALTA:
121480040Syokota			if (state & SHIFTAON) {
121580040Syokota				set_lockkey_state(kbd, state, ALK);
121680040Syokota				state &= ~ALKDOWN;
121780040Syokota			}
121880040Syokota			action = LALT;
121980040Syokota			/* FALL THROUGH */
122080040Syokota		case LALT:
122180040Syokota			state &= ~ALTS1;
122280040Syokota			break;
122380040Syokota		case RALTA:
122480040Syokota			if (state & SHIFTAON) {
122580040Syokota				set_lockkey_state(kbd, state, ALK);
122680040Syokota				state &= ~ALKDOWN;
122780040Syokota			}
122880040Syokota			action = RALT;
122980040Syokota			/* FALL THROUGH */
123080040Syokota		case RALT:
123180040Syokota			state &= ~ALTS2;
123280040Syokota			break;
123380040Syokota		case ASH:
123480040Syokota			state &= ~AGRS1;
123580040Syokota			break;
123680040Syokota		case META:
123780040Syokota			state &= ~METAS1;
123880040Syokota			break;
123980040Syokota		case NLK:
124080040Syokota			state &= ~NLKDOWN;
124180040Syokota			break;
124280040Syokota		case CLK:
124342421Syokota#ifndef PC98
124480040Syokota			state &= ~CLKDOWN;
124542421Syokota#else
124680040Syokota			state &= ~CLKED;
124780040Syokota			i = state & LOCK_MASK;
124880040Syokota			(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
124980040Syokota						       (caddr_t)&i);
125042421Syokota#endif
125180040Syokota			break;
125280040Syokota		case SLK:
125380040Syokota			state &= ~SLKDOWN;
125480040Syokota			break;
125580040Syokota		case ALK:
125680040Syokota			state &= ~ALKDOWN;
125780040Syokota			break;
125880040Syokota		case NOP:
125980040Syokota			/* release events of regular keys are not reported */
126080040Syokota			*shiftstate &= ~SHIFTAON;
1261127752Sdes			return (NOKEY);
126242421Syokota		}
126380040Syokota		*shiftstate = state & ~SHIFTAON;
126480040Syokota		return (SPCLKEY | RELKEY | action);
126542421Syokota	} else {	/* make: key pressed */
126680040Syokota		action = key->map[i];
126755820Syokota		state &= ~SHIFTAON;
126842421Syokota		if (key->spcl & (0x80 >> i)) {
126942421Syokota			/* special keys */
127080040Syokota			if (kbd->kb_lastact[keycode] == NOP)
127180040Syokota				kbd->kb_lastact[keycode] = action;
127280040Syokota			if (kbd->kb_lastact[keycode] != action)
127380040Syokota				action = NOP;
127442421Syokota			switch (action) {
127542421Syokota			/* LOCKING KEYS */
127642421Syokota			case NLK:
127742421Syokota				set_lockkey_state(kbd, state, NLK);
127842421Syokota				break;
127942421Syokota			case CLK:
128042421Syokota#ifndef PC98
128142421Syokota				set_lockkey_state(kbd, state, CLK);
128242421Syokota#else
128342421Syokota				state |= CLKED;
128442421Syokota				i = state & LOCK_MASK;
128542421Syokota				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
128642421Syokota							       (caddr_t)&i);
128742421Syokota#endif
128842421Syokota				break;
128942421Syokota			case SLK:
129042421Syokota				set_lockkey_state(kbd, state, SLK);
129142421Syokota				break;
129242421Syokota			case ALK:
129342421Syokota				set_lockkey_state(kbd, state, ALK);
129442421Syokota				break;
129542421Syokota			/* NON-LOCKING KEYS */
129642421Syokota			case SPSC: case RBT:  case SUSP: case STBY:
129754382Syokota			case DBG:  case NEXT: case PREV: case PNC:
129865759Sdwmalone			case HALT: case PDWN:
129942421Syokota				*accents = 0;
130042421Syokota				break;
130142421Syokota			case BTAB:
130242421Syokota				*accents = 0;
130342421Syokota				action |= BKEY;
130442421Syokota				break;
130554382Syokota			case LSHA:
130655820Syokota				state |= SHIFTAON;
130754382Syokota				action = LSH;
130854382Syokota				/* FALL THROUGH */
130942421Syokota			case LSH:
131042421Syokota				state |= SHIFTS1;
131142421Syokota				break;
131254382Syokota			case RSHA:
131355820Syokota				state |= SHIFTAON;
131454382Syokota				action = RSH;
131554382Syokota				/* FALL THROUGH */
131642421Syokota			case RSH:
131742421Syokota				state |= SHIFTS2;
131842421Syokota				break;
131954382Syokota			case LCTRA:
132055820Syokota				state |= SHIFTAON;
132154382Syokota				action = LCTR;
132254382Syokota				/* FALL THROUGH */
132342421Syokota			case LCTR:
132442421Syokota				state |= CTLS1;
132542421Syokota				break;
132654382Syokota			case RCTRA:
132755820Syokota				state |= SHIFTAON;
132854382Syokota				action = RCTR;
132954382Syokota				/* FALL THROUGH */
133042421Syokota			case RCTR:
133142421Syokota				state |= CTLS2;
133242421Syokota				break;
133354382Syokota			case LALTA:
133455820Syokota				state |= SHIFTAON;
133554382Syokota				action = LALT;
133654382Syokota				/* FALL THROUGH */
133742421Syokota			case LALT:
133842421Syokota				state |= ALTS1;
133942421Syokota				break;
134054382Syokota			case RALTA:
134155820Syokota				state |= SHIFTAON;
134254382Syokota				action = RALT;
134354382Syokota				/* FALL THROUGH */
134442421Syokota			case RALT:
134542421Syokota				state |= ALTS2;
134642421Syokota				break;
134742421Syokota			case ASH:
134842421Syokota				state |= AGRS1;
134942421Syokota				break;
135042421Syokota			case META:
135142421Syokota				state |= METAS1;
135242421Syokota				break;
135380040Syokota			case NOP:
135480040Syokota				*shiftstate = state;
1355127752Sdes				return (NOKEY);
135642421Syokota			default:
135742421Syokota				/* is this an accent (dead) key? */
135855820Syokota				*shiftstate = state;
135942421Syokota				if (action >= F_ACC && action <= L_ACC) {
136042421Syokota					action = save_accent_key(kbd, action,
136142421Syokota								 accents);
136242421Syokota					switch (action) {
136342421Syokota					case NOKEY:
136442421Syokota					case ERRKEY:
1365127752Sdes						return (action);
136642421Syokota					default:
136742421Syokota						if (state & METAS)
136842421Syokota							return (action | MKEY);
136942421Syokota						else
1370127752Sdes							return (action);
137142421Syokota					}
137242421Syokota					/* NOT REACHED */
137342421Syokota				}
137442421Syokota				/* other special keys */
137542421Syokota				if (*accents > 0) {
137642421Syokota					*accents = 0;
1377127752Sdes					return (ERRKEY);
137842421Syokota				}
137942421Syokota				if (action >= F_FN && action <= L_FN)
138042421Syokota					action |= FKEY;
138142421Syokota				/* XXX: return fkey string for the FKEY? */
138255820Syokota				return (SPCLKEY | action);
138342421Syokota			}
138442421Syokota			*shiftstate = state;
138542421Syokota			return (SPCLKEY | action);
138642421Syokota		} else {
138742421Syokota			/* regular keys */
138880040Syokota			kbd->kb_lastact[keycode] = NOP;
138955820Syokota			*shiftstate = state;
139042421Syokota			if (*accents > 0) {
139142421Syokota				/* make an accented char */
139242421Syokota				action = make_accent_char(kbd, action, accents);
139342421Syokota				if (action == ERRKEY)
1394127752Sdes					return (action);
139542421Syokota			}
139642421Syokota			if (state & METAS)
139742421Syokota				action |= MKEY;
1398127752Sdes			return (action);
139942421Syokota		}
140042421Syokota	}
140142421Syokota	/* NOT REACHED */
140242421Syokota}
1403