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