xref: /freebsd/sys/dev/kbd/kbd.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "opt_kbd.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/fcntl.h>
41 #include <sys/poll.h>
42 #include <sys/priv.h>
43 #include <sys/proc.h>
44 #include <sys/selinfo.h>
45 #include <sys/sysctl.h>
46 #include <sys/uio.h>
47 
48 #include <sys/kbio.h>
49 
50 #include <dev/kbd/kbdreg.h>
51 
52 #define KBD_INDEX(dev)	dev2unit(dev)
53 
54 #define KB_QSIZE	512
55 #define KB_BUFSIZE	64
56 
57 typedef struct genkbd_softc {
58 	int		gkb_flags;	/* flag/status bits */
59 #define KB_ASLEEP	(1 << 0)
60 	struct selinfo	gkb_rsel;
61 	char		gkb_q[KB_QSIZE];		/* input queue */
62 	unsigned int	gkb_q_start;
63 	unsigned int	gkb_q_length;
64 } genkbd_softc_t;
65 
66 static	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
67 	SLIST_HEAD_INITIALIZER(keyboard_drivers);
68 
69 SET_DECLARE(kbddriver_set, const keyboard_driver_t);
70 
71 /* local arrays */
72 
73 /*
74  * We need at least one entry each in order to initialize a keyboard
75  * for the kernel console.  The arrays will be increased dynamically
76  * when necessary.
77  */
78 
79 static int		keyboards = 1;
80 static keyboard_t	*kbd_ini;
81 static keyboard_t	**keyboard = &kbd_ini;
82 static keyboard_switch_t *kbdsw_ini;
83        keyboard_switch_t **kbdsw = &kbdsw_ini;
84 
85 static int keymap_restrict_change;
86 static SYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd");
87 SYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW,
88     &keymap_restrict_change, 0, "restrict ability to change keymap");
89 
90 #define ARRAY_DELTA	4
91 
92 static int
93 kbd_realloc_array(void)
94 {
95 	keyboard_t **new_kbd;
96 	keyboard_switch_t **new_kbdsw;
97 	int newsize;
98 	int s;
99 
100 	s = spltty();
101 	newsize = rounddown(keyboards + ARRAY_DELTA, ARRAY_DELTA);
102 	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO);
103 	if (new_kbd == NULL) {
104 		splx(s);
105 		return (ENOMEM);
106 	}
107 	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF,
108 			    M_NOWAIT|M_ZERO);
109 	if (new_kbdsw == NULL) {
110 		free(new_kbd, M_DEVBUF);
111 		splx(s);
112 		return (ENOMEM);
113 	}
114 	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
115 	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
116 	if (keyboards > 1) {
117 		free(keyboard, M_DEVBUF);
118 		free(kbdsw, M_DEVBUF);
119 	}
120 	keyboard = new_kbd;
121 	kbdsw = new_kbdsw;
122 	keyboards = newsize;
123 	splx(s);
124 
125 	if (bootverbose)
126 		printf("kbd: new array size %d\n", keyboards);
127 
128 	return (0);
129 }
130 
131 /*
132  * Low-level keyboard driver functions
133  * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
134  * driver, call these functions to initialize the keyboard_t structure
135  * and register it to the virtual keyboard driver `kbd'.
136  */
137 
138 /* initialize the keyboard_t structure */
139 void
140 kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
141 		int port, int port_size)
142 {
143 	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
144 	kbd->kb_name = name;
145 	kbd->kb_type = type;
146 	kbd->kb_unit = unit;
147 	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
148 	kbd->kb_led = 0;		/* unknown */
149 	kbd->kb_io_base = port;
150 	kbd->kb_io_size = port_size;
151 	kbd->kb_data = NULL;
152 	kbd->kb_keymap = NULL;
153 	kbd->kb_accentmap = NULL;
154 	kbd->kb_fkeytab = NULL;
155 	kbd->kb_fkeytab_size = 0;
156 	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
157 	kbd->kb_delay2 = KB_DELAY2;
158 	kbd->kb_count = 0L;
159 	bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
160 }
161 
162 void
163 kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
164 	     fkeytab_t *fkeymap, int fkeymap_size)
165 {
166 	kbd->kb_keymap = keymap;
167 	kbd->kb_accentmap = accmap;
168 	kbd->kb_fkeytab = fkeymap;
169 	kbd->kb_fkeytab_size = fkeymap_size;
170 }
171 
172 /* declare a new keyboard driver */
173 int
174 kbd_add_driver(keyboard_driver_t *driver)
175 {
176 	if (SLIST_NEXT(driver, link))
177 		return (EINVAL);
178 	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
179 	return (0);
180 }
181 
182 int
183 kbd_delete_driver(keyboard_driver_t *driver)
184 {
185 	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
186 	SLIST_NEXT(driver, link) = NULL;
187 	return (0);
188 }
189 
190 /* register a keyboard and associate it with a function table */
191 int
192 kbd_register(keyboard_t *kbd)
193 {
194 	const keyboard_driver_t **list;
195 	const keyboard_driver_t *p;
196 	keyboard_t *mux;
197 	keyboard_info_t ki;
198 	int index;
199 
200 	mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1));
201 
202 	for (index = 0; index < keyboards; ++index) {
203 		if (keyboard[index] == NULL)
204 			break;
205 	}
206 	if (index >= keyboards) {
207 		if (kbd_realloc_array())
208 			return (-1);
209 	}
210 
211 	kbd->kb_index = index;
212 	KBD_UNBUSY(kbd);
213 	KBD_VALID(kbd);
214 	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
215 	kbd->kb_token = NULL;
216 	kbd->kb_callback.kc_func = NULL;
217 	kbd->kb_callback.kc_arg = NULL;
218 
219 	SLIST_FOREACH(p, &keyboard_drivers, link) {
220 		if (strcmp(p->name, kbd->kb_name) == 0) {
221 			keyboard[index] = kbd;
222 			kbdsw[index] = p->kbdsw;
223 
224 			if (mux != NULL) {
225 				bzero(&ki, sizeof(ki));
226 				strcpy(ki.kb_name, kbd->kb_name);
227 				ki.kb_unit = kbd->kb_unit;
228 
229 				(void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
230 			}
231 
232 			return (index);
233 		}
234 	}
235 	SET_FOREACH(list, kbddriver_set) {
236 		p = *list;
237 		if (strcmp(p->name, kbd->kb_name) == 0) {
238 			keyboard[index] = kbd;
239 			kbdsw[index] = p->kbdsw;
240 
241 			if (mux != NULL) {
242 				bzero(&ki, sizeof(ki));
243 				strcpy(ki.kb_name, kbd->kb_name);
244 				ki.kb_unit = kbd->kb_unit;
245 
246 				(void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki);
247 			}
248 
249 			return (index);
250 		}
251 	}
252 
253 	return (-1);
254 }
255 
256 int
257 kbd_unregister(keyboard_t *kbd)
258 {
259 	int error;
260 	int s;
261 
262 	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
263 		return (ENOENT);
264 	if (keyboard[kbd->kb_index] != kbd)
265 		return (ENOENT);
266 
267 	s = spltty();
268 	if (KBD_IS_BUSY(kbd)) {
269 		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
270 		    kbd->kb_callback.kc_arg);
271 		if (error) {
272 			splx(s);
273 			return (error);
274 		}
275 		if (KBD_IS_BUSY(kbd)) {
276 			splx(s);
277 			return (EBUSY);
278 		}
279 	}
280 	KBD_INVALID(kbd);
281 	keyboard[kbd->kb_index] = NULL;
282 	kbdsw[kbd->kb_index] = NULL;
283 
284 	splx(s);
285 	return (0);
286 }
287 
288 /* find a function table by the driver name */
289 keyboard_switch_t *
290 kbd_get_switch(char *driver)
291 {
292 	const keyboard_driver_t **list;
293 	const keyboard_driver_t *p;
294 
295 	SLIST_FOREACH(p, &keyboard_drivers, link) {
296 		if (strcmp(p->name, driver) == 0)
297 			return (p->kbdsw);
298 	}
299 	SET_FOREACH(list, kbddriver_set) {
300 		p = *list;
301 		if (strcmp(p->name, driver) == 0)
302 			return (p->kbdsw);
303 	}
304 
305 	return (NULL);
306 }
307 
308 /*
309  * Keyboard client functions
310  * Keyboard clients, such as the console driver `syscons' and the keyboard
311  * cdev driver, use these functions to claim and release a keyboard for
312  * exclusive use.
313  */
314 
315 /*
316  * find the keyboard specified by a driver name and a unit number
317  * starting at given index
318  */
319 int
320 kbd_find_keyboard2(char *driver, int unit, int index)
321 {
322 	int i;
323 
324 	if ((index < 0) || (index >= keyboards))
325 		return (-1);
326 
327 	for (i = index; i < keyboards; ++i) {
328 		if (keyboard[i] == NULL)
329 			continue;
330 		if (!KBD_IS_VALID(keyboard[i]))
331 			continue;
332 		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
333 			continue;
334 		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
335 			continue;
336 		return (i);
337 	}
338 
339 	return (-1);
340 }
341 
342 /* find the keyboard specified by a driver name and a unit number */
343 int
344 kbd_find_keyboard(char *driver, int unit)
345 {
346 	return (kbd_find_keyboard2(driver, unit, 0));
347 }
348 
349 /* allocate a keyboard */
350 int
351 kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
352 	     void *arg)
353 {
354 	int index;
355 	int s;
356 
357 	if (func == NULL)
358 		return (-1);
359 
360 	s = spltty();
361 	index = kbd_find_keyboard(driver, unit);
362 	if (index >= 0) {
363 		if (KBD_IS_BUSY(keyboard[index])) {
364 			splx(s);
365 			return (-1);
366 		}
367 		keyboard[index]->kb_token = id;
368 		KBD_BUSY(keyboard[index]);
369 		keyboard[index]->kb_callback.kc_func = func;
370 		keyboard[index]->kb_callback.kc_arg = arg;
371 		kbdd_clear_state(keyboard[index]);
372 	}
373 	splx(s);
374 	return (index);
375 }
376 
377 int
378 kbd_release(keyboard_t *kbd, void *id)
379 {
380 	int error;
381 	int s;
382 
383 	s = spltty();
384 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
385 		error = EINVAL;
386 	} else if (kbd->kb_token != id) {
387 		error = EPERM;
388 	} else {
389 		kbd->kb_token = NULL;
390 		KBD_UNBUSY(kbd);
391 		kbd->kb_callback.kc_func = NULL;
392 		kbd->kb_callback.kc_arg = NULL;
393 		kbdd_clear_state(kbd);
394 		error = 0;
395 	}
396 	splx(s);
397 	return (error);
398 }
399 
400 int
401 kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
402 		    void *arg)
403 {
404 	int error;
405 	int s;
406 
407 	s = spltty();
408 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
409 		error = EINVAL;
410 	} else if (kbd->kb_token != id) {
411 		error = EPERM;
412 	} else if (func == NULL) {
413 		error = EINVAL;
414 	} else {
415 		kbd->kb_callback.kc_func = func;
416 		kbd->kb_callback.kc_arg = arg;
417 		error = 0;
418 	}
419 	splx(s);
420 	return (error);
421 }
422 
423 /* get a keyboard structure */
424 keyboard_t *
425 kbd_get_keyboard(int index)
426 {
427 	if ((index < 0) || (index >= keyboards))
428 		return (NULL);
429 	if (keyboard[index] == NULL)
430 		return (NULL);
431 	if (!KBD_IS_VALID(keyboard[index]))
432 		return (NULL);
433 	return (keyboard[index]);
434 }
435 
436 /*
437  * The back door for the console driver; configure keyboards
438  * This function is for the kernel console to initialize keyboards
439  * at very early stage.
440  */
441 
442 int
443 kbd_configure(int flags)
444 {
445 	const keyboard_driver_t **list;
446 	const keyboard_driver_t *p;
447 
448 	SLIST_FOREACH(p, &keyboard_drivers, link) {
449 		if (p->configure != NULL)
450 			(*p->configure)(flags);
451 	}
452 	SET_FOREACH(list, kbddriver_set) {
453 		p = *list;
454 		if (p->configure != NULL)
455 			(*p->configure)(flags);
456 	}
457 
458 	return (0);
459 }
460 
461 #ifdef KBD_INSTALL_CDEV
462 
463 /*
464  * Virtual keyboard cdev driver functions
465  * The virtual keyboard driver dispatches driver functions to
466  * appropriate subdrivers.
467  */
468 
469 #define KBD_UNIT(dev)	dev2unit(dev)
470 
471 static d_open_t		genkbdopen;
472 static d_close_t	genkbdclose;
473 static d_read_t		genkbdread;
474 static d_write_t	genkbdwrite;
475 static d_ioctl_t	genkbdioctl;
476 static d_poll_t		genkbdpoll;
477 
478 
479 static struct cdevsw kbd_cdevsw = {
480 	.d_version =	D_VERSION,
481 	.d_flags =	D_NEEDGIANT,
482 	.d_open =	genkbdopen,
483 	.d_close =	genkbdclose,
484 	.d_read =	genkbdread,
485 	.d_write =	genkbdwrite,
486 	.d_ioctl =	genkbdioctl,
487 	.d_poll =	genkbdpoll,
488 	.d_name =	"kbd",
489 };
490 
491 int
492 kbd_attach(keyboard_t *kbd)
493 {
494 
495 	if (kbd->kb_index >= keyboards)
496 		return (EINVAL);
497 	if (keyboard[kbd->kb_index] != kbd)
498 		return (EINVAL);
499 
500 	kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL,
501 	    0600, "%s%r", kbd->kb_name, kbd->kb_unit);
502 	make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index);
503 	kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
504 	    M_WAITOK | M_ZERO);
505 	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
506 	return (0);
507 }
508 
509 int
510 kbd_detach(keyboard_t *kbd)
511 {
512 
513 	if (kbd->kb_index >= keyboards)
514 		return (EINVAL);
515 	if (keyboard[kbd->kb_index] != kbd)
516 		return (EINVAL);
517 
518 	free(kbd->kb_dev->si_drv1, M_DEVBUF);
519 	destroy_dev(kbd->kb_dev);
520 
521 	return (0);
522 }
523 
524 /*
525  * Generic keyboard cdev driver functions
526  * Keyboard subdrivers may call these functions to implement common
527  * driver functions.
528  */
529 
530 static void
531 genkbd_putc(genkbd_softc_t *sc, char c)
532 {
533 	unsigned int p;
534 
535 	if (sc->gkb_q_length == KB_QSIZE)
536 		return;
537 
538 	p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE;
539 	sc->gkb_q[p] = c;
540 	sc->gkb_q_length++;
541 }
542 
543 static size_t
544 genkbd_getc(genkbd_softc_t *sc, char *buf, size_t len)
545 {
546 
547 	/* Determine copy size. */
548 	if (sc->gkb_q_length == 0)
549 		return (0);
550 	if (len >= sc->gkb_q_length)
551 		len = sc->gkb_q_length;
552 	if (len >= KB_QSIZE - sc->gkb_q_start)
553 		len = KB_QSIZE - sc->gkb_q_start;
554 
555 	/* Copy out data and progress offset. */
556 	memcpy(buf, sc->gkb_q + sc->gkb_q_start, len);
557 	sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE;
558 	sc->gkb_q_length -= len;
559 
560 	return (len);
561 }
562 
563 static kbd_callback_func_t genkbd_event;
564 
565 static int
566 genkbdopen(struct cdev *dev, int mode, int flag, struct thread *td)
567 {
568 	keyboard_t *kbd;
569 	genkbd_softc_t *sc;
570 	int s;
571 	int i;
572 
573 	s = spltty();
574 	sc = dev->si_drv1;
575 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
576 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
577 		splx(s);
578 		return (ENXIO);
579 	}
580 	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
581 	    genkbd_event, (void *)sc);
582 	if (i < 0) {
583 		splx(s);
584 		return (EBUSY);
585 	}
586 	/* assert(i == kbd->kb_index) */
587 	/* assert(kbd == kbd_get_keyboard(i)) */
588 
589 	/*
590 	 * NOTE: even when we have successfully claimed a keyboard,
591 	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
592 	 */
593 
594 	sc->gkb_q_length = 0;
595 	splx(s);
596 
597 	return (0);
598 }
599 
600 static int
601 genkbdclose(struct cdev *dev, int mode, int flag, struct thread *td)
602 {
603 	keyboard_t *kbd;
604 	genkbd_softc_t *sc;
605 	int s;
606 
607 	/*
608 	 * NOTE: the device may have already become invalid.
609 	 * kbd == NULL || !KBD_IS_VALID(kbd)
610 	 */
611 	s = spltty();
612 	sc = dev->si_drv1;
613 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
614 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
615 		/* XXX: we shall be forgiving and don't report error... */
616 	} else {
617 		kbd_release(kbd, (void *)sc);
618 	}
619 	splx(s);
620 	return (0);
621 }
622 
623 static int
624 genkbdread(struct cdev *dev, struct uio *uio, int flag)
625 {
626 	keyboard_t *kbd;
627 	genkbd_softc_t *sc;
628 	u_char buffer[KB_BUFSIZE];
629 	int len;
630 	int error;
631 	int s;
632 
633 	/* wait for input */
634 	s = spltty();
635 	sc = dev->si_drv1;
636 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
637 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
638 		splx(s);
639 		return (ENXIO);
640 	}
641 	while (sc->gkb_q_length == 0) {
642 		if (flag & O_NONBLOCK) {
643 			splx(s);
644 			return (EWOULDBLOCK);
645 		}
646 		sc->gkb_flags |= KB_ASLEEP;
647 		error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0);
648 		kbd = kbd_get_keyboard(KBD_INDEX(dev));
649 		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
650 			splx(s);
651 			return (ENXIO);	/* our keyboard has gone... */
652 		}
653 		if (error) {
654 			sc->gkb_flags &= ~KB_ASLEEP;
655 			splx(s);
656 			return (error);
657 		}
658 	}
659 	splx(s);
660 
661 	/* copy as much input as possible */
662 	error = 0;
663 	while (uio->uio_resid > 0) {
664 		len = imin(uio->uio_resid, sizeof(buffer));
665 		len = genkbd_getc(sc, buffer, len);
666 		if (len <= 0)
667 			break;
668 		error = uiomove(buffer, len, uio);
669 		if (error)
670 			break;
671 	}
672 
673 	return (error);
674 }
675 
676 static int
677 genkbdwrite(struct cdev *dev, struct uio *uio, int flag)
678 {
679 	keyboard_t *kbd;
680 
681 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
682 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
683 		return (ENXIO);
684 	return (ENODEV);
685 }
686 
687 static int
688 genkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
689 {
690 	keyboard_t *kbd;
691 	int error;
692 
693 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
694 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
695 		return (ENXIO);
696 	error = kbdd_ioctl(kbd, cmd, arg);
697 	if (error == ENOIOCTL)
698 		error = ENODEV;
699 	return (error);
700 }
701 
702 static int
703 genkbdpoll(struct cdev *dev, int events, struct thread *td)
704 {
705 	keyboard_t *kbd;
706 	genkbd_softc_t *sc;
707 	int revents;
708 	int s;
709 
710 	revents = 0;
711 	s = spltty();
712 	sc = dev->si_drv1;
713 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
714 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
715 		revents =  POLLHUP;	/* the keyboard has gone */
716 	} else if (events & (POLLIN | POLLRDNORM)) {
717 		if (sc->gkb_q_length > 0)
718 			revents = events & (POLLIN | POLLRDNORM);
719 		else
720 			selrecord(td, &sc->gkb_rsel);
721 	}
722 	splx(s);
723 	return (revents);
724 }
725 
726 static int
727 genkbd_event(keyboard_t *kbd, int event, void *arg)
728 {
729 	genkbd_softc_t *sc;
730 	size_t len;
731 	u_char *cp;
732 	int mode;
733 	u_int c;
734 
735 	/* assert(KBD_IS_VALID(kbd)) */
736 	sc = (genkbd_softc_t *)arg;
737 
738 	switch (event) {
739 	case KBDIO_KEYINPUT:
740 		break;
741 	case KBDIO_UNLOADING:
742 		/* the keyboard is going... */
743 		kbd_release(kbd, (void *)sc);
744 		if (sc->gkb_flags & KB_ASLEEP) {
745 			sc->gkb_flags &= ~KB_ASLEEP;
746 			wakeup(sc);
747 		}
748 		selwakeuppri(&sc->gkb_rsel, PZERO);
749 		return (0);
750 	default:
751 		return (EINVAL);
752 	}
753 
754 	/* obtain the current key input mode */
755 	if (kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode))
756 		mode = K_XLATE;
757 
758 	/* read all pending input */
759 	while (kbdd_check_char(kbd)) {
760 		c = kbdd_read_char(kbd, FALSE);
761 		if (c == NOKEY)
762 			continue;
763 		if (c == ERRKEY)	/* XXX: ring bell? */
764 			continue;
765 		if (!KBD_IS_BUSY(kbd))
766 			/* the device is not open, discard the input */
767 			continue;
768 
769 		/* store the byte as is for K_RAW and K_CODE modes */
770 		if (mode != K_XLATE) {
771 			genkbd_putc(sc, KEYCHAR(c));
772 			continue;
773 		}
774 
775 		/* K_XLATE */
776 		if (c & RELKEY)	/* key release is ignored */
777 			continue;
778 
779 		/* process special keys; most of them are just ignored... */
780 		if (c & SPCLKEY) {
781 			switch (KEYCHAR(c)) {
782 			default:
783 				/* ignore them... */
784 				continue;
785 			case BTAB:	/* a backtab: ESC [ Z */
786 				genkbd_putc(sc, 0x1b);
787 				genkbd_putc(sc, '[');
788 				genkbd_putc(sc, 'Z');
789 				continue;
790 			}
791 		}
792 
793 		/* normal chars, normal chars with the META, function keys */
794 		switch (KEYFLAGS(c)) {
795 		case 0:			/* a normal char */
796 			genkbd_putc(sc, KEYCHAR(c));
797 			break;
798 		case MKEY:		/* the META flag: prepend ESC */
799 			genkbd_putc(sc, 0x1b);
800 			genkbd_putc(sc, KEYCHAR(c));
801 			break;
802 		case FKEY | SPCLKEY:	/* a function key, return string */
803 			cp = kbdd_get_fkeystr(kbd, KEYCHAR(c), &len);
804 			if (cp != NULL) {
805 				while (len-- >  0)
806 					genkbd_putc(sc, *cp++);
807 			}
808 			break;
809 		}
810 	}
811 
812 	/* wake up sleeping/polling processes */
813 	if (sc->gkb_q_length > 0) {
814 		if (sc->gkb_flags & KB_ASLEEP) {
815 			sc->gkb_flags &= ~KB_ASLEEP;
816 			wakeup(sc);
817 		}
818 		selwakeuppri(&sc->gkb_rsel, PZERO);
819 	}
820 
821 	return (0);
822 }
823 
824 #endif /* KBD_INSTALL_CDEV */
825 
826 /*
827  * Generic low-level keyboard functions
828  * The low-level functions in the keyboard subdriver may use these
829  * functions.
830  */
831 
832 #ifndef KBD_DISABLE_KEYMAP_LOAD
833 static int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *);
834 static int keymap_change_ok(keymap_t *, keymap_t *, struct thread *);
835 static int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *);
836 static int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *);
837 #endif
838 
839 int
840 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
841 {
842 	keymap_t *mapp;
843 	okeymap_t *omapp;
844 	keyarg_t *keyp;
845 	fkeyarg_t *fkeyp;
846 	int s;
847 	int i, j;
848 	int error;
849 
850 	s = spltty();
851 	switch (cmd) {
852 
853 	case KDGKBINFO:		/* get keyboard information */
854 		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
855 		i = imin(strlen(kbd->kb_name) + 1,
856 		    sizeof(((keyboard_info_t *)arg)->kb_name));
857 		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
858 		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
859 		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
860 		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
861 		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
862 		break;
863 
864 	case KDGKBTYPE:		/* get keyboard type */
865 		*(int *)arg = kbd->kb_type;
866 		break;
867 
868 	case KDGETREPEAT:	/* get keyboard repeat rate */
869 		((int *)arg)[0] = kbd->kb_delay1;
870 		((int *)arg)[1] = kbd->kb_delay2;
871 		break;
872 
873 	case GIO_KEYMAP:	/* get keyboard translation table */
874 		error = copyout(kbd->kb_keymap, *(void **)arg,
875 		    sizeof(keymap_t));
876 		splx(s);
877 		return (error);
878 	case OGIO_KEYMAP:	/* get keyboard translation table (compat) */
879 		mapp = kbd->kb_keymap;
880 		omapp = (okeymap_t *)arg;
881 		omapp->n_keys = mapp->n_keys;
882 		for (i = 0; i < NUM_KEYS; i++) {
883 			for (j = 0; j < NUM_STATES; j++)
884 				omapp->key[i].map[j] =
885 				    mapp->key[i].map[j];
886 			omapp->key[i].spcl = mapp->key[i].spcl;
887 			omapp->key[i].flgs = mapp->key[i].flgs;
888 		}
889 		break;
890 	case PIO_KEYMAP:	/* set keyboard translation table */
891 	case OPIO_KEYMAP:	/* set keyboard translation table (compat) */
892 #ifndef KBD_DISABLE_KEYMAP_LOAD
893 		mapp = malloc(sizeof *mapp, M_TEMP, M_WAITOK);
894 		if (cmd == OPIO_KEYMAP) {
895 			omapp = (okeymap_t *)arg;
896 			mapp->n_keys = omapp->n_keys;
897 			for (i = 0; i < NUM_KEYS; i++) {
898 				for (j = 0; j < NUM_STATES; j++)
899 					mapp->key[i].map[j] =
900 					    omapp->key[i].map[j];
901 				mapp->key[i].spcl = omapp->key[i].spcl;
902 				mapp->key[i].flgs = omapp->key[i].flgs;
903 			}
904 		} else {
905 			error = copyin(*(void **)arg, mapp, sizeof *mapp);
906 			if (error != 0) {
907 				splx(s);
908 				free(mapp, M_TEMP);
909 				return (error);
910 			}
911 		}
912 
913 		error = keymap_change_ok(kbd->kb_keymap, mapp, curthread);
914 		if (error != 0) {
915 			splx(s);
916 			free(mapp, M_TEMP);
917 			return (error);
918 		}
919 		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
920 		bcopy(mapp, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
921 		free(mapp, M_TEMP);
922 		break;
923 #else
924 		splx(s);
925 		return (ENODEV);
926 #endif
927 
928 	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
929 		keyp = (keyarg_t *)arg;
930 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
931 		    sizeof(kbd->kb_keymap->key[0])) {
932 			splx(s);
933 			return (EINVAL);
934 		}
935 		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
936 		    sizeof(keyp->key));
937 		break;
938 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
939 #ifndef KBD_DISABLE_KEYMAP_LOAD
940 		keyp = (keyarg_t *)arg;
941 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key) /
942 		    sizeof(kbd->kb_keymap->key[0])) {
943 			splx(s);
944 			return (EINVAL);
945 		}
946 		error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum],
947 		    &keyp->key, curthread);
948 		if (error != 0) {
949 			splx(s);
950 			return (error);
951 		}
952 		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
953 		    sizeof(keyp->key));
954 		break;
955 #else
956 		splx(s);
957 		return (ENODEV);
958 #endif
959 
960 	case GIO_DEADKEYMAP:	/* get accent key translation table */
961 		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
962 		break;
963 	case PIO_DEADKEYMAP:	/* set accent key translation table */
964 #ifndef KBD_DISABLE_KEYMAP_LOAD
965 		error = accent_change_ok(kbd->kb_accentmap,
966 		    (accentmap_t *)arg, curthread);
967 		if (error != 0) {
968 			splx(s);
969 			return (error);
970 		}
971 		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
972 		break;
973 #else
974 		splx(s);
975 		return (ENODEV);
976 #endif
977 
978 	case GETFKEY:		/* get functionkey string */
979 		fkeyp = (fkeyarg_t *)arg;
980 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
981 			splx(s);
982 			return (EINVAL);
983 		}
984 		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
985 		    kbd->kb_fkeytab[fkeyp->keynum].len);
986 		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
987 		break;
988 	case SETFKEY:		/* set functionkey string */
989 #ifndef KBD_DISABLE_KEYMAP_LOAD
990 		fkeyp = (fkeyarg_t *)arg;
991 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
992 			splx(s);
993 			return (EINVAL);
994 		}
995 		error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum],
996 		    fkeyp, curthread);
997 		if (error != 0) {
998 			splx(s);
999 			return (error);
1000 		}
1001 		kbd->kb_fkeytab[fkeyp->keynum].len = min(fkeyp->flen, MAXFK);
1002 		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
1003 		    kbd->kb_fkeytab[fkeyp->keynum].len);
1004 		break;
1005 #else
1006 		splx(s);
1007 		return (ENODEV);
1008 #endif
1009 
1010 	default:
1011 		splx(s);
1012 		return (ENOIOCTL);
1013 	}
1014 
1015 	splx(s);
1016 	return (0);
1017 }
1018 
1019 #ifndef KBD_DISABLE_KEYMAP_LOAD
1020 #define RESTRICTED_KEY(key, i) \
1021 	((key->spcl & (0x80 >> i)) && \
1022 		(key->map[i] == RBT || key->map[i] == SUSP || \
1023 		 key->map[i] == STBY || key->map[i] == DBG || \
1024 		 key->map[i] == PNC || key->map[i] == HALT || \
1025 		 key->map[i] == PDWN))
1026 
1027 static int
1028 key_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td)
1029 {
1030 	int i;
1031 
1032 	/* Low keymap_restrict_change means any changes are OK. */
1033 	if (keymap_restrict_change <= 0)
1034 		return (0);
1035 
1036 	/* High keymap_restrict_change means only root can change the keymap. */
1037 	if (keymap_restrict_change >= 2) {
1038 		for (i = 0; i < NUM_STATES; i++)
1039 			if (oldkey->map[i] != newkey->map[i])
1040 				return priv_check(td, PRIV_KEYBOARD);
1041 		if (oldkey->spcl != newkey->spcl)
1042 			return priv_check(td, PRIV_KEYBOARD);
1043 		if (oldkey->flgs != newkey->flgs)
1044 			return priv_check(td, PRIV_KEYBOARD);
1045 		return (0);
1046 	}
1047 
1048 	/* Otherwise we have to see if any special keys are being changed. */
1049 	for (i = 0; i < NUM_STATES; i++) {
1050 		/*
1051 		 * If either the oldkey or the newkey action is restricted
1052 		 * then we must make sure that the action doesn't change.
1053 		 */
1054 		if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i))
1055 			continue;
1056 		if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i))
1057 		    && oldkey->map[i] == newkey->map[i])
1058 			continue;
1059 		return priv_check(td, PRIV_KEYBOARD);
1060 	}
1061 
1062 	return (0);
1063 }
1064 
1065 static int
1066 keymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td)
1067 {
1068 	int keycode, error;
1069 
1070 	for (keycode = 0; keycode < NUM_KEYS; keycode++) {
1071 		if ((error = key_change_ok(&oldmap->key[keycode],
1072 		    &newmap->key[keycode], td)) != 0)
1073 			return (error);
1074 	}
1075 	return (0);
1076 }
1077 
1078 static int
1079 accent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td)
1080 {
1081 	struct acc_t *oldacc, *newacc;
1082 	int accent, i;
1083 
1084 	if (keymap_restrict_change <= 2)
1085 		return (0);
1086 
1087 	if (oldmap->n_accs != newmap->n_accs)
1088 		return priv_check(td, PRIV_KEYBOARD);
1089 
1090 	for (accent = 0; accent < oldmap->n_accs; accent++) {
1091 		oldacc = &oldmap->acc[accent];
1092 		newacc = &newmap->acc[accent];
1093 		if (oldacc->accchar != newacc->accchar)
1094 			return priv_check(td, PRIV_KEYBOARD);
1095 		for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1096 			if (oldacc->map[i][0] != newacc->map[i][0])
1097 				return priv_check(td, PRIV_KEYBOARD);
1098 			if (oldacc->map[i][0] == 0)	/* end of table */
1099 				break;
1100 			if (oldacc->map[i][1] != newacc->map[i][1])
1101 				return priv_check(td, PRIV_KEYBOARD);
1102 		}
1103 	}
1104 
1105 	return (0);
1106 }
1107 
1108 static int
1109 fkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td)
1110 {
1111 	if (keymap_restrict_change <= 3)
1112 		return (0);
1113 
1114 	if (oldkey->len != newkey->flen ||
1115 	    bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0)
1116 		return priv_check(td, PRIV_KEYBOARD);
1117 
1118 	return (0);
1119 }
1120 #endif
1121 
1122 /* get a pointer to the string associated with the given function key */
1123 u_char *
1124 genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
1125 {
1126 	if (kbd == NULL)
1127 		return (NULL);
1128 	fkey -= F_FN;
1129 	if (fkey > kbd->kb_fkeytab_size)
1130 		return (NULL);
1131 	*len = kbd->kb_fkeytab[fkey].len;
1132 	return (kbd->kb_fkeytab[fkey].str);
1133 }
1134 
1135 /* diagnostic dump */
1136 static char *
1137 get_kbd_type_name(int type)
1138 {
1139 	static struct {
1140 		int type;
1141 		char *name;
1142 	} name_table[] = {
1143 		{ KB_84,	"AT 84" },
1144 		{ KB_101,	"AT 101/102" },
1145 		{ KB_OTHER,	"generic" },
1146 	};
1147 	int i;
1148 
1149 	for (i = 0; i < nitems(name_table); ++i) {
1150 		if (type == name_table[i].type)
1151 			return (name_table[i].name);
1152 	}
1153 	return ("unknown");
1154 }
1155 
1156 void
1157 genkbd_diag(keyboard_t *kbd, int level)
1158 {
1159 	if (level > 0) {
1160 		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
1161 		    kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1162 		    get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1163 		    kbd->kb_config, kbd->kb_flags);
1164 		if (kbd->kb_io_base > 0)
1165 			printf(", port:0x%x-0x%x", kbd->kb_io_base,
1166 			    kbd->kb_io_base + kbd->kb_io_size - 1);
1167 		printf("\n");
1168 	}
1169 }
1170 
1171 #define set_lockkey_state(k, s, l)				\
1172 	if (!((s) & l ## DOWN)) {				\
1173 		int i;						\
1174 		(s) |= l ## DOWN;				\
1175 		(s) ^= l ## ED;					\
1176 		i = (s) & LOCK_MASK;				\
1177 		(void)kbdd_ioctl((k), KDSETLED, (caddr_t)&i);	\
1178 	}
1179 
1180 static u_int
1181 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
1182 {
1183 	int i;
1184 
1185 	/* make an index into the accent map */
1186 	i = key - F_ACC + 1;
1187 	if ((i > kbd->kb_accentmap->n_accs)
1188 	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
1189 		/* the index is out of range or pointing to an empty entry */
1190 		*accents = 0;
1191 		return (ERRKEY);
1192 	}
1193 
1194 	/*
1195 	 * If the same accent key has been hit twice, produce the accent
1196 	 * char itself.
1197 	 */
1198 	if (i == *accents) {
1199 		key = kbd->kb_accentmap->acc[i - 1].accchar;
1200 		*accents = 0;
1201 		return (key);
1202 	}
1203 
1204 	/* remember the index and wait for the next key  */
1205 	*accents = i;
1206 	return (NOKEY);
1207 }
1208 
1209 static u_int
1210 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
1211 {
1212 	struct acc_t *acc;
1213 	int i;
1214 
1215 	acc = &kbd->kb_accentmap->acc[*accents - 1];
1216 	*accents = 0;
1217 
1218 	/*
1219 	 * If the accent key is followed by the space key,
1220 	 * produce the accent char itself.
1221 	 */
1222 	if (ch == ' ')
1223 		return (acc->accchar);
1224 
1225 	/* scan the accent map */
1226 	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1227 		if (acc->map[i][0] == 0)	/* end of table */
1228 			break;
1229 		if (acc->map[i][0] == ch)
1230 			return (acc->map[i][1]);
1231 	}
1232 	/* this char cannot be accented... */
1233 	return (ERRKEY);
1234 }
1235 
1236 int
1237 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1238 		 int *accents)
1239 {
1240 	struct keyent_t *key;
1241 	int state = *shiftstate;
1242 	int action;
1243 	int f;
1244 	int i;
1245 
1246 	i = keycode;
1247 	f = state & (AGRS | ALKED);
1248 	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1249 		i += ALTGR_OFFSET;
1250 	key = &kbd->kb_keymap->key[i];
1251 	i = ((state & SHIFTS) ? 1 : 0)
1252 	    | ((state & CTLS) ? 2 : 0)
1253 	    | ((state & ALTS) ? 4 : 0);
1254 	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1255 		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1256 		i ^= 1;
1257 
1258 	if (up) {	/* break: key released */
1259 		action = kbd->kb_lastact[keycode];
1260 		kbd->kb_lastact[keycode] = NOP;
1261 		switch (action) {
1262 		case LSHA:
1263 			if (state & SHIFTAON) {
1264 				set_lockkey_state(kbd, state, ALK);
1265 				state &= ~ALKDOWN;
1266 			}
1267 			action = LSH;
1268 			/* FALL THROUGH */
1269 		case LSH:
1270 			state &= ~SHIFTS1;
1271 			break;
1272 		case RSHA:
1273 			if (state & SHIFTAON) {
1274 				set_lockkey_state(kbd, state, ALK);
1275 				state &= ~ALKDOWN;
1276 			}
1277 			action = RSH;
1278 			/* FALL THROUGH */
1279 		case RSH:
1280 			state &= ~SHIFTS2;
1281 			break;
1282 		case LCTRA:
1283 			if (state & SHIFTAON) {
1284 				set_lockkey_state(kbd, state, ALK);
1285 				state &= ~ALKDOWN;
1286 			}
1287 			action = LCTR;
1288 			/* FALL THROUGH */
1289 		case LCTR:
1290 			state &= ~CTLS1;
1291 			break;
1292 		case RCTRA:
1293 			if (state & SHIFTAON) {
1294 				set_lockkey_state(kbd, state, ALK);
1295 				state &= ~ALKDOWN;
1296 			}
1297 			action = RCTR;
1298 			/* FALL THROUGH */
1299 		case RCTR:
1300 			state &= ~CTLS2;
1301 			break;
1302 		case LALTA:
1303 			if (state & SHIFTAON) {
1304 				set_lockkey_state(kbd, state, ALK);
1305 				state &= ~ALKDOWN;
1306 			}
1307 			action = LALT;
1308 			/* FALL THROUGH */
1309 		case LALT:
1310 			state &= ~ALTS1;
1311 			break;
1312 		case RALTA:
1313 			if (state & SHIFTAON) {
1314 				set_lockkey_state(kbd, state, ALK);
1315 				state &= ~ALKDOWN;
1316 			}
1317 			action = RALT;
1318 			/* FALL THROUGH */
1319 		case RALT:
1320 			state &= ~ALTS2;
1321 			break;
1322 		case ASH:
1323 			state &= ~AGRS1;
1324 			break;
1325 		case META:
1326 			state &= ~METAS1;
1327 			break;
1328 		case NLK:
1329 			state &= ~NLKDOWN;
1330 			break;
1331 		case CLK:
1332 			state &= ~CLKDOWN;
1333 			break;
1334 		case SLK:
1335 			state &= ~SLKDOWN;
1336 			break;
1337 		case ALK:
1338 			state &= ~ALKDOWN;
1339 			break;
1340 		case NOP:
1341 			/* release events of regular keys are not reported */
1342 			*shiftstate &= ~SHIFTAON;
1343 			return (NOKEY);
1344 		}
1345 		*shiftstate = state & ~SHIFTAON;
1346 		return (SPCLKEY | RELKEY | action);
1347 	} else {	/* make: key pressed */
1348 		action = key->map[i];
1349 		state &= ~SHIFTAON;
1350 		if (key->spcl & (0x80 >> i)) {
1351 			/* special keys */
1352 			if (kbd->kb_lastact[keycode] == NOP)
1353 				kbd->kb_lastact[keycode] = action;
1354 			if (kbd->kb_lastact[keycode] != action)
1355 				action = NOP;
1356 			switch (action) {
1357 			/* LOCKING KEYS */
1358 			case NLK:
1359 				set_lockkey_state(kbd, state, NLK);
1360 				break;
1361 			case CLK:
1362 				set_lockkey_state(kbd, state, CLK);
1363 				break;
1364 			case SLK:
1365 				set_lockkey_state(kbd, state, SLK);
1366 				break;
1367 			case ALK:
1368 				set_lockkey_state(kbd, state, ALK);
1369 				break;
1370 			/* NON-LOCKING KEYS */
1371 			case SPSC: case RBT:  case SUSP: case STBY:
1372 			case DBG:  case NEXT: case PREV: case PNC:
1373 			case HALT: case PDWN:
1374 				*accents = 0;
1375 				break;
1376 			case BTAB:
1377 				*accents = 0;
1378 				action |= BKEY;
1379 				break;
1380 			case LSHA:
1381 				state |= SHIFTAON;
1382 				action = LSH;
1383 				/* FALL THROUGH */
1384 			case LSH:
1385 				state |= SHIFTS1;
1386 				break;
1387 			case RSHA:
1388 				state |= SHIFTAON;
1389 				action = RSH;
1390 				/* FALL THROUGH */
1391 			case RSH:
1392 				state |= SHIFTS2;
1393 				break;
1394 			case LCTRA:
1395 				state |= SHIFTAON;
1396 				action = LCTR;
1397 				/* FALL THROUGH */
1398 			case LCTR:
1399 				state |= CTLS1;
1400 				break;
1401 			case RCTRA:
1402 				state |= SHIFTAON;
1403 				action = RCTR;
1404 				/* FALL THROUGH */
1405 			case RCTR:
1406 				state |= CTLS2;
1407 				break;
1408 			case LALTA:
1409 				state |= SHIFTAON;
1410 				action = LALT;
1411 				/* FALL THROUGH */
1412 			case LALT:
1413 				state |= ALTS1;
1414 				break;
1415 			case RALTA:
1416 				state |= SHIFTAON;
1417 				action = RALT;
1418 				/* FALL THROUGH */
1419 			case RALT:
1420 				state |= ALTS2;
1421 				break;
1422 			case ASH:
1423 				state |= AGRS1;
1424 				break;
1425 			case META:
1426 				state |= METAS1;
1427 				break;
1428 			case NOP:
1429 				*shiftstate = state;
1430 				return (NOKEY);
1431 			default:
1432 				/* is this an accent (dead) key? */
1433 				*shiftstate = state;
1434 				if (action >= F_ACC && action <= L_ACC) {
1435 					action = save_accent_key(kbd, action,
1436 								 accents);
1437 					switch (action) {
1438 					case NOKEY:
1439 					case ERRKEY:
1440 						return (action);
1441 					default:
1442 						if (state & METAS)
1443 							return (action | MKEY);
1444 						else
1445 							return (action);
1446 					}
1447 					/* NOT REACHED */
1448 				}
1449 				/* other special keys */
1450 				if (*accents > 0) {
1451 					*accents = 0;
1452 					return (ERRKEY);
1453 				}
1454 				if (action >= F_FN && action <= L_FN)
1455 					action |= FKEY;
1456 				/* XXX: return fkey string for the FKEY? */
1457 				return (SPCLKEY | action);
1458 			}
1459 			*shiftstate = state;
1460 			return (SPCLKEY | action);
1461 		} else {
1462 			/* regular keys */
1463 			kbd->kb_lastact[keycode] = NOP;
1464 			*shiftstate = state;
1465 			if (*accents > 0) {
1466 				/* make an accented char */
1467 				action = make_accent_char(kbd, action, accents);
1468 				if (action == ERRKEY)
1469 					return (action);
1470 			}
1471 			if (state & METAS)
1472 				action |= MKEY;
1473 			return (action);
1474 		}
1475 	}
1476 	/* NOT REACHED */
1477 }
1478