xref: /freebsd/sys/dev/kbd/kbd.c (revision a1a4f1a0d87b594d3f17a97dc0127eec1417e6f6)
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 	/* stop */	nostop,
397 	/* reset */	noreset,
398 	/* devtotty */	nodevtotty,
399 	/* poll */	genkbdpoll,
400 	/* mmap */	nommap,
401 	/* strategy */	nostrategy,
402 	/* name */	"kbd",
403 	/* parms */	noparms,
404 	/* maj */	CDEV_MAJOR,
405 	/* dump */	nodump,
406 	/* psize */	nopsize,
407 	/* flags */	0,
408 	/* maxio */	0,
409 	/* bmaj */	-1
410 };
411 
412 int
413 kbd_attach(keyboard_t *kbd)
414 {
415 	dev_t dev;
416 
417 	if (kbd->kb_index >= keyboards)
418 		return EINVAL;
419 	if (keyboard[kbd->kb_index] != kbd)
420 		return EINVAL;
421 
422 	dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
423 		       "kbd%r", kbd->kb_index);
424 	if (dev->si_drv1 == NULL)
425 		dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
426 				      M_WAITOK);
427 	bzero(dev->si_drv1, sizeof(genkbd_softc_t));
428 
429 	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
430 	return 0;
431 }
432 
433 int
434 kbd_detach(keyboard_t *kbd)
435 {
436 	if (kbd->kb_index >= keyboards)
437 		return EINVAL;
438 	if (keyboard[kbd->kb_index] != kbd)
439 		return EINVAL;
440 
441 	/* XXX: unmake_dev() ? */
442 	return 0;
443 }
444 
445 /*
446  * Generic keyboard cdev driver functions
447  * Keyboard subdrivers may call these functions to implement common
448  * driver functions.
449  */
450 
451 #define KB_QSIZE	512
452 #define KB_BUFSIZE	64
453 
454 static kbd_callback_func_t genkbd_event;
455 
456 static int
457 genkbdopen(dev_t dev, int mode, int flag, struct proc *p)
458 {
459 	keyboard_t *kbd;
460 	genkbd_softc_t *sc;
461 	int s;
462 	int i;
463 
464 	s = spltty();
465 	sc = dev->si_drv1;
466 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
467 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
468 		splx(s);
469 		return ENXIO;
470 	}
471 	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
472 			 genkbd_event, (void *)sc);
473 	if (i < 0) {
474 		splx(s);
475 		return EBUSY;
476 	}
477 	/* assert(i == kbd->kb_index) */
478 	/* assert(kbd == kbd_get_keyboard(i)) */
479 
480 	/*
481 	 * NOTE: even when we have successfully claimed a keyboard,
482 	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
483 	 */
484 
485 #if 0
486 	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
487 #endif
488 	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
489 	sc->gkb_rsel.si_flags = 0;
490 	sc->gkb_rsel.si_pid = 0;
491 	splx(s);
492 
493 	return 0;
494 }
495 
496 static int
497 genkbdclose(dev_t dev, int mode, int flag, struct proc *p)
498 {
499 	keyboard_t *kbd;
500 	genkbd_softc_t *sc;
501 	int s;
502 
503 	/*
504 	 * NOTE: the device may have already become invalid.
505 	 * kbd == NULL || !KBD_IS_VALID(kbd)
506 	 */
507 	s = spltty();
508 	sc = dev->si_drv1;
509 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
510 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
511 		/* XXX: we shall be forgiving and don't report error... */
512 	} else {
513 		kbd_release(kbd, (void *)sc);
514 #if 0
515 		clist_free_cblocks(&sc->gkb_q);
516 #endif
517 	}
518 	splx(s);
519 	return 0;
520 }
521 
522 static int
523 genkbdread(dev_t dev, struct uio *uio, int flag)
524 {
525 	keyboard_t *kbd;
526 	genkbd_softc_t *sc;
527 	u_char buffer[KB_BUFSIZE];
528 	int len;
529 	int error;
530 	int s;
531 
532 	/* wait for input */
533 	s = spltty();
534 	sc = dev->si_drv1;
535 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
536 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
537 		splx(s);
538 		return ENXIO;
539 	}
540 	while (sc->gkb_q.c_cc == 0) {
541 		if (flag & IO_NDELAY) {
542 			splx(s);
543 			return EWOULDBLOCK;
544 		}
545 		sc->gkb_flags |= KB_ASLEEP;
546 		error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
547 		kbd = kbd_get_keyboard(KBD_INDEX(dev));
548 		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
549 			splx(s);
550 			return ENXIO;	/* our keyboard has gone... */
551 		}
552 		if (error) {
553 			sc->gkb_flags &= ~KB_ASLEEP;
554 			splx(s);
555 			return error;
556 		}
557 	}
558 	splx(s);
559 
560 	/* copy as much input as possible */
561 	error = 0;
562 	while (uio->uio_resid > 0) {
563 		len = imin(uio->uio_resid, sizeof(buffer));
564 		len = q_to_b(&sc->gkb_q, buffer, len);
565 		if (len <= 0)
566 			break;
567 		error = uiomove(buffer, len, uio);
568 		if (error)
569 			break;
570 	}
571 
572 	return error;
573 }
574 
575 static int
576 genkbdwrite(dev_t dev, struct uio *uio, int flag)
577 {
578 	keyboard_t *kbd;
579 
580 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
581 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
582 		return ENXIO;
583 	return ENODEV;
584 }
585 
586 static int
587 genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
588 {
589 	keyboard_t *kbd;
590 	int error;
591 
592 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
593 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
594 		return ENXIO;
595 	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
596 	if (error == ENOIOCTL)
597 		error = ENODEV;
598 	return error;
599 }
600 
601 static int
602 genkbdpoll(dev_t dev, int events, struct proc *p)
603 {
604 	keyboard_t *kbd;
605 	genkbd_softc_t *sc;
606 	int revents;
607 	int s;
608 
609 	revents = 0;
610 	s = spltty();
611 	sc = dev->si_drv1;
612 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
613 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
614 		revents =  POLLHUP;	/* the keyboard has gone */
615 	} else if (events & (POLLIN | POLLRDNORM)) {
616 		if (sc->gkb_q.c_cc > 0)
617 			revents = events & (POLLIN | POLLRDNORM);
618 		else
619 			selrecord(p, &sc->gkb_rsel);
620 	}
621 	splx(s);
622 	return revents;
623 }
624 
625 static int
626 genkbd_event(keyboard_t *kbd, int event, void *arg)
627 {
628 	genkbd_softc_t *sc;
629 	size_t len;
630 	u_char *cp;
631 	int mode;
632 	int c;
633 
634 	/* assert(KBD_IS_VALID(kbd)) */
635 	sc = (genkbd_softc_t *)arg;
636 
637 	switch (event) {
638 	case KBDIO_KEYINPUT:
639 		break;
640 	case KBDIO_UNLOADING:
641 		/* the keyboard is going... */
642 		kbd_release(kbd, (void *)sc);
643 		if (sc->gkb_flags & KB_ASLEEP) {
644 			sc->gkb_flags &= ~KB_ASLEEP;
645 			wakeup((caddr_t)sc);
646 		}
647 		selwakeup(&sc->gkb_rsel);
648 		return 0;
649 	default:
650 		return EINVAL;
651 	}
652 
653 	/* obtain the current key input mode */
654 	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
655 		mode = K_XLATE;
656 
657 	/* read all pending input */
658 	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
659 		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
660 		if (c == NOKEY)
661 			continue;
662 		if (c == ERRKEY)	/* XXX: ring bell? */
663 			continue;
664 		if (!KBD_IS_BUSY(kbd))
665 			/* the device is not open, discard the input */
666 			continue;
667 
668 		/* store the byte as is for K_RAW and K_CODE modes */
669 		if (mode != K_XLATE) {
670 			putc(KEYCHAR(c), &sc->gkb_q);
671 			continue;
672 		}
673 
674 		/* K_XLATE */
675 		if (c & RELKEY)	/* key release is ignored */
676 			continue;
677 
678 		/* process special keys; most of them are just ignored... */
679 		if (c & SPCLKEY) {
680 			switch (KEYCHAR(c)) {
681 			/* locking keys */
682 			case NLK:  case CLK:  case SLK:  case ALK:
683 			/* shift keys */
684 			case LSH:  case RSH:  case LCTR: case RCTR:
685 			case LALT: case RALT: case ASH:  case META:
686 			/* other special keys */
687 			case NOP:  case SPSC: case RBT:  case SUSP:
688 			case STBY: case DBG:  case NEXT:
689 				/* ignore them... */
690 				continue;
691 			case BTAB:	/* a backtab: ESC [ Z */
692 				putc(0x1b, &sc->gkb_q);
693 				putc('[', &sc->gkb_q);
694 				putc('Z', &sc->gkb_q);
695 				continue;
696 			}
697 		}
698 
699 		/* normal chars, normal chars with the META, function keys */
700 		switch (KEYFLAGS(c)) {
701 		case 0:			/* a normal char */
702 			putc(KEYCHAR(c), &sc->gkb_q);
703 			break;
704 		case MKEY:		/* the META flag: prepend ESC */
705 			putc(0x1b, &sc->gkb_q);
706 			putc(KEYCHAR(c), &sc->gkb_q);
707 			break;
708 		case FKEY | SPCLKEY:	/* a function key, return string */
709 			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
710 							KEYCHAR(c), &len);
711 			if (cp != NULL) {
712 				while (len-- >  0)
713 					putc(*cp++, &sc->gkb_q);
714 			}
715 			break;
716 		}
717 	}
718 
719 	/* wake up sleeping/polling processes */
720 	if (sc->gkb_q.c_cc > 0) {
721 		if (sc->gkb_flags & KB_ASLEEP) {
722 			sc->gkb_flags &= ~KB_ASLEEP;
723 			wakeup((caddr_t)sc);
724 		}
725 		selwakeup(&sc->gkb_rsel);
726 	}
727 
728 	return 0;
729 }
730 
731 #endif /* KBD_INSTALL_CDEV */
732 
733 /*
734  * Generic low-level keyboard functions
735  * The low-level functions in the keyboard subdriver may use these
736  * functions.
737  */
738 
739 int
740 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
741 {
742 	keyarg_t *keyp;
743 	fkeyarg_t *fkeyp;
744 	int s;
745 	int i;
746 
747 	s = spltty();
748 	switch (cmd) {
749 
750 	case KDGKBINFO:		/* get keyboard information */
751 		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
752 		i = imin(strlen(kbd->kb_name) + 1,
753 			 sizeof(((keyboard_info_t *)arg)->kb_name));
754 		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
755 		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
756 		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
757 		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
758 		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
759 		break;
760 
761 	case KDGKBTYPE:		/* get keyboard type */
762 		*(int *)arg = kbd->kb_type;
763 		break;
764 
765 	case GIO_KEYMAP:	/* get keyboard translation table */
766 		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
767 		break;
768 	case PIO_KEYMAP:	/* set keyboard translation table */
769 #ifndef KBD_DISABLE_KEYMAP_LOAD
770 		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
771 		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
772 		break;
773 #else
774 		splx(s);
775 		return ENODEV;
776 #endif
777 
778 	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
779 		keyp = (keyarg_t *)arg;
780 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
781 					/sizeof(kbd->kb_keymap->key[0])) {
782 			splx(s);
783 			return EINVAL;
784 		}
785 		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
786 		      sizeof(keyp->key));
787 		break;
788 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
789 #ifndef KBD_DISABLE_KEYMAP_LOAD
790 		keyp = (keyarg_t *)arg;
791 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
792 					/sizeof(kbd->kb_keymap->key[0])) {
793 			splx(s);
794 			return EINVAL;
795 		}
796 		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
797 		      sizeof(keyp->key));
798 		break;
799 #else
800 		splx(s);
801 		return ENODEV;
802 #endif
803 
804 	case GIO_DEADKEYMAP:	/* get accent key translation table */
805 		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
806 		break;
807 	case PIO_DEADKEYMAP:	/* set accent key translation table */
808 #ifndef KBD_DISABLE_KEYMAP_LOAD
809 		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
810 		break;
811 #else
812 		splx(s);
813 		return ENODEV;
814 #endif
815 
816 	case GETFKEY:		/* get functionkey string */
817 		fkeyp = (fkeyarg_t *)arg;
818 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
819 			splx(s);
820 			return EINVAL;
821 		}
822 		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
823 		      kbd->kb_fkeytab[fkeyp->keynum].len);
824 		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
825 		break;
826 	case SETFKEY:		/* set functionkey string */
827 #ifndef KBD_DISABLE_KEYMAP_LOAD
828 		fkeyp = (fkeyarg_t *)arg;
829 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
830 			splx(s);
831 			return EINVAL;
832 		}
833 		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
834 		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
835 		      kbd->kb_fkeytab[fkeyp->keynum].len);
836 		break;
837 #else
838 		splx(s);
839 		return ENODEV;
840 #endif
841 
842 	default:
843 		splx(s);
844 		return ENOIOCTL;
845 	}
846 
847 	splx(s);
848 	return 0;
849 }
850 
851 /* get a pointer to the string associated with the given function key */
852 u_char
853 *genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
854 {
855 	if (kbd == NULL)
856 		return NULL;
857 	fkey -= F_FN;
858 	if (fkey > kbd->kb_fkeytab_size)
859 		return NULL;
860 	*len = kbd->kb_fkeytab[fkey].len;
861 	return kbd->kb_fkeytab[fkey].str;
862 }
863 
864 /* diagnostic dump */
865 static char
866 *get_kbd_type_name(int type)
867 {
868 	static struct {
869 		int type;
870 		char *name;
871 	} name_table[] = {
872 		{ KB_84,	"AT 84" },
873 		{ KB_101,	"AT 101/102" },
874 		{ KB_OTHER,	"generic" },
875 	};
876 	int i;
877 
878 	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
879 		if (type == name_table[i].type)
880 			return name_table[i].name;
881 	}
882 	return "unknown";
883 }
884 
885 void
886 genkbd_diag(keyboard_t *kbd, int level)
887 {
888 	if (level > 0) {
889 		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x",
890 		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
891 		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
892 		       kbd->kb_config, kbd->kb_flags);
893 		if (kbd->kb_io_base > 0)
894 			printf(", port:0x%x-0x%x", kbd->kb_io_base,
895 			       kbd->kb_io_base + kbd->kb_io_size - 1);
896 		printf("\n");
897 	}
898 }
899 
900 #define set_lockkey_state(k, s, l)				\
901 	if (!((s) & l ## DOWN)) {				\
902 		int i;						\
903 		(s) |= l ## DOWN;				\
904 		(s) ^= l ## ED;					\
905 		i = (s) & LOCK_MASK;				\
906 		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
907 	}
908 
909 static u_int
910 save_accent_key(keyboard_t *kbd, u_int key, int *accents)
911 {
912 	int i;
913 
914 	/* make an index into the accent map */
915 	i = key - F_ACC + 1;
916 	if ((i > kbd->kb_accentmap->n_accs)
917 	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
918 		/* the index is out of range or pointing to an empty entry */
919 		*accents = 0;
920 		return ERRKEY;
921 	}
922 
923 	/*
924 	 * If the same accent key has been hit twice, produce the accent char
925 	 * itself.
926 	 */
927 	if (i == *accents) {
928 		key = kbd->kb_accentmap->acc[i - 1].accchar;
929 		*accents = 0;
930 		return key;
931 	}
932 
933 	/* remember the index and wait for the next key  */
934 	*accents = i;
935 	return NOKEY;
936 }
937 
938 static u_int
939 make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
940 {
941 	struct acc_t *acc;
942 	int i;
943 
944 	acc = &kbd->kb_accentmap->acc[*accents - 1];
945 	*accents = 0;
946 
947 	/*
948 	 * If the accent key is followed by the space key,
949 	 * produce the accent char itself.
950 	 */
951 	if (ch == ' ')
952 		return acc->accchar;
953 
954 	/* scan the accent map */
955 	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
956 		if (acc->map[i][0] == 0)	/* end of table */
957 			break;
958 		if (acc->map[i][0] == ch)
959 			return acc->map[i][1];
960 	}
961 	/* this char cannot be accented... */
962 	return ERRKEY;
963 }
964 
965 int
966 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
967 		 int *accents)
968 {
969 	struct keyent_t *key;
970 	int state = *shiftstate;
971 	int action;
972 	int f;
973 	int i;
974 
975 	f = state & (AGRS | ALKED);
976 	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
977 		keycode += ALTGR_OFFSET;
978 	key = &kbd->kb_keymap->key[keycode];
979 	i = ((state & SHIFTS) ? 1 : 0)
980 	    | ((state & CTLS) ? 2 : 0)
981 	    | ((state & ALTS) ? 4 : 0);
982 	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
983 		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
984 		i ^= 1;
985 
986 	action = key->map[i];
987 	if (up) {	/* break: key released */
988 		if (key->spcl & (0x80 >> i)) {
989 			/* special keys */
990 			switch (action) {
991 			case LSH:
992 				state &= ~SHIFTS1;
993 				break;
994 			case RSH:
995 				state &= ~SHIFTS2;
996 				break;
997 			case LCTR:
998 				state &= ~CTLS1;
999 				break;
1000 			case RCTR:
1001 				state &= ~CTLS2;
1002 				break;
1003 			case LALT:
1004 				state &= ~ALTS1;
1005 				break;
1006 			case RALT:
1007 				state &= ~ALTS2;
1008 				break;
1009 			case ASH:
1010 				state &= ~AGRS1;
1011 				break;
1012 			case META:
1013 				state &= ~METAS1;
1014 				break;
1015 			case NLK:
1016 				state &= ~NLKDOWN;
1017 				break;
1018 			case CLK:
1019 #ifndef PC98
1020 				state &= ~CLKDOWN;
1021 #else
1022 				state &= ~CLKED;
1023 				i = state & LOCK_MASK;
1024 				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1025 							       (caddr_t)&i);
1026 #endif
1027 				break;
1028 			case SLK:
1029 				state &= ~SLKDOWN;
1030 				break;
1031 			case ALK:
1032 				state &= ~ALKDOWN;
1033 				break;
1034 			}
1035 			*shiftstate = state;
1036 			return (SPCLKEY | RELKEY | action);
1037 		}
1038 		/* release events of regular keys are not reported */
1039 		return NOKEY;
1040 	} else {	/* make: key pressed */
1041 		if (key->spcl & (0x80 >> i)) {
1042 			/* special keys */
1043 			switch (action) {
1044 			/* LOCKING KEYS */
1045 			case NLK:
1046 				set_lockkey_state(kbd, state, NLK);
1047 				break;
1048 			case CLK:
1049 #ifndef PC98
1050 				set_lockkey_state(kbd, state, CLK);
1051 #else
1052 				state |= CLKED;
1053 				i = state & LOCK_MASK;
1054 				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
1055 							       (caddr_t)&i);
1056 #endif
1057 				break;
1058 			case SLK:
1059 				set_lockkey_state(kbd, state, SLK);
1060 				break;
1061 			case ALK:
1062 				set_lockkey_state(kbd, state, ALK);
1063 				break;
1064 			/* NON-LOCKING KEYS */
1065 			case SPSC: case RBT:  case SUSP: case STBY:
1066 			case DBG:  case NEXT:
1067 				*accents = 0;
1068 				break;
1069 			case BTAB:
1070 				*accents = 0;
1071 				action |= BKEY;
1072 				break;
1073 			case LSH:
1074 				state |= SHIFTS1;
1075 				break;
1076 			case RSH:
1077 				state |= SHIFTS2;
1078 				break;
1079 			case LCTR:
1080 				state |= CTLS1;
1081 				break;
1082 			case RCTR:
1083 				state |= CTLS2;
1084 				break;
1085 			case LALT:
1086 				state |= ALTS1;
1087 				break;
1088 			case RALT:
1089 				state |= ALTS2;
1090 				break;
1091 			case ASH:
1092 				state |= AGRS1;
1093 				break;
1094 			case META:
1095 				state |= METAS1;
1096 				break;
1097 			default:
1098 				/* is this an accent (dead) key? */
1099 				if (action >= F_ACC && action <= L_ACC) {
1100 					action = save_accent_key(kbd, action,
1101 								 accents);
1102 					switch (action) {
1103 					case NOKEY:
1104 					case ERRKEY:
1105 						return action;
1106 					default:
1107 						if (state & METAS)
1108 							return (action | MKEY);
1109 						else
1110 							return action;
1111 					}
1112 					/* NOT REACHED */
1113 				}
1114 				/* other special keys */
1115 				if (*accents > 0) {
1116 					*accents = 0;
1117 					return ERRKEY;
1118 				}
1119 				if (action >= F_FN && action <= L_FN)
1120 					action |= FKEY;
1121 				/* XXX: return fkey string for the FKEY? */
1122 			}
1123 			*shiftstate = state;
1124 			return (SPCLKEY | action);
1125 		} else {
1126 			/* regular keys */
1127 			if (*accents > 0) {
1128 				/* make an accented char */
1129 				action = make_accent_char(kbd, action, accents);
1130 				if (action == ERRKEY)
1131 					return action;
1132 			}
1133 			if (state & METAS)
1134 				action |= MKEY;
1135 			return action;
1136 		}
1137 	}
1138 	/* NOT REACHED */
1139 }
1140