xref: /csrg-svn/sys/sparc/dev/kbd.c (revision 55499)
155105Storek /*
255105Storek  * Copyright (c) 1992 The Regents of the University of California.
355105Storek  * All rights reserved.
455105Storek  *
555105Storek  * This software was developed by the Computer Systems Engineering group
655105Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755105Storek  * contributed to Berkeley.
855105Storek  *
9*55499Sbostic  * All advertising materials mentioning features or use of this software
10*55499Sbostic  * must display the following acknowledgement:
11*55499Sbostic  *	This product includes software developed by the University of
12*55499Sbostic  *	California, Lawrence Berkeley Laboratories.
13*55499Sbostic  *
1455105Storek  * %sccs.include.redist.c%
1555105Storek  *
16*55499Sbostic  *	@(#)kbd.c	7.2 (Berkeley) 07/21/92
1755105Storek  *
1855105Storek  * from: $Header: kbd.c,v 1.15 92/07/09 07:59:27 torek Exp $ (LBL)
1955105Storek  */
2055105Storek 
2155105Storek /*
2255105Storek  * Keyboard driver (/dev/kbd -- note that we do not have minor numbers
2355105Storek  * [yet?]).  Translates incoming bytes to ASCII or to `firm_events' and
2455105Storek  * passes them up to the appropriate reader.
2555105Storek  */
2655105Storek 
2755105Storek #include "sys/param.h"
2855105Storek #include "sys/conf.h"
2955105Storek #include "sys/device.h"
3055105Storek #include "sys/ioctl.h"
3155105Storek #include "sys/kernel.h"
3255105Storek #include "sys/proc.h"
3355105Storek #include "sys/syslog.h"
3455105Storek #include "sys/systm.h"
3555105Storek #include "sys/tty.h"
3655105Storek 
3755105Storek #include "machine/autoconf.h"
3855105Storek 
3955105Storek #include "vuid_event.h"
4055105Storek #include "event_var.h"
4155105Storek #include "kbd.h"
4255105Storek #include "kbio.h"
4355105Storek 
4455105Storek /*
4555105Storek  * Sun keyboard definitions (from Sprite).
4655105Storek  * These apply to type 2, 3 and 4 keyboards.
4755105Storek  */
4855105Storek #define	KEY_CODE(c)	((c) & KBD_KEYMASK)	/* keyboard code index */
4955105Storek #define	KEY_UP(c)	((c) & KBD_UP)		/* true => key went up */
5055105Storek 
5155105Storek /*
5255105Storek  * Each KEY_CODE(x) can be translated via the tables below.
5355105Storek  * The result is either a valid ASCII value in [0..0x7f] or is one
5455105Storek  * of the following `magic' values saying something interesting
5555105Storek  * happened.  If LSHIFT or RSHIFT has changed state the next
5655105Storek  * lookup should come from the appropriate table; if ALLUP is
5755105Storek  * sent all keys (including both shifts and the control key) are
5855105Storek  * now up, and the next byte is the keyboard ID code.
5955105Storek  *
6055105Storek  * These tables ignore all function keys (on the theory that if you
6155105Storek  * want these keys, you should use a window system).  Note that
6255105Storek  * `caps lock' is just mapped as `ignore' (so there!). (Only the
6355105Storek  * type 3 and 4 keyboards have a caps lock key anyway.)
6455105Storek  */
6555105Storek #define	KEY_MAGIC	0x80		/* flag => magic value */
6655105Storek #define	KEY_IGNORE	0x80
6755105Storek #define	KEY_L1		KEY_IGNORE
6855105Storek #define	KEY_CAPSLOCK	KEY_IGNORE
6955105Storek #define	KEY_LSHIFT	0x81
7055105Storek #define	KEY_RSHIFT	0x82
7155105Storek #define	KEY_CONTROL	0x83
7255105Storek #define	KEY_ALLUP	0x84		/* all keys are now up; also reset */
7355105Storek 
7455105Storek /*
7555105Storek  * Decode tables for type 2, 3, and 4 keyboards
7655105Storek  * (stolen from Sprite; see also kbd.h).
7755105Storek  */
7855105Storek static const u_char kbd_unshifted[] = {
7955105Storek /*   0 */	KEY_IGNORE,	KEY_L1,		KEY_IGNORE,	KEY_IGNORE,
8055105Storek /*   4 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8155105Storek /*   8 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8255105Storek /*  12 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8355105Storek /*  16 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8455105Storek /*  20 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8555105Storek /*  24 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
8655105Storek /*  28 */	KEY_IGNORE,	'\033',		'1',		'2',
8755105Storek /*  32 */	'3',		'4',		'5',		'6',
8855105Storek /*  36 */	'7',		'8',		'9',		'0',
8955105Storek /*  40 */	'-',		'=',		'`',		'\b',
9055105Storek /*  44 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
9155105Storek /*  48 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
9255105Storek /*  52 */	KEY_IGNORE,	'\t',		'q',		'w',
9355105Storek /*  56 */	'e',		'r',		't',		'y',
9455105Storek /*  60 */	'u',		'i',		'o',		'p',
9555105Storek /*  64 */	'[',		']',		'\177',		KEY_IGNORE,
9655105Storek /*  68 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
9755105Storek /*  72 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
9855105Storek /*  76 */	KEY_CONTROL,	'a',		's',		'd',
9955105Storek /*  80 */	'f',		'g',		'h',		'j',
10055105Storek /*  84 */	'k',		'l',		';',		'\'',
10155105Storek /*  88 */	'\\',		'\r',		KEY_IGNORE,	KEY_IGNORE,
10255105Storek /*  92 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
10355105Storek /*  96 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_LSHIFT,
10455105Storek /* 100 */	'z',		'x',		'c',		'v',
10555105Storek /* 104 */	'b',		'n',		'm',		',',
10655105Storek /* 108 */	'.',		'/',		KEY_RSHIFT,	'\n',
10755105Storek /* 112 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
10855105Storek /* 116 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_CAPSLOCK,
10955105Storek /* 120 */	KEY_IGNORE,	' ',		KEY_IGNORE,	KEY_IGNORE,
11055105Storek /* 124 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_ALLUP,
11155105Storek };
11255105Storek 
11355105Storek static const u_char kbd_shifted[] = {
11455105Storek /*   0 */	KEY_IGNORE,	KEY_L1,		KEY_IGNORE,	KEY_IGNORE,
11555105Storek /*   4 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
11655105Storek /*   8 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
11755105Storek /*  12 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
11855105Storek /*  16 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
11955105Storek /*  20 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
12055105Storek /*  24 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
12155105Storek /*  28 */	KEY_IGNORE,	'\033',		'!',		'@',
12255105Storek /*  32 */	'#',		'$',		'%',		'^',
12355105Storek /*  36 */	'&',		'*',		'(',		')',
12455105Storek /*  40 */	'_',		'+',		'~',		'\b',
12555105Storek /*  44 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
12655105Storek /*  48 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
12755105Storek /*  52 */	KEY_IGNORE,	'\t',		'Q',		'W',
12855105Storek /*  56 */	'E',		'R',		'T',		'Y',
12955105Storek /*  60 */	'U',		'I',		'O',		'P',
13055105Storek /*  64 */	'{',		'}',		'\177',		KEY_IGNORE,
13155105Storek /*  68 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
13255105Storek /*  72 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
13355105Storek /*  76 */	KEY_CONTROL,	'A',		'S',		'D',
13455105Storek /*  80 */	'F',		'G',		'H',		'J',
13555105Storek /*  84 */	'K',		'L',		':',		'"',
13655105Storek /*  88 */	'|',		'\r',		KEY_IGNORE,	KEY_IGNORE,
13755105Storek /*  92 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
13855105Storek /*  96 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_LSHIFT,
13955105Storek /* 100 */	'Z',		'X',		'C',		'V',
14055105Storek /* 104 */	'B',		'N',		'M',		'<',
14155105Storek /* 108 */	'>',		'?',		KEY_RSHIFT,	'\n',
14255105Storek /* 112 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,
14355105Storek /* 116 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_CAPSLOCK,
14455105Storek /* 120 */	KEY_IGNORE,	' ',		KEY_IGNORE,	KEY_IGNORE,
14555105Storek /* 124 */	KEY_IGNORE,	KEY_IGNORE,	KEY_IGNORE,	KEY_ALLUP,
14655105Storek };
14755105Storek 
14855105Storek /*
14955105Storek  * We need to remember the state of the keyboard's shift and control
15055105Storek  * keys, and we need a per-type translation table.
15155105Storek  */
15255105Storek struct kbd_state {
15355105Storek 	const u_char *kbd_unshifted;	/* unshifted keys */
15455105Storek 	const u_char *kbd_shifted;	/* shifted keys */
15555105Storek 	const u_char *kbd_cur;	/* current keys (either of the preceding) */
15655105Storek 	union {
15755105Storek 		char	c[2];	/* left and right shift keys */
15855105Storek 		short	s;	/* true => either shift key */
15955105Storek 	} kbd_shift;
16055105Storek #define	kbd_lshift	kbd_shift.c[0]
16155105Storek #define	kbd_rshift	kbd_shift.c[1]
16255105Storek #define	kbd_anyshift	kbd_shift.s
16355105Storek 	char	kbd_control;	/* true => ctrl down */
16455105Storek 	char	kbd_click;	/* true => keyclick enabled */
16555105Storek 	char	kbd_takeid;	/* take next byte as ID */
16655105Storek 	u_char	kbd_id;		/* a place to store the ID */
16755105Storek };
16855105Storek 
16955105Storek /*
17055105Storek  * Keyboard driver state.  The ascii and kbd links go up and down and
17155105Storek  * we just sit in the middle doing translation.  Note that it is possible
17255105Storek  * to get just one of the two links, in which case /dev/kbd is unavailable.
17355105Storek  * The downlink supplies us with `internal' open and close routines which
17455105Storek  * will enable dataflow across the downlink.  We promise to call open when
17555105Storek  * we are willing to take keystrokes, and to call close when we are not.
17655105Storek  * If /dev/kbd is not the console tty input source, we do this whenever
17755105Storek  * /dev/kbd is in use; otherwise we just leave it open forever.
17855105Storek  */
17955105Storek struct kbd_softc {
18055105Storek 	struct	tty *k_cons;		/* uplink for ASCII data to console */
18155105Storek 	struct	tty *k_kbd;		/* downlink for output to keyboard */
18255105Storek 	void	(*k_open) __P((struct tty *));	/* enable dataflow */
18355105Storek 	void	(*k_close) __P((struct tty *));	/* disable dataflow */
18455105Storek 	int	k_evmode;		/* set if we should produce events */
18555105Storek 	struct	kbd_state k_state;	/* ASCII decode state */
18655105Storek 	struct	evvar k_events;		/* event queue state */
18755105Storek } kbd_softc;
18855105Storek 
18955105Storek /* Prototypes */
19055105Storek void	kbd_ascii(struct tty *);
19155105Storek void	kbd_serial(struct tty *, void (*)(), void (*)());
19255105Storek static	void kbd_getid(void *);
19355105Storek void	kbd_reset(struct kbd_state *);
19455105Storek static	int kbd_translate(int, struct kbd_state *);
19555105Storek void	kbd_rint(int);
19655105Storek int	kbdopen(dev_t, int, int, struct proc *);
19755105Storek int	kbdclose(dev_t, int, int, struct proc *);
19855105Storek int	kbdread(dev_t, struct uio *, int);
19955105Storek int	kbdwrite(dev_t, struct uio *, int);
20055105Storek int	kbdioctl(dev_t, int, caddr_t, int, struct proc *);
20155105Storek int	kbdselect(dev_t, int, struct proc *);
20255105Storek int	kbd_docmd(int, int);
20355105Storek 
20455105Storek /*
20555105Storek  * Attach the console keyboard ASCII (up-link) interface.
20655105Storek  * This happens before kbd_serial.
20755105Storek  */
20855105Storek void
20955105Storek kbd_ascii(struct tty *tp)
21055105Storek {
21155105Storek 
21255105Storek 	kbd_softc.k_cons = tp;
21355105Storek }
21455105Storek 
21555105Storek /*
21655105Storek  * Attach the console keyboard serial (down-link) interface.
21755105Storek  * We pick up the initial keyboard clock state here as well.
21855105Storek  */
21955105Storek void
22055105Storek kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)())
22155105Storek {
22255105Storek 	register struct kbd_softc *k;
22355105Storek 	register char *cp;
22455105Storek 
22555105Storek 	k = &kbd_softc;
22655105Storek 	k->k_kbd = tp;
22755105Storek 	k->k_open = iopen;
22855105Storek 	k->k_close = iclose;
22955105Storek 
23055105Storek 	cp = getpropstring(optionsnode, "keyboard-click?");
23155105Storek 	if (cp && strcmp(cp, "true") == 0)
23255105Storek 		k->k_state.kbd_click = 1;
23355105Storek 
23455105Storek 	if (k->k_cons) {
23555105Storek 		/*
23655105Storek 		 * We supply keys for /dev/console.  Before we can
23755105Storek 		 * do so, we have to ``open'' the line.  We also need
23855105Storek 		 * the type, got by sending a RESET down the line ...
23955105Storek 		 * but clists are not yet set up, so we use a timeout
24055105Storek 		 * to try constantly until we can get the ID.  (gag)
24155105Storek 		 */
24255105Storek 		(*iopen)(tp);		/* never to be closed */
24355105Storek 		kbd_getid(NULL);
24455105Storek 	}
24555105Storek }
24655105Storek 
24755105Storek /*
24855105Storek  * Initial keyboard reset, to obtain ID and thus a translation table.
24955105Storek  * We have to try again and again until the tty subsystem works.
25055105Storek  */
25155105Storek static void
25255105Storek kbd_getid(void *arg)
25355105Storek {
25455105Storek 	register struct kbd_softc *k;
25555105Storek 	register struct tty *tp;
25655105Storek 	register int retry;
25755105Storek 	extern int cold;		/* XXX */
25855105Storek 
25955105Storek 	k = &kbd_softc;
26055105Storek 	if (k->k_state.kbd_cur != NULL)
26155105Storek 		return;
26255105Storek 	tp = k->k_kbd;
26355105Storek 	if (cold || ttyoutput(KBD_CMD_RESET, tp) >= 0)
26455105Storek 		retry = 1;
26555105Storek 	else {
26655105Storek 		(*tp->t_oproc)(tp);
26755105Storek 		retry = 2 * hz;
26855105Storek 	}
26955105Storek 	timeout(kbd_getid, NULL, retry);
27055105Storek }
27155105Storek 
27255105Storek void
27355105Storek kbd_reset(register struct kbd_state *ks)
27455105Storek {
27555105Storek 	/*
27655105Storek 	 * On first identification, wake up anyone waiting for type
27755105Storek 	 * and set up the table pointers.
27855105Storek 	 */
27955105Storek 	if (ks->kbd_unshifted == NULL) {
28055105Storek 		wakeup((caddr_t)ks);
28155105Storek 		ks->kbd_unshifted = kbd_unshifted;
28255105Storek 		ks->kbd_shifted = kbd_shifted;
28355105Storek 		ks->kbd_cur = ks->kbd_unshifted;
28455105Storek 	}
28555105Storek 
28655105Storek 	/* Restore keyclick, if necessary */
28755105Storek 	switch (ks->kbd_id) {
28855105Storek 
28955105Storek 	case KB_SUN2:
29055105Storek 		/* Type 2 keyboards don't support keyclick */
29155105Storek 		break;
29255105Storek 
29355105Storek 	case KB_SUN3:
29455105Storek 		/* Type 3 keyboards come up with keyclick on */
29555105Storek 		if (!ks->kbd_click)
29655105Storek 			(void) kbd_docmd(KBD_CMD_NOCLICK, 0);
29755105Storek 		break;
29855105Storek 
29955105Storek 	case KB_SUN4:
30055105Storek 		/* Type 4 keyboards come up with keyclick off */
30155105Storek 		if (ks->kbd_click)
30255105Storek 			(void) kbd_docmd(KBD_CMD_CLICK, 0);
30355105Storek 		break;
30455105Storek 	}
30555105Storek }
30655105Storek 
30755105Storek /*
30855105Storek  * Turn keyboard up/down codes into ASCII.
30955105Storek  */
31055105Storek static int
31155105Storek kbd_translate(register int c, register struct kbd_state *ks)
31255105Storek {
31355105Storek 	register int down;
31455105Storek 
31555105Storek 	if (ks->kbd_cur == NULL) {
31655105Storek 		/*
31755105Storek 		 * Do not know how to translate yet.
31855105Storek 		 * We will find out when a RESET comes along.
31955105Storek 		 */
32055105Storek 		return (-1);
32155105Storek 	}
32255105Storek 	down = !KEY_UP(c);
32355105Storek 	c = ks->kbd_cur[KEY_CODE(c)];
32455105Storek 	if (c & KEY_MAGIC) {
32555105Storek 		switch (c) {
32655105Storek 
32755105Storek 		case KEY_LSHIFT:
32855105Storek 			ks->kbd_lshift = down;
32955105Storek 			break;
33055105Storek 
33155105Storek 		case KEY_RSHIFT:
33255105Storek 			ks->kbd_rshift = down;
33355105Storek 			break;
33455105Storek 
33555105Storek 		case KEY_ALLUP:
33655105Storek 			ks->kbd_anyshift = 0;
33755105Storek 			ks->kbd_control = 0;
33855105Storek 			break;
33955105Storek 
34055105Storek 		case KEY_CONTROL:
34155105Storek 			ks->kbd_control = down;
34255105Storek 			/* FALLTHROUGH */
34355105Storek 
34455105Storek 		case KEY_IGNORE:
34555105Storek 			return (-1);
34655105Storek 
34755105Storek 		default:
34855105Storek 			panic("kbd_translate");
34955105Storek 		}
35055105Storek 		if (ks->kbd_anyshift)
35155105Storek 			ks->kbd_cur = ks->kbd_shifted;
35255105Storek 		else
35355105Storek 			ks->kbd_cur = ks->kbd_unshifted;
35455105Storek 		return (-1);
35555105Storek 	}
35655105Storek 	if (!down)
35755105Storek 		return (-1);
35855105Storek 	if (ks->kbd_control) {
35955105Storek 		/* control space and unshifted control atsign return null */
36055105Storek 		if (c == ' ' || c == '2')
36155105Storek 			return (0);
36255105Storek 		/* unshifted control hat */
36355105Storek 		if (c == '6')
36455105Storek 			return ('^' & 0x1f);
36555105Storek 		/* standard controls */
36655105Storek 		if (c >= '@' && c < 0x7f)
36755105Storek 			return (c & 0x1f);
36855105Storek 	}
36955105Storek 	return (c);
37055105Storek }
37155105Storek 
37255105Storek void
37355105Storek kbd_rint(register int c)
37455105Storek {
37555105Storek 	register struct kbd_softc *k = &kbd_softc;
37655105Storek 	register struct firm_event *fe;
37755105Storek 	register int put;
37855105Storek 
37955105Storek 	/*
38055105Storek 	 * Reset keyboard after serial port overrun, so we can resynch.
38155105Storek 	 * The printf below should be shortened and/or replaced with a
38255105Storek 	 * call to log() after this is tested (and how will we test it?!).
38355105Storek 	 */
38455105Storek 	if (c & (TTY_FE|TTY_PE)) {
38555105Storek 		printf("keyboard input parity or framing error (0x%x)\n", c);
38655105Storek 		(void) ttyoutput(KBD_CMD_RESET, k->k_kbd);
38755105Storek 		(*k->k_kbd->t_oproc)(k->k_kbd);
38855105Storek 		return;
38955105Storek 	}
39055105Storek 
39155105Storek 	/* Read the keyboard id if we read a KBD_RESET last time */
39255105Storek 	if (k->k_state.kbd_takeid) {
39355105Storek 		k->k_state.kbd_takeid = 0;
39455105Storek 		k->k_state.kbd_id = c;
39555105Storek 		kbd_reset(&k->k_state);
39655105Storek 		return;
39755105Storek 	}
39855105Storek 
39955105Storek 	/* If we have been reset, setup to grab the keyboard id next time */
40055105Storek 	if (c == KBD_RESET) {
40155105Storek 		k->k_state.kbd_takeid = 1;
40255105Storek 		return;
40355105Storek 	}
40455105Storek 
40555105Storek 	/*
40655105Storek 	 * If /dev/kbd is not connected in event mode, but we are sending
40755105Storek 	 * data to /dev/console, translate and send upstream.  Note that
40855105Storek 	 * we will get this while opening /dev/kbd if it is not already
40955105Storek 	 * open and we do not know its type.
41055105Storek 	 */
41155105Storek 	if (!k->k_evmode) {
41255105Storek 		c = kbd_translate(c, &k->k_state);
41355105Storek 		if (c >= 0 && k->k_cons != NULL)
41455105Storek 			ttyinput(c, k->k_cons);
41555105Storek 		return;
41655105Storek 	}
41755105Storek 
41855105Storek 	/*
41955105Storek 	 * IDLEs confuse the MIT X11R4 server badly, so we must drop them.
42055105Storek 	 * This is bad as it means the server will not automatically resync
42155105Storek 	 * on all-up IDLEs, but I did not drop them before, and the server
42255105Storek 	 * goes crazy when it comes time to blank the screen....
42355105Storek 	 */
42455105Storek 	if (c == KBD_IDLE)
42555105Storek 		return;
42655105Storek 
42755105Storek 	/*
42855105Storek 	 * Keyboard is generating events.  Turn this keystroke into an
42955105Storek 	 * event and put it in the queue.  If the queue is full, the
43055105Storek 	 * keystroke is lost (sorry!).
43155105Storek 	 */
43255105Storek 	put = k->k_events.ev_put;
43355105Storek 	fe = &k->k_events.ev_q[put];
43455105Storek 	put = (put + 1) % EV_QSIZE;
43555105Storek 	if (put == k->k_events.ev_get) {
43655105Storek 		log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
43755105Storek 		return;
43855105Storek 	}
43955105Storek 	fe->id = KEY_CODE(c);
44055105Storek 	fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
44155105Storek 	fe->time = time;
44255105Storek 	k->k_events.ev_put = put;
44355105Storek 	EV_WAKEUP(&k->k_events);
44455105Storek }
44555105Storek 
44655105Storek int
44755105Storek kbdopen(dev_t dev, int flags, int mode, struct proc *p)
44855105Storek {
44955105Storek 	int s, error;
45055105Storek 
45155105Storek 	if (kbd_softc.k_events.ev_io)
45255105Storek 		return (EBUSY);
45355105Storek 	kbd_softc.k_events.ev_io = p;
45455105Storek 	/*
45555105Storek 	 * If no console keyboard, tell the device to open up, maybe for
45655105Storek 	 * the first time.  Then make sure we know what kind of keyboard
45755105Storek 	 * it is.
45855105Storek 	 */
45955105Storek 	if (kbd_softc.k_cons == NULL)
46055105Storek 		(*kbd_softc.k_open)(kbd_softc.k_kbd);
46155105Storek 	error = 0;
46255105Storek 	s = spltty();
46355105Storek 	if (kbd_softc.k_state.kbd_cur == NULL) {
46455105Storek 		(void) ttyoutput(KBD_CMD_RESET, kbd_softc.k_kbd);
46555105Storek 		error = tsleep((caddr_t)&kbd_softc.k_state, PZERO | PCATCH,
46655105Storek 		    devopn, hz);
46755105Storek 		if (error == EWOULDBLOCK)	/* no response */
46855105Storek 			error = ENXIO;
46955105Storek 	}
47055105Storek 	splx(s);
47155105Storek 	if (error) {
47255105Storek 		kbd_softc.k_events.ev_io = NULL;
47355105Storek 		return (error);
47455105Storek 	}
47555105Storek 	ev_init(&kbd_softc.k_events);
47655105Storek 	return (0);
47755105Storek }
47855105Storek 
47955105Storek int
48055105Storek kbdclose(dev_t dev, int flags, int mode, struct proc *p)
48155105Storek {
48255105Storek 
48355105Storek 	/*
48455105Storek 	 * Turn off event mode, dump the queue, and close the keyboard
48555105Storek 	 * unless it is supplying console input.
48655105Storek 	 */
48755105Storek 	kbd_softc.k_evmode = 0;
48855105Storek 	ev_fini(&kbd_softc.k_events);
48955105Storek 	if (kbd_softc.k_cons == NULL)
49055105Storek 		(*kbd_softc.k_close)(kbd_softc.k_kbd);
49155105Storek 	kbd_softc.k_events.ev_io = NULL;
49255105Storek 	return (0);
49355105Storek }
49455105Storek 
49555105Storek int
49655105Storek kbdread(dev_t dev, struct uio *uio, int flags)
49755105Storek {
49855105Storek 
49955105Storek 	return (ev_read(&kbd_softc.k_events, uio, flags));
50055105Storek }
50155105Storek 
50255105Storek /* this routine should not exist, but is convenient to write here for now */
50355105Storek int
50455105Storek kbdwrite(dev_t dev, struct uio *uio, int flags)
50555105Storek {
50655105Storek 
50755105Storek 	return (EOPNOTSUPP);
50855105Storek }
50955105Storek 
51055105Storek int
51155105Storek kbdioctl(dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p)
51255105Storek {
51355105Storek 	register struct kbd_softc *k = &kbd_softc;
51455105Storek 
51555105Storek 	switch (cmd) {
51655105Storek 
51755105Storek 	case KIOCTRANS:
51855105Storek 		if (*(int *)data == TR_UNTRANS_EVENT)
51955105Storek 			return (0);
52055105Storek 		break;
52155105Storek 
52255105Storek 	case KIOCGTRANS:
52355105Storek 		/*
52455105Storek 		 * Get translation mode
52555105Storek 		 */
52655105Storek 		*(int *)data = TR_UNTRANS_EVENT;
52755105Storek 		return (0);
52855105Storek 
52955105Storek 	case KIOCGETKEY:
53055105Storek 		if (((struct kiockey *)data)->kio_station == 118) {
53155105Storek 			/*
53255105Storek 			 * This is X11 asking if a type 3 keyboard is
53355105Storek 			 * really a type 3 keyboard.  Say yes.
53455105Storek 			 */
53555105Storek 			((struct kiockey *)data)->kio_entry = HOLE;
53655105Storek 			return (0);
53755105Storek 		}
53855105Storek 		break;
53955105Storek 
54055105Storek 	case KIOCCMD:
54155105Storek 		/*
54255105Storek 		 * ``unimplemented commands are ignored'' (blech)
54355105Storek 		 * so cannot check return value from kbd_docmd
54455105Storek 		 */
54555105Storek #ifdef notyet
54655105Storek 		while (kbd_docmd(*(int *)data, 1) == ENOSPC) /*ERESTART?*/
54755105Storek 			(void) sleep((caddr_t)&lbolt, TTOPRI);
54855105Storek #else
54955105Storek 		(void) kbd_docmd(*(int *)data, 1);
55055105Storek #endif
55155105Storek 		return (0);
55255105Storek 
55355105Storek 	case KIOCTYPE:
55455105Storek 		*(int *)data = k->k_state.kbd_id;
55555105Storek 		return (0);
55655105Storek 
55755105Storek 	case KIOCSDIRECT:
55855105Storek 		k->k_evmode = *(int *)data;
55955105Storek 		return (0);
56055105Storek 
56155105Storek 	case FIONBIO:		/* we will remove this someday (soon???) */
56255105Storek 		return (0);
56355105Storek 
56455105Storek 	case FIOASYNC:
56555105Storek 		k->k_events.ev_async = *(int *)data != 0;
56655105Storek 		return (0);
56755105Storek 
56855105Storek 	case TIOCSPGRP:
56955105Storek 		if (*(int *)data != k->k_events.ev_io->p_pgid)
57055105Storek 			return (EPERM);
57155105Storek 		return (0);
57255105Storek 
57355105Storek 	default:
57455105Storek 		return (ENOTTY);
57555105Storek 	}
57655105Storek 
57755105Storek 	/*
57855105Storek 	 * We identified the ioctl, but we do not handle it.
57955105Storek 	 */
58055105Storek 	return (EOPNOTSUPP);		/* misuse, but what the heck */
58155105Storek }
58255105Storek 
58355105Storek int
58455105Storek kbdselect(dev_t dev, int rw, struct proc *p)
58555105Storek {
58655105Storek 
58755105Storek 	return (ev_select(&kbd_softc.k_events, rw, p));
58855105Storek }
58955105Storek 
59055105Storek /*
59155105Storek  * Execute a keyboard command; return 0 on success.
59255105Storek  * If `isuser', force a small delay before output if output queue
59355105Storek  * is flooding.  (The keyboard runs at 1200 baud, or 120 cps.)
59455105Storek  */
59555105Storek int
59655105Storek kbd_docmd(int cmd, int isuser)
59755105Storek {
59855105Storek 	register struct tty *tp = kbd_softc.k_kbd;
59955105Storek 	register struct kbd_softc *k = &kbd_softc;
60055105Storek 	int s;
60155105Storek 
60255105Storek 	if (tp == NULL)
60355105Storek 		return (ENXIO);		/* ??? */
60455105Storek 	switch (cmd) {
60555105Storek 
60655105Storek 	case KBD_CMD_BELL:
60755105Storek 	case KBD_CMD_NOBELL:
60855105Storek 		/* Supported by type 2, 3, and 4 keyboards */
60955105Storek 		break;
61055105Storek 
61155105Storek 	case KBD_CMD_CLICK:
61255105Storek 		/* Unsupported by type 2 keyboards */
61355105Storek 		if (k->k_state.kbd_id != KB_SUN2) {
61455105Storek 			k->k_state.kbd_click = 1;
61555105Storek 			break;
61655105Storek 		}
61755105Storek 		return (EINVAL);
61855105Storek 
61955105Storek 	case KBD_CMD_NOCLICK:
62055105Storek 		/* Unsupported by type 2 keyboards */
62155105Storek 		if (k->k_state.kbd_id != KB_SUN2) {
62255105Storek 			k->k_state.kbd_click = 0;
62355105Storek 			break;
62455105Storek 		}
62555105Storek 		return (EINVAL);
62655105Storek 
62755105Storek 	default:
62855105Storek 		return (EINVAL);	/* ENOTTY? EOPNOTSUPP? */
62955105Storek 	}
63055105Storek 
63155105Storek 	if (isuser) {
63255105Storek 		s = spltty();
63355105Storek 		if (tp->t_outq.c_cc > 120)
63455105Storek 			(void) tsleep((caddr_t)&lbolt, TTIPRI,
63555105Storek 			    ttyout, 0);
63655105Storek 		splx(s);
63755105Storek 	}
63855105Storek 	if (ttyoutput(cmd, tp) >= 0)
63955105Storek 		return (ENOSPC);	/* ERESTART? */
64055105Storek 	(*tp->t_oproc)(tp);
64155105Storek 	return (0);
64255105Storek }
643