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