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