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