xref: /dragonfly/sys/dev/misc/kbd/kbd.c (revision 88cfb1f7)
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 		kn->kn_flags |= EV_EOF;	/* the keyboard has gone */
928 		ready = 1;
929 	} else {
930 		if (sc->gkb_q_length > 0)
931                         ready = 1;
932         }
933 	lwkt_reltoken(&tty_token);
934 	crit_exit();
935 
936 	return (ready);
937 }
938 
939 static int
940 genkbd_event(keyboard_t *kbd, int event, void *arg)
941 {
942 	genkbd_softc_t sc;
943 	size_t len;
944 	u_char *cp;
945 	int mode;
946 	int c;
947 
948 	lwkt_gettoken(&tty_token);
949 	/* assert(KBD_IS_VALID(kbd)) */
950 	sc = (genkbd_softc_t)arg;
951 
952 	switch (event) {
953 	case KBDIO_KEYINPUT:
954 		break;
955 	case KBDIO_UNLOADING:
956 		/* the keyboard is going... */
957 		kbd_release(kbd, (void *)sc);
958 		if (sc->gkb_flags & KB_ASLEEP) {
959 			sc->gkb_flags &= ~KB_ASLEEP;
960 			wakeup((caddr_t)sc);
961 		}
962 		KNOTE(&sc->gkb_rkq.ki_note, 0);
963 		lwkt_reltoken(&tty_token);
964 		return 0;
965 	default:
966 		lwkt_reltoken(&tty_token);
967 		return EINVAL;
968 	}
969 
970 	/* obtain the current key input mode */
971 	if (kbd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode))
972 		mode = K_XLATE;
973 
974 	/* read all pending input */
975 	while (kbd_check_char(kbd)) {
976 		c = kbd_read_char(kbd, FALSE);
977 		if (c == NOKEY)
978 			continue;
979 		if (c == ERRKEY)	/* XXX: ring bell? */
980 			continue;
981 		if (!KBD_IS_BUSY(kbd))
982 			/* the device is not open, discard the input */
983 			continue;
984 
985 		/* store the byte as is for K_RAW and K_CODE modes */
986 		if (mode != K_XLATE) {
987 			genkbd_putc(sc, KEYCHAR(c));
988 			continue;
989 		}
990 
991 		/* K_XLATE */
992 		if (c & RELKEY)	/* key release is ignored */
993 			continue;
994 
995 		/* process special keys; most of them are just ignored... */
996 		if (c & SPCLKEY) {
997 			switch (KEYCHAR(c)) {
998 			default:
999 				/* ignore them... */
1000 				continue;
1001 			case BTAB:	/* a backtab: ESC [ Z */
1002 				genkbd_putc(sc, 0x1b);
1003 				genkbd_putc(sc, '[');
1004 				genkbd_putc(sc, 'Z');
1005 				continue;
1006 			}
1007 		}
1008 
1009 		/* normal chars, normal chars with the META, function keys */
1010 		switch (KEYFLAGS(c)) {
1011 		case 0:			/* a normal char */
1012 			genkbd_putc(sc, KEYCHAR(c));
1013 			break;
1014 		case MKEY:		/* the META flag: prepend ESC */
1015 			genkbd_putc(sc, 0x1b);
1016 			genkbd_putc(sc, KEYCHAR(c));
1017 			break;
1018 		case FKEY | SPCLKEY:	/* a function key, return string */
1019 			cp = kbd_get_fkeystr(kbd, KEYCHAR(c), &len);
1020 			if (cp != NULL) {
1021 				while (len-- >  0)
1022 					genkbd_putc(sc, *cp++);
1023 			}
1024 			break;
1025 		}
1026 	}
1027 
1028 	/* wake up sleeping/polling processes */
1029 	if (sc->gkb_q_length > 0) {
1030 		if (sc->gkb_flags & KB_ASLEEP) {
1031 			sc->gkb_flags &= ~KB_ASLEEP;
1032 			wakeup((caddr_t)sc);
1033 		}
1034 		KNOTE(&sc->gkb_rkq.ki_note, 0);
1035 	}
1036 
1037 	lwkt_reltoken(&tty_token);
1038 	return 0;
1039 }
1040 
1041 #endif /* KBD_INSTALL_CDEV */
1042 
1043 /*
1044  * Generic low-level keyboard functions
1045  * The low-level functions in the keyboard subdriver may use these
1046  * functions.
1047  */
1048 
1049 int
1050 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
1051 {
1052 	keyarg_t *keyp;
1053 	fkeyarg_t *fkeyp;
1054 	int i;
1055 
1056 	crit_enter();
1057 	lwkt_gettoken(&tty_token);
1058 	switch (cmd) {
1059 
1060 	case KDGKBINFO:		/* get keyboard information */
1061 		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
1062 		i = imin(strlen(kbd->kb_name) + 1,
1063 			 sizeof(((keyboard_info_t *)arg)->kb_name));
1064 		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
1065 		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
1066 		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
1067 		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
1068 		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
1069 		break;
1070 
1071 	case KDGKBTYPE:		/* get keyboard type */
1072 		*(int *)arg = kbd->kb_type;
1073 		break;
1074 
1075 	case KDGETREPEAT:	/* get keyboard repeat rate */
1076 		((int *)arg)[0] = kbd->kb_delay1;
1077 		((int *)arg)[1] = kbd->kb_delay2;
1078 		break;
1079 
1080 	case GIO_KEYMAP:	/* get keyboard translation table */
1081 		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
1082 		break;
1083 	case PIO_KEYMAP:	/* set keyboard translation table */
1084 #ifndef KBD_DISABLE_KEYMAP_LOAD
1085 		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
1086 		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
1087 		break;
1088 #else
1089 		lwkt_reltoken(&tty_token);
1090 		crit_exit();
1091 		return ENODEV;
1092 #endif
1093 
1094 	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
1095 		keyp = (keyarg_t *)arg;
1096 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
1097 					/sizeof(kbd->kb_keymap->key[0])) {
1098 			lwkt_reltoken(&tty_token);
1099 			crit_exit();
1100 			return EINVAL;
1101 		}
1102 		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
1103 		      sizeof(keyp->key));
1104 		break;
1105 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
1106 #ifndef KBD_DISABLE_KEYMAP_LOAD
1107 		keyp = (keyarg_t *)arg;
1108 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
1109 					/sizeof(kbd->kb_keymap->key[0])) {
1110 			lwkt_reltoken(&tty_token);
1111 			crit_exit();
1112 			return EINVAL;
1113 		}
1114 		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
1115 		      sizeof(keyp->key));
1116 		break;
1117 #else
1118 		lwkt_reltoken(&tty_token);
1119 		crit_exit();
1120 		return ENODEV;
1121 #endif
1122 
1123 	case GIO_DEADKEYMAP:	/* get accent key translation table */
1124 		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
1125 		break;
1126 	case PIO_DEADKEYMAP:	/* set accent key translation table */
1127 #ifndef KBD_DISABLE_KEYMAP_LOAD
1128 		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
1129 		break;
1130 #else
1131 		lwkt_reltoken(&tty_token);
1132 		crit_exit();
1133 		return ENODEV;
1134 #endif
1135 
1136 	case GETFKEY:		/* get functionkey string */
1137 		fkeyp = (fkeyarg_t *)arg;
1138 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
1139 			lwkt_reltoken(&tty_token);
1140 			crit_exit();
1141 			return EINVAL;
1142 		}
1143 		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
1144 		      kbd->kb_fkeytab[fkeyp->keynum].len);
1145 		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
1146 		break;
1147 	case SETFKEY:		/* set functionkey string */
1148 #ifndef KBD_DISABLE_KEYMAP_LOAD
1149 		fkeyp = (fkeyarg_t *)arg;
1150 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
1151 			lwkt_reltoken(&tty_token);
1152 			crit_exit();
1153 			return EINVAL;
1154 		}
1155 		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
1156 		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
1157 		      kbd->kb_fkeytab[fkeyp->keynum].len);
1158 		break;
1159 #else
1160 		lwkt_reltoken(&tty_token);
1161 		crit_exit();
1162 		return ENODEV;
1163 #endif
1164 
1165 	default:
1166 		lwkt_reltoken(&tty_token);
1167 		crit_exit();
1168 		return ENOIOCTL;
1169 	}
1170 
1171 	lwkt_reltoken(&tty_token);
1172 	crit_exit();
1173 	return 0;
1174 }
1175 
1176 /* get a pointer to the string associated with the given function key */
1177 u_char *
1178 genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
1179 {
1180 	u_char *ch;
1181 
1182 	if (kbd == NULL)
1183 		return NULL;
1184 
1185 	lwkt_gettoken(&tty_token);
1186 	fkey -= F_FN;
1187 	if (fkey > kbd->kb_fkeytab_size) {
1188 		lwkt_reltoken(&tty_token);
1189 		return NULL;
1190 	}
1191 	*len = kbd->kb_fkeytab[fkey].len;
1192 	ch = kbd->kb_fkeytab[fkey].str;
1193 
1194 	lwkt_reltoken(&tty_token);
1195 	return ch;
1196 }
1197 
1198 /* diagnostic dump */
1199 static char *
1200 get_kbd_type_name(int type)
1201 {
1202 	static struct {
1203 		int type;
1204 		char *name;
1205 	} name_table[] = {
1206 		{ KB_84,	"AT 84" },
1207 		{ KB_101,	"AT 101/102" },
1208 		{ KB_OTHER,	"generic" },
1209 	};
1210 	int i;
1211 
1212 	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
1213 		if (type == name_table[i].type)
1214 			return name_table[i].name;
1215 	}
1216 	return "unknown";
1217 }
1218 
1219 void
1220 genkbd_diag(keyboard_t *kbd, int level)
1221 {
1222 	if (level > 0) {
1223 		kprintf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
1224 		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
1225 		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
1226 		       kbd->kb_config, kbd->kb_flags);
1227 		if (kbd->kb_io_base > 0)
1228 			kprintf(", port:0x%x-0x%x", kbd->kb_io_base,
1229 			       kbd->kb_io_base + kbd->kb_io_size - 1);
1230 		kprintf("\n");
1231 	}
1232 }
1233 
1234 #define set_lockkey_state(k, s, l)				\
1235 	if (!((s) & l ## DOWN)) {				\
1236 		int i;						\
1237 		(s) |= l ## DOWN;				\
1238 		(s) ^= l ## ED;					\
1239 		i = (s) & LOCK_MASK;				\
1240 		kbd_ioctl((k), KDSETLED, (caddr_t)&i); \
1241 	}
1242 
1243 static u_int
1244 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
1245 {
1246 	int i;
1247 
1248 	lwkt_gettoken(&tty_token);
1249 	/* make an index into the accent map */
1250 	i = key - F_ACC + 1;
1251 	if ((i > kbd->kb_accentmap->n_accs)
1252 	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
1253 		/* the index is out of range or pointing to an empty entry */
1254 		*accents = 0;
1255 		lwkt_reltoken(&tty_token);
1256 		return ERRKEY;
1257 	}
1258 
1259 	/*
1260 	 * If the same accent key has been hit twice, produce the accent char
1261 	 * itself.
1262 	 */
1263 	if (i == *accents) {
1264 		key = kbd->kb_accentmap->acc[i - 1].accchar;
1265 		*accents = 0;
1266 		lwkt_reltoken(&tty_token);
1267 		return key;
1268 	}
1269 
1270 	/* remember the index and wait for the next key  */
1271 	*accents = i;
1272 	lwkt_reltoken(&tty_token);
1273 	return NOKEY;
1274 }
1275 
1276 static u_int
1277 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
1278 {
1279 	struct acc_t *acc;
1280 	int i;
1281 
1282 	lwkt_gettoken(&tty_token);
1283 	acc = &kbd->kb_accentmap->acc[*accents - 1];
1284 	*accents = 0;
1285 
1286 	/*
1287 	 * If the accent key is followed by the space key,
1288 	 * produce the accent char itself.
1289 	 */
1290 	if (ch == ' ') {
1291 		lwkt_reltoken(&tty_token);
1292 		return acc->accchar;
1293 	}
1294 
1295 	/* scan the accent map */
1296 	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
1297 		if (acc->map[i][0] == 0)	/* end of table */
1298 			break;
1299 		if (acc->map[i][0] == ch) {
1300 			lwkt_reltoken(&tty_token);
1301 			return acc->map[i][1];
1302 		}
1303 	}
1304 	lwkt_reltoken(&tty_token);
1305 	/* this char cannot be accented... */
1306 	return ERRKEY;
1307 }
1308 
1309 int
1310 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
1311 		 int *accents)
1312 {
1313 	struct keyent_t *key;
1314 	int state = *shiftstate;
1315 	int action;
1316 	int f;
1317 	int i;
1318 
1319 	lwkt_gettoken(&tty_token);
1320 	i = keycode;
1321 	f = state & (AGRS | ALKED);
1322 	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
1323 		i += ALTGR_OFFSET;
1324 	key = &kbd->kb_keymap->key[i];
1325 	i = ((state & SHIFTS) ? 1 : 0)
1326 	    | ((state & CTLS) ? 2 : 0)
1327 	    | ((state & ALTS) ? 4 : 0);
1328 	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
1329 		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
1330 		i ^= 1;
1331 
1332 	if (up) {	/* break: key released */
1333 		action = kbd->kb_lastact[keycode];
1334 		kbd->kb_lastact[keycode] = NOP;
1335 		switch (action) {
1336 		case LSHA:
1337 			if (state & SHIFTAON) {
1338 				set_lockkey_state(kbd, state, ALK);
1339 				state &= ~ALKDOWN;
1340 			}
1341 			action = LSH;
1342 			/* FALL THROUGH */
1343 		case LSH:
1344 			state &= ~SHIFTS1;
1345 			break;
1346 		case RSHA:
1347 			if (state & SHIFTAON) {
1348 				set_lockkey_state(kbd, state, ALK);
1349 				state &= ~ALKDOWN;
1350 			}
1351 			action = RSH;
1352 			/* FALL THROUGH */
1353 		case RSH:
1354 			state &= ~SHIFTS2;
1355 			break;
1356 		case LCTRA:
1357 			if (state & SHIFTAON) {
1358 				set_lockkey_state(kbd, state, ALK);
1359 				state &= ~ALKDOWN;
1360 			}
1361 			action = LCTR;
1362 			/* FALL THROUGH */
1363 		case LCTR:
1364 			state &= ~CTLS1;
1365 			break;
1366 		case RCTRA:
1367 			if (state & SHIFTAON) {
1368 				set_lockkey_state(kbd, state, ALK);
1369 				state &= ~ALKDOWN;
1370 			}
1371 			action = RCTR;
1372 			/* FALL THROUGH */
1373 		case RCTR:
1374 			state &= ~CTLS2;
1375 			break;
1376 		case LALTA:
1377 			if (state & SHIFTAON) {
1378 				set_lockkey_state(kbd, state, ALK);
1379 				state &= ~ALKDOWN;
1380 			}
1381 			action = LALT;
1382 			/* FALL THROUGH */
1383 		case LALT:
1384 			state &= ~ALTS1;
1385 			break;
1386 		case RALTA:
1387 			if (state & SHIFTAON) {
1388 				set_lockkey_state(kbd, state, ALK);
1389 				state &= ~ALKDOWN;
1390 			}
1391 			action = RALT;
1392 			/* FALL THROUGH */
1393 		case RALT:
1394 			state &= ~ALTS2;
1395 			break;
1396 		case ASH:
1397 			state &= ~AGRS1;
1398 			break;
1399 		case META:
1400 			state &= ~METAS1;
1401 			break;
1402 		case NLK:
1403 			state &= ~NLKDOWN;
1404 			break;
1405 		case CLK:
1406 			state &= ~CLKDOWN;
1407 			break;
1408 		case SLK:
1409 			state &= ~SLKDOWN;
1410 			break;
1411 		case ALK:
1412 			state &= ~ALKDOWN;
1413 			break;
1414 		case NOP:
1415 			/* release events of regular keys are not reported */
1416 			*shiftstate &= ~SHIFTAON;
1417 			lwkt_reltoken(&tty_token);
1418 			return NOKEY;
1419 		}
1420 		*shiftstate = state & ~SHIFTAON;
1421 		lwkt_reltoken(&tty_token);
1422 		return (SPCLKEY | RELKEY | action);
1423 	} else {	/* make: key pressed */
1424 		action = key->map[i];
1425 		state &= ~SHIFTAON;
1426 		if (key->spcl & (0x80 >> i)) {
1427 			/* special keys */
1428 			if (kbd->kb_lastact[keycode] == NOP)
1429 				kbd->kb_lastact[keycode] = action;
1430 			if (kbd->kb_lastact[keycode] != action)
1431 				action = NOP;
1432 			switch (action) {
1433 			/* LOCKING KEYS */
1434 			case NLK:
1435 				set_lockkey_state(kbd, state, NLK);
1436 				break;
1437 			case CLK:
1438 				set_lockkey_state(kbd, state, CLK);
1439 				break;
1440 			case SLK:
1441 				set_lockkey_state(kbd, state, SLK);
1442 				break;
1443 			case ALK:
1444 				set_lockkey_state(kbd, state, ALK);
1445 				break;
1446 			/* NON-LOCKING KEYS */
1447 			case SPSC: case RBT:  case SUSP: case STBY:
1448 			case DBG:  case NEXT: case PREV: case PNC:
1449 			case HALT: case PDWN:
1450 				*accents = 0;
1451 				break;
1452 			case BTAB:
1453 				*accents = 0;
1454 				action |= BKEY;
1455 				break;
1456 			case LSHA:
1457 				state |= SHIFTAON;
1458 				action = LSH;
1459 				/* FALL THROUGH */
1460 			case LSH:
1461 				state |= SHIFTS1;
1462 				break;
1463 			case RSHA:
1464 				state |= SHIFTAON;
1465 				action = RSH;
1466 				/* FALL THROUGH */
1467 			case RSH:
1468 				state |= SHIFTS2;
1469 				break;
1470 			case LCTRA:
1471 				state |= SHIFTAON;
1472 				action = LCTR;
1473 				/* FALL THROUGH */
1474 			case LCTR:
1475 				state |= CTLS1;
1476 				break;
1477 			case RCTRA:
1478 				state |= SHIFTAON;
1479 				action = RCTR;
1480 				/* FALL THROUGH */
1481 			case RCTR:
1482 				state |= CTLS2;
1483 				break;
1484 			case LALTA:
1485 				state |= SHIFTAON;
1486 				action = LALT;
1487 				/* FALL THROUGH */
1488 			case LALT:
1489 				state |= ALTS1;
1490 				break;
1491 			case RALTA:
1492 				state |= SHIFTAON;
1493 				action = RALT;
1494 				/* FALL THROUGH */
1495 			case RALT:
1496 				state |= ALTS2;
1497 				break;
1498 			case ASH:
1499 				state |= AGRS1;
1500 				break;
1501 			case META:
1502 				state |= METAS1;
1503 				break;
1504 			case NOP:
1505 				*shiftstate = state;
1506 				lwkt_reltoken(&tty_token);
1507 				return NOKEY;
1508 			default:
1509 				/* is this an accent (dead) key? */
1510 				*shiftstate = state;
1511 				if (action >= F_ACC && action <= L_ACC) {
1512 					action = save_accent_key(kbd, action,
1513 								 accents);
1514 					switch (action) {
1515 					case NOKEY:
1516 					case ERRKEY:
1517 						lwkt_reltoken(&tty_token);
1518 						return action;
1519 					default:
1520 						if (state & METAS) {
1521 							lwkt_reltoken(&tty_token);
1522 							return (action | MKEY);
1523 						} else {
1524 							lwkt_reltoken(&tty_token);
1525 							return action;
1526 						}
1527 					}
1528 					/* NOT REACHED */
1529 				}
1530 				/* other special keys */
1531 				if (*accents > 0) {
1532 					*accents = 0;
1533 					lwkt_reltoken(&tty_token);
1534 					return ERRKEY;
1535 				}
1536 				if (action >= F_FN && action <= L_FN)
1537 					action |= FKEY;
1538 				/* XXX: return fkey string for the FKEY? */
1539 				lwkt_reltoken(&tty_token);
1540 				return (SPCLKEY | action);
1541 			}
1542 			*shiftstate = state;
1543 			lwkt_reltoken(&tty_token);
1544 			return (SPCLKEY | action);
1545 		} else {
1546 			/* regular keys */
1547 			kbd->kb_lastact[keycode] = NOP;
1548 			*shiftstate = state;
1549 			if (*accents > 0) {
1550 				/* make an accented char */
1551 				action = make_accent_char(kbd, action, accents);
1552 				if (action == ERRKEY) {
1553 					lwkt_reltoken(&tty_token);
1554 					return action;
1555 				}
1556 			}
1557 			if (state & METAS)
1558 				action |= MKEY;
1559 			lwkt_reltoken(&tty_token);
1560 			return action;
1561 		}
1562 	}
1563 	/* NOT REACHED */
1564 	lwkt_reltoken(&tty_token);
1565 }
1566