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