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