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