xref: /freebsd/sys/dev/kbd/kbd.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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$
27  */
28 
29 #include "kbd.h"
30 #include "opt_kbd.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/conf.h>
37 #include <sys/proc.h>
38 #include <sys/tty.h>
39 #include <sys/poll.h>
40 #include <sys/vnode.h>
41 #include <sys/uio.h>
42 
43 #include <machine/console.h>
44 
45 #include <dev/kbd/kbdreg.h>
46 
47 #define KBD_INDEX(dev)	minor(dev)
48 
49 typedef struct genkbd_softc {
50 	int		gkb_flags;	/* flag/status bits */
51 #define KB_ASLEEP	(1 << 0)
52 	struct clist	gkb_q;		/* input queue */
53 	struct selinfo	gkb_rsel;
54 } genkbd_softc_t;
55 
56 /* local arrays */
57 
58 /*
59  * We need at least one entry each in order to initialize a keyboard
60  * for the kernel console.  The arrays will be increased dynamically
61  * when necessary.
62  */
63 
64 static int		keyboards = 1;
65 static keyboard_t	*kbd_ini;
66 static keyboard_t	**keyboard = &kbd_ini;
67 static keyboard_switch_t *kbdsw_ini;
68        keyboard_switch_t **kbdsw = &kbdsw_ini;
69 
70 #define ARRAY_DELTA	4
71 
72 static int
73 kbd_realloc_array(void)
74 {
75 	keyboard_t **new_kbd;
76 	keyboard_switch_t **new_kbdsw;
77 	int newsize;
78 	int s;
79 
80 	s = spltty();
81 	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
82 	new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT);
83 	if (new_kbd == NULL) {
84 		splx(s);
85 		return ENOMEM;
86 	}
87 	new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT);
88 	if (new_kbdsw == NULL) {
89 		free(new_kbd, M_DEVBUF);
90 		splx(s);
91 		return ENOMEM;
92 	}
93 	bzero(new_kbd, sizeof(*new_kbd)*newsize);
94 	bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
95 	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
96 	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
97 	if (keyboards > 1) {
98 		free(keyboard, M_DEVBUF);
99 		free(kbdsw, M_DEVBUF);
100 	}
101 	keyboard = new_kbd;
102 	kbdsw = new_kbdsw;
103 	keyboards = newsize;
104 	splx(s);
105 
106 	if (bootverbose)
107 		printf("kbd: new array size %d\n", keyboards);
108 
109 	return 0;
110 }
111 
112 /*
113  * Low-level keyboard driver functions
114  * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
115  * driver, call these functions to initialize the keyboard_t structure
116  * and register it to the virtual keyboard driver `kbd'.
117  */
118 
119 /* initialize the keyboard_t structure */
120 void
121 kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
122 		int port, int port_size)
123 {
124 	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
125 	kbd->kb_name = name;
126 	kbd->kb_type = type;
127 	kbd->kb_unit = unit;
128 	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
129 	kbd->kb_led = 0;		/* unknown */
130 	kbd->kb_io_base = port;
131 	kbd->kb_io_size = port_size;
132 	kbd->kb_data = NULL;
133 	kbd->kb_keymap = NULL;
134 	kbd->kb_accentmap = NULL;
135 	kbd->kb_fkeytab = NULL;
136 	kbd->kb_fkeytab_size = 0;
137 	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
138 	kbd->kb_delay2 = KB_DELAY2;
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 	kbd->kb_keymap = keymap;
146 	kbd->kb_accentmap = accmap;
147 	kbd->kb_fkeytab = fkeymap;
148 	kbd->kb_fkeytab_size = fkeymap_size;
149 }
150 
151 /* register a keyboard and associate it with a function table */
152 int
153 kbd_register(keyboard_t *kbd)
154 {
155 	const keyboard_driver_t **list;
156 	const keyboard_driver_t *p;
157 	int index;
158 
159 	for (index = 0; index < keyboards; ++index) {
160 		if (keyboard[index] == NULL)
161 			break;
162 	}
163 	if (index >= keyboards) {
164 		if (kbd_realloc_array())
165 			return -1;
166 	}
167 
168 	kbd->kb_index = index;
169 	KBD_UNBUSY(kbd);
170 	KBD_VALID(kbd);
171 	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
172 	kbd->kb_token = NULL;
173 	kbd->kb_callback.kc_func = NULL;
174 	kbd->kb_callback.kc_arg = NULL;
175 
176 	list = (const keyboard_driver_t **)kbddriver_set.ls_items;
177 	while ((p = *list++) != NULL) {
178 		if (strcmp(p->name, kbd->kb_name) == 0) {
179 			keyboard[index] = kbd;
180 			kbdsw[index] = p->kbdsw;
181 			return index;
182 		}
183 	}
184 
185 	return -1;
186 }
187 
188 int
189 kbd_unregister(keyboard_t *kbd)
190 {
191 	int error;
192 	int s;
193 
194 	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
195 		return ENOENT;
196 	if (keyboard[kbd->kb_index] != kbd)
197 		return ENOENT;
198 
199 	s = spltty();
200 	if (KBD_IS_BUSY(kbd)) {
201 		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
202 						    kbd->kb_callback.kc_arg);
203 		if (error) {
204 			splx(s);
205 			return error;
206 		}
207 		if (KBD_IS_BUSY(kbd)) {
208 			splx(s);
209 			return EBUSY;
210 		}
211 	}
212 	KBD_INVALID(kbd);
213 	keyboard[kbd->kb_index] = NULL;
214 	kbdsw[kbd->kb_index] = NULL;
215 
216 	splx(s);
217 	return 0;
218 }
219 
220 /* find a funciton table by the driver name */
221 keyboard_switch_t
222 *kbd_get_switch(char *driver)
223 {
224 	const keyboard_driver_t **list;
225 	const keyboard_driver_t *p;
226 
227 	list = (const keyboard_driver_t **)kbddriver_set.ls_items;
228 	while ((p = *list++) != NULL) {
229 		if (strcmp(p->name, driver) == 0)
230 			return p->kbdsw;
231 	}
232 
233 	return NULL;
234 }
235 
236 /*
237  * Keyboard client functions
238  * Keyboard clients, such as the console driver `syscons' and the keyboard
239  * cdev driver, use these functions to claim and release a keyboard for
240  * exclusive use.
241  */
242 
243 /* find the keyboard specified by a driver name and a unit number */
244 int
245 kbd_find_keyboard(char *driver, int unit)
246 {
247 	int i;
248 
249 	for (i = 0; i < keyboards; ++i) {
250 		if (keyboard[i] == NULL)
251 			continue;
252 		if (!KBD_IS_VALID(keyboard[i]))
253 			continue;
254 		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
255 			continue;
256 		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
257 			continue;
258 		return i;
259 	}
260 	return -1;
261 }
262 
263 /* allocate a keyboard */
264 int
265 kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
266 	     void *arg)
267 {
268 	int index;
269 	int s;
270 
271 	if (func == NULL)
272 		return -1;
273 
274 	s = spltty();
275 	index = kbd_find_keyboard(driver, unit);
276 	if (index >= 0) {
277 		if (KBD_IS_BUSY(keyboard[index])) {
278 			splx(s);
279 			return -1;
280 		}
281 		keyboard[index]->kb_token = id;
282 		KBD_BUSY(keyboard[index]);
283 		keyboard[index]->kb_callback.kc_func = func;
284 		keyboard[index]->kb_callback.kc_arg = arg;
285 		(*kbdsw[index]->clear_state)(keyboard[index]);
286 	}
287 	splx(s);
288 	return index;
289 }
290 
291 int
292 kbd_release(keyboard_t *kbd, void *id)
293 {
294 	int error;
295 	int s;
296 
297 	s = spltty();
298 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
299 		error = EINVAL;
300 	} else if (kbd->kb_token != id) {
301 		error = EPERM;
302 	} else {
303 		kbd->kb_token = NULL;
304 		KBD_UNBUSY(kbd);
305 		kbd->kb_callback.kc_func = NULL;
306 		kbd->kb_callback.kc_arg = NULL;
307 		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
308 		error = 0;
309 	}
310 	splx(s);
311 	return error;
312 }
313 
314 int
315 kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
316 		    void *arg)
317 {
318 	int error;
319 	int s;
320 
321 	s = spltty();
322 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
323 		error = EINVAL;
324 	} else if (kbd->kb_token != id) {
325 		error = EPERM;
326 	} else if (func == NULL) {
327 		error = EINVAL;
328 	} else {
329 		kbd->kb_callback.kc_func = func;
330 		kbd->kb_callback.kc_arg = arg;
331 		error = 0;
332 	}
333 	splx(s);
334 	return error;
335 }
336 
337 /* get a keyboard structure */
338 keyboard_t
339 *kbd_get_keyboard(int index)
340 {
341 	if ((index < 0) || (index >= keyboards))
342 		return NULL;
343 	if (keyboard[index] == NULL)
344 		return NULL;
345 	if (!KBD_IS_VALID(keyboard[index]))
346 		return NULL;
347 	return keyboard[index];
348 }
349 
350 /*
351  * The back door for the console driver; configure keyboards
352  * This function is for the kernel console to initialize keyboards
353  * at very early stage.
354  */
355 
356 int
357 kbd_configure(int flags)
358 {
359 	const keyboard_driver_t **list;
360 	const keyboard_driver_t *p;
361 
362 	list = (const keyboard_driver_t **)kbddriver_set.ls_items;
363 	while ((p = *list++) != NULL) {
364 		if (p->configure != NULL)
365 			(*p->configure)(flags);
366 	}
367 
368 	return 0;
369 }
370 
371 #ifdef KBD_INSTALL_CDEV
372 
373 /*
374  * Virtual keyboard cdev driver functions
375  * The virtual keyboard driver dispatches driver functions to
376  * appropriate subdrivers.
377  */
378 
379 #define KBD_UNIT(dev)	minor(dev)
380 
381 static d_open_t		genkbdopen;
382 static d_close_t	genkbdclose;
383 static d_read_t		genkbdread;
384 static d_write_t	genkbdwrite;
385 static d_ioctl_t	genkbdioctl;
386 static d_poll_t		genkbdpoll;
387 
388 #define CDEV_MAJOR	112
389 
390 static struct cdevsw kbd_cdevsw = {
391 	/* open */	genkbdopen,
392 	/* close */	genkbdclose,
393 	/* read */	genkbdread,
394 	/* write */	genkbdwrite,
395 	/* ioctl */	genkbdioctl,
396 	/* poll */	genkbdpoll,
397 	/* mmap */	nommap,
398 	/* strategy */	nostrategy,
399 	/* name */	"kbd",
400 	/* maj */	CDEV_MAJOR,
401 	/* dump */	nodump,
402 	/* psize */	nopsize,
403 	/* flags */	0,
404 	/* bmaj */	-1
405 };
406 
407 int
408 kbd_attach(keyboard_t *kbd)
409 {
410 	dev_t dev;
411 
412 	if (kbd->kb_index >= keyboards)
413 		return EINVAL;
414 	if (keyboard[kbd->kb_index] != kbd)
415 		return EINVAL;
416 
417 	dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
418 		       "kbd%r", kbd->kb_index);
419 	if (dev->si_drv1 == NULL)
420 		dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
421 				      M_WAITOK);
422 	bzero(dev->si_drv1, sizeof(genkbd_softc_t));
423 
424 	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
425 	return 0;
426 }
427 
428 int
429 kbd_detach(keyboard_t *kbd)
430 {
431 	if (kbd->kb_index >= keyboards)
432 		return EINVAL;
433 	if (keyboard[kbd->kb_index] != kbd)
434 		return EINVAL;
435 
436 	/* XXX: unmake_dev() ? */
437 	return 0;
438 }
439 
440 /*
441  * Generic keyboard cdev driver functions
442  * Keyboard subdrivers may call these functions to implement common
443  * driver functions.
444  */
445 
446 #define KB_QSIZE	512
447 #define KB_BUFSIZE	64
448 
449 static kbd_callback_func_t genkbd_event;
450 
451 static int
452 genkbdopen(dev_t dev, int mode, int flag, struct proc *p)
453 {
454 	keyboard_t *kbd;
455 	genkbd_softc_t *sc;
456 	int s;
457 	int i;
458 
459 	s = spltty();
460 	sc = dev->si_drv1;
461 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
462 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
463 		splx(s);
464 		return ENXIO;
465 	}
466 	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
467 			 genkbd_event, (void *)sc);
468 	if (i < 0) {
469 		splx(s);
470 		return EBUSY;
471 	}
472 	/* assert(i == kbd->kb_index) */
473 	/* assert(kbd == kbd_get_keyboard(i)) */
474 
475 	/*
476 	 * NOTE: even when we have successfully claimed a keyboard,
477 	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
478 	 */
479 
480 #if 0
481 	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
482 #endif
483 	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
484 	sc->gkb_rsel.si_flags = 0;
485 	sc->gkb_rsel.si_pid = 0;
486 	splx(s);
487 
488 	return 0;
489 }
490 
491 static int
492 genkbdclose(dev_t dev, int mode, int flag, struct proc *p)
493 {
494 	keyboard_t *kbd;
495 	genkbd_softc_t *sc;
496 	int s;
497 
498 	/*
499 	 * NOTE: the device may have already become invalid.
500 	 * kbd == NULL || !KBD_IS_VALID(kbd)
501 	 */
502 	s = spltty();
503 	sc = dev->si_drv1;
504 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
505 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
506 		/* XXX: we shall be forgiving and don't report error... */
507 	} else {
508 		kbd_release(kbd, (void *)sc);
509 #if 0
510 		clist_free_cblocks(&sc->gkb_q);
511 #endif
512 	}
513 	splx(s);
514 	return 0;
515 }
516 
517 static int
518 genkbdread(dev_t dev, struct uio *uio, int flag)
519 {
520 	keyboard_t *kbd;
521 	genkbd_softc_t *sc;
522 	u_char buffer[KB_BUFSIZE];
523 	int len;
524 	int error;
525 	int s;
526 
527 	/* wait for input */
528 	s = spltty();
529 	sc = dev->si_drv1;
530 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
531 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
532 		splx(s);
533 		return ENXIO;
534 	}
535 	while (sc->gkb_q.c_cc == 0) {
536 		if (flag & IO_NDELAY) {
537 			splx(s);
538 			return EWOULDBLOCK;
539 		}
540 		sc->gkb_flags |= KB_ASLEEP;
541 		error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
542 		kbd = kbd_get_keyboard(KBD_INDEX(dev));
543 		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
544 			splx(s);
545 			return ENXIO;	/* our keyboard has gone... */
546 		}
547 		if (error) {
548 			sc->gkb_flags &= ~KB_ASLEEP;
549 			splx(s);
550 			return error;
551 		}
552 	}
553 	splx(s);
554 
555 	/* copy as much input as possible */
556 	error = 0;
557 	while (uio->uio_resid > 0) {
558 		len = imin(uio->uio_resid, sizeof(buffer));
559 		len = q_to_b(&sc->gkb_q, buffer, len);
560 		if (len <= 0)
561 			break;
562 		error = uiomove(buffer, len, uio);
563 		if (error)
564 			break;
565 	}
566 
567 	return error;
568 }
569 
570 static int
571 genkbdwrite(dev_t dev, struct uio *uio, int flag)
572 {
573 	keyboard_t *kbd;
574 
575 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
576 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
577 		return ENXIO;
578 	return ENODEV;
579 }
580 
581 static int
582 genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
583 {
584 	keyboard_t *kbd;
585 	int error;
586 
587 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
588 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
589 		return ENXIO;
590 	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
591 	if (error == ENOIOCTL)
592 		error = ENODEV;
593 	return error;
594 }
595 
596 static int
597 genkbdpoll(dev_t dev, int events, struct proc *p)
598 {
599 	keyboard_t *kbd;
600 	genkbd_softc_t *sc;
601 	int revents;
602 	int s;
603 
604 	revents = 0;
605 	s = spltty();
606 	sc = dev->si_drv1;
607 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
608 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
609 		revents =  POLLHUP;	/* the keyboard has gone */
610 	} else if (events & (POLLIN | POLLRDNORM)) {
611 		if (sc->gkb_q.c_cc > 0)
612 			revents = events & (POLLIN | POLLRDNORM);
613 		else
614 			selrecord(p, &sc->gkb_rsel);
615 	}
616 	splx(s);
617 	return revents;
618 }
619 
620 static int
621 genkbd_event(keyboard_t *kbd, int event, void *arg)
622 {
623 	genkbd_softc_t *sc;
624 	size_t len;
625 	u_char *cp;
626 	int mode;
627 	int c;
628 
629 	/* assert(KBD_IS_VALID(kbd)) */
630 	sc = (genkbd_softc_t *)arg;
631 
632 	switch (event) {
633 	case KBDIO_KEYINPUT:
634 		break;
635 	case KBDIO_UNLOADING:
636 		/* the keyboard is going... */
637 		kbd_release(kbd, (void *)sc);
638 		if (sc->gkb_flags & KB_ASLEEP) {
639 			sc->gkb_flags &= ~KB_ASLEEP;
640 			wakeup((caddr_t)sc);
641 		}
642 		selwakeup(&sc->gkb_rsel);
643 		return 0;
644 	default:
645 		return EINVAL;
646 	}
647 
648 	/* obtain the current key input mode */
649 	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
650 		mode = K_XLATE;
651 
652 	/* read all pending input */
653 	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
654 		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
655 		if (c == NOKEY)
656 			continue;
657 		if (c == ERRKEY)	/* XXX: ring bell? */
658 			continue;
659 		if (!KBD_IS_BUSY(kbd))
660 			/* the device is not open, discard the input */
661 			continue;
662 
663 		/* store the byte as is for K_RAW and K_CODE modes */
664 		if (mode != K_XLATE) {
665 			putc(KEYCHAR(c), &sc->gkb_q);
666 			continue;
667 		}
668 
669 		/* K_XLATE */
670 		if (c & RELKEY)	/* key release is ignored */
671 			continue;
672 
673 		/* process special keys; most of them are just ignored... */
674 		if (c & SPCLKEY) {
675 			switch (KEYCHAR(c)) {
676 			/* locking keys */
677 			case NLK:  case CLK:  case SLK:  case ALK:
678 			/* shift keys */
679 			case LSH:  case RSH:  case LCTR: case RCTR:
680 			case LALT: case RALT: case ASH:  case META:
681 			/* other special keys */
682 			case NOP:  case SPSC: case RBT:  case SUSP:
683 			case STBY: case DBG:  case NEXT:
684 				/* ignore them... */
685 				continue;
686 			case BTAB:	/* a backtab: ESC [ Z */
687 				putc(0x1b, &sc->gkb_q);
688 				putc('[', &sc->gkb_q);
689 				putc('Z', &sc->gkb_q);
690 				continue;
691 			}
692 		}
693 
694 		/* normal chars, normal chars with the META, function keys */
695 		switch (KEYFLAGS(c)) {
696 		case 0:			/* a normal char */
697 			putc(KEYCHAR(c), &sc->gkb_q);
698 			break;
699 		case MKEY:		/* the META flag: prepend ESC */
700 			putc(0x1b, &sc->gkb_q);
701 			putc(KEYCHAR(c), &sc->gkb_q);
702 			break;
703 		case FKEY | SPCLKEY:	/* a function key, return string */
704 			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
705 							KEYCHAR(c), &len);
706 			if (cp != NULL) {
707 				while (len-- >  0)
708 					putc(*cp++, &sc->gkb_q);
709 			}
710 			break;
711 		}
712 	}
713 
714 	/* wake up sleeping/polling processes */
715 	if (sc->gkb_q.c_cc > 0) {
716 		if (sc->gkb_flags & KB_ASLEEP) {
717 			sc->gkb_flags &= ~KB_ASLEEP;
718 			wakeup((caddr_t)sc);
719 		}
720 		selwakeup(&sc->gkb_rsel);
721 	}
722 
723 	return 0;
724 }
725 
726 #endif /* KBD_INSTALL_CDEV */
727 
728 /*
729  * Generic low-level keyboard functions
730  * The low-level functions in the keyboard subdriver may use these
731  * functions.
732  */
733 
734 int
735 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
736 {
737 	keyarg_t *keyp;
738 	fkeyarg_t *fkeyp;
739 	int s;
740 	int i;
741 
742 	s = spltty();
743 	switch (cmd) {
744 
745 	case KDGKBINFO:		/* get keyboard information */
746 		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
747 		i = imin(strlen(kbd->kb_name) + 1,
748 			 sizeof(((keyboard_info_t *)arg)->kb_name));
749 		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
750 		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
751 		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
752 		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
753 		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
754 		break;
755 
756 	case KDGKBTYPE:		/* get keyboard type */
757 		*(int *)arg = kbd->kb_type;
758 		break;
759 
760 	case GIO_KEYMAP:	/* get keyboard translation table */
761 		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
762 		break;
763 	case PIO_KEYMAP:	/* set keyboard translation table */
764 #ifndef KBD_DISABLE_KEYMAP_LOAD
765 		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
766 		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
767 		break;
768 #else
769 		splx(s);
770 		return ENODEV;
771 #endif
772 
773 	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
774 		keyp = (keyarg_t *)arg;
775 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
776 					/sizeof(kbd->kb_keymap->key[0])) {
777 			splx(s);
778 			return EINVAL;
779 		}
780 		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
781 		      sizeof(keyp->key));
782 		break;
783 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
784 #ifndef KBD_DISABLE_KEYMAP_LOAD
785 		keyp = (keyarg_t *)arg;
786 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
787 					/sizeof(kbd->kb_keymap->key[0])) {
788 			splx(s);
789 			return EINVAL;
790 		}
791 		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
792 		      sizeof(keyp->key));
793 		break;
794 #else
795 		splx(s);
796 		return ENODEV;
797 #endif
798 
799 	case GIO_DEADKEYMAP:	/* get accent key translation table */
800 		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
801 		break;
802 	case PIO_DEADKEYMAP:	/* set accent key translation table */
803 #ifndef KBD_DISABLE_KEYMAP_LOAD
804 		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
805 		break;
806 #else
807 		splx(s);
808 		return ENODEV;
809 #endif
810 
811 	case GETFKEY:		/* get functionkey string */
812 		fkeyp = (fkeyarg_t *)arg;
813 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
814 			splx(s);
815 			return EINVAL;
816 		}
817 		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
818 		      kbd->kb_fkeytab[fkeyp->keynum].len);
819 		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
820 		break;
821 	case SETFKEY:		/* set functionkey string */
822 #ifndef KBD_DISABLE_KEYMAP_LOAD
823 		fkeyp = (fkeyarg_t *)arg;
824 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
825 			splx(s);
826 			return EINVAL;
827 		}
828 		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
829 		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
830 		      kbd->kb_fkeytab[fkeyp->keynum].len);
831 		break;
832 #else
833 		splx(s);
834 		return ENODEV;
835 #endif
836 
837 	default:
838 		splx(s);
839 		return ENOIOCTL;
840 	}
841 
842 	splx(s);
843 	return 0;
844 }
845 
846 /* get a pointer to the string associated with the given function key */
847 u_char
848 *genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
849 {
850 	if (kbd == NULL)
851 		return NULL;
852 	fkey -= F_FN;
853 	if (fkey > kbd->kb_fkeytab_size)
854 		return NULL;
855 	*len = kbd->kb_fkeytab[fkey].len;
856 	return kbd->kb_fkeytab[fkey].str;
857 }
858 
859 /* diagnostic dump */
860 static char
861 *get_kbd_type_name(int type)
862 {
863 	static struct {
864 		int type;
865 		char *name;
866 	} name_table[] = {
867 		{ KB_84,	"AT 84" },
868 		{ KB_101,	"AT 101/102" },
869 		{ KB_OTHER,	"generic" },
870 	};
871 	int i;
872 
873 	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
874 		if (type == name_table[i].type)
875 			return name_table[i].name;
876 	}
877 	return "unknown";
878 }
879 
880 void
881 genkbd_diag(keyboard_t *kbd, int level)
882 {
883 	if (level > 0) {
884 		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
885 		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
886 		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
887 		       kbd->kb_config, kbd->kb_flags);
888 		if (kbd->kb_io_base > 0)
889 			printf(", port:0x%x-0x%x", kbd->kb_io_base,
890 			       kbd->kb_io_base + kbd->kb_io_size - 1);
891 		printf("\n");
892 	}
893 }
894 
895 #define set_lockkey_state(k, s, l)				\
896 	if (!((s) & l ## DOWN)) {				\
897 		int i;						\
898 		(s) |= l ## DOWN;				\
899 		(s) ^= l ## ED;					\
900 		i = (s) & LOCK_MASK;				\
901 		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
902 	}
903 
904 static u_int
905 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
906 {
907 	int i;
908 
909 	/* make an index into the accent map */
910 	i = key - F_ACC + 1;
911 	if ((i > kbd->kb_accentmap->n_accs)
912 	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
913 		/* the index is out of range or pointing to an empty entry */
914 		*accents = 0;
915 		return ERRKEY;
916 	}
917 
918 	/*
919 	 * If the same accent key has been hit twice, produce the accent char
920 	 * itself.
921 	 */
922 	if (i == *accents) {
923 		key = kbd->kb_accentmap->acc[i - 1].accchar;
924 		*accents = 0;
925 		return key;
926 	}
927 
928 	/* remember the index and wait for the next key  */
929 	*accents = i;
930 	return NOKEY;
931 }
932 
933 static u_int
934 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
935 {
936 	struct acc_t *acc;
937 	int i;
938 
939 	acc = &kbd->kb_accentmap->acc[*accents - 1];
940 	*accents = 0;
941 
942 	/*
943 	 * If the accent key is followed by the space key,
944 	 * produce the accent char itself.
945 	 */
946 	if (ch == ' ')
947 		return acc->accchar;
948 
949 	/* scan the accent map */
950 	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
951 		if (acc->map[i][0] == 0)	/* end of table */
952 			break;
953 		if (acc->map[i][0] == ch)
954 			return acc->map[i][1];
955 	}
956 	/* this char cannot be accented... */
957 	return ERRKEY;
958 }
959 
960 int
961 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
962 		 int *accents)
963 {
964 	struct keyent_t *key;
965 	int state = *shiftstate;
966 	int action;
967 	int f;
968 	int i;
969 
970 	f = state & (AGRS | ALKED);
971 	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
972 		keycode += ALTGR_OFFSET;
973 	key = &kbd->kb_keymap->key[keycode];
974 	i = ((state & SHIFTS) ? 1 : 0)
975 	    | ((state & CTLS) ? 2 : 0)
976 	    | ((state & ALTS) ? 4 : 0);
977 	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
978 		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
979 		i ^= 1;
980 
981 	action = key->map[i];
982 	if (up) {	/* break: key released */
983 		if (key->spcl & (0x80 >> i)) {
984 			/* special keys */
985 			switch (action) {
986 			case LSH:
987 				state &= ~SHIFTS1;
988 				break;
989 			case RSH:
990 				state &= ~SHIFTS2;
991 				break;
992 			case LCTR:
993 				state &= ~CTLS1;
994 				break;
995 			case RCTR:
996 				state &= ~CTLS2;
997 				break;
998 			case LALT:
999 				state &= ~ALTS1;
1000 				break;
1001 			case RALT:
1002 				state &= ~ALTS2;
1003 				break;
1004 			case ASH:
1005 				state &= ~AGRS1;
1006 				break;
1007 			case META:
1008 				state &= ~METAS1;
1009 				break;
1010 			case NLK:
1011 				state &= ~NLKDOWN;
1012 				break;
1013 			case CLK:
1014 #ifndef PC98
1015 				state &= ~CLKDOWN;
1016 #else
1017 				state &= ~CLKED;
1018 				i = state & LOCK_MASK;
1019 				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1020 							       (caddr_t)&i);
1021 #endif
1022 				break;
1023 			case SLK:
1024 				state &= ~SLKDOWN;
1025 				break;
1026 			case ALK:
1027 				state &= ~ALKDOWN;
1028 				break;
1029 			}
1030 			*shiftstate = state;
1031 			return (SPCLKEY | RELKEY | action);
1032 		}
1033 		/* release events of regular keys are not reported */
1034 		return NOKEY;
1035 	} else {	/* make: key pressed */
1036 		if (key->spcl & (0x80 >> i)) {
1037 			/* special keys */
1038 			switch (action) {
1039 			/* LOCKING KEYS */
1040 			case NLK:
1041 				set_lockkey_state(kbd, state, NLK);
1042 				break;
1043 			case CLK:
1044 #ifndef PC98
1045 				set_lockkey_state(kbd, state, CLK);
1046 #else
1047 				state |= CLKED;
1048 				i = state & LOCK_MASK;
1049 				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1050 							       (caddr_t)&i);
1051 #endif
1052 				break;
1053 			case SLK:
1054 				set_lockkey_state(kbd, state, SLK);
1055 				break;
1056 			case ALK:
1057 				set_lockkey_state(kbd, state, ALK);
1058 				break;
1059 			/* NON-LOCKING KEYS */
1060 			case SPSC: case RBT:  case SUSP: case STBY:
1061 			case DBG:  case NEXT:
1062 				*accents = 0;
1063 				break;
1064 			case BTAB:
1065 				*accents = 0;
1066 				action |= BKEY;
1067 				break;
1068 			case LSH:
1069 				state |= SHIFTS1;
1070 				break;
1071 			case RSH:
1072 				state |= SHIFTS2;
1073 				break;
1074 			case LCTR:
1075 				state |= CTLS1;
1076 				break;
1077 			case RCTR:
1078 				state |= CTLS2;
1079 				break;
1080 			case LALT:
1081 				state |= ALTS1;
1082 				break;
1083 			case RALT:
1084 				state |= ALTS2;
1085 				break;
1086 			case ASH:
1087 				state |= AGRS1;
1088 				break;
1089 			case META:
1090 				state |= METAS1;
1091 				break;
1092 			default:
1093 				/* is this an accent (dead) key? */
1094 				if (action >= F_ACC && action <= L_ACC) {
1095 					action = save_accent_key(kbd, action,
1096 								 accents);
1097 					switch (action) {
1098 					case NOKEY:
1099 					case ERRKEY:
1100 						return action;
1101 					default:
1102 						if (state & METAS)
1103 							return (action | MKEY);
1104 						else
1105 							return action;
1106 					}
1107 					/* NOT REACHED */
1108 				}
1109 				/* other special keys */
1110 				if (*accents > 0) {
1111 					*accents = 0;
1112 					return ERRKEY;
1113 				}
1114 				if (action >= F_FN && action <= L_FN)
1115 					action |= FKEY;
1116 				/* XXX: return fkey string for the FKEY? */
1117 			}
1118 			*shiftstate = state;
1119 			return (SPCLKEY | action);
1120 		} else {
1121 			/* regular keys */
1122 			if (*accents > 0) {
1123 				/* make an accented char */
1124 				action = make_accent_char(kbd, action, accents);
1125 				if (action == ERRKEY)
1126 					return action;
1127 			}
1128 			if (state & METAS)
1129 				action |= MKEY;
1130 			return action;
1131 		}
1132 	}
1133 	/* NOT REACHED */
1134 }
1135