155105Storek /*
263318Sbostic * Copyright (c) 1992, 1993
363318Sbostic * The Regents of the University of California. 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 *
955499Sbostic * All advertising materials mentioning features or use of this software
1055499Sbostic * must display the following acknowledgement:
1155499Sbostic * This product includes software developed by the University of
1259189Storek * California, Lawrence Berkeley Laboratory.
1355499Sbostic *
1455105Storek * %sccs.include.redist.c%
1555105Storek *
16*64787Storek * @(#)kbd.c 8.2 (Berkeley) 10/30/93
1755105Storek *
18*64787Storek * from: $Header: kbd.c,v 1.18 93/10/31 05:44:01 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
2756536Sbostic #include <sys/param.h>
2856536Sbostic #include <sys/conf.h>
2956536Sbostic #include <sys/device.h>
3056536Sbostic #include <sys/ioctl.h>
3156536Sbostic #include <sys/kernel.h>
3256536Sbostic #include <sys/proc.h>
3356536Sbostic #include <sys/syslog.h>
3456536Sbostic #include <sys/systm.h>
3556536Sbostic #include <sys/tty.h>
3655105Storek
3756536Sbostic #include <machine/autoconf.h>
3855105Storek
3956536Sbostic #include <sparc/dev/vuid_event.h>
4056536Sbostic #include <sparc/dev/event_var.h>
4156536Sbostic #include <sparc/dev/kbd.h>
4256536Sbostic #include <sparc/dev/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
kbd_ascii(struct tty * tp)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.
217*64787Storek * We pick up the initial keyboard click state here as well.
21855105Storek */
21955105Storek void
kbd_serial(struct tty * tp,void (* iopen)(),void (* iclose)())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
23555105Storek /*
236*64787Storek * Called from main() during pseudo-device setup. If this keyboard is
237*64787Storek * the console, this is our chance to open the underlying serial port and
238*64787Storek * send a RESET, so that we can find out what kind of keyboard it is.
23955105Storek */
240*64787Storek void
kbdattach(int nkbd)241*64787Storek kbdattach(int nkbd)
24255105Storek {
24355105Storek register struct kbd_softc *k;
24455105Storek register struct tty *tp;
24555105Storek
246*64787Storek if (kbd_softc.k_cons != NULL) {
247*64787Storek k = &kbd_softc;
248*64787Storek tp = k->k_kbd;
249*64787Storek (*k->k_open)(tp); /* never to be closed */
250*64787Storek if (ttyoutput(KBD_CMD_RESET, tp) >= 0)
251*64787Storek panic("kbdattach");
252*64787Storek (*tp->t_oproc)(tp); /* get it going */
25355105Storek }
25455105Storek }
25555105Storek
25655105Storek void
kbd_reset(register struct kbd_state * ks)25755105Storek kbd_reset(register struct kbd_state *ks)
25855105Storek {
25955105Storek /*
26055105Storek * On first identification, wake up anyone waiting for type
26155105Storek * and set up the table pointers.
26255105Storek */
26355105Storek if (ks->kbd_unshifted == NULL) {
26455105Storek wakeup((caddr_t)ks);
26555105Storek ks->kbd_unshifted = kbd_unshifted;
26655105Storek ks->kbd_shifted = kbd_shifted;
26755105Storek ks->kbd_cur = ks->kbd_unshifted;
26855105Storek }
26955105Storek
27055105Storek /* Restore keyclick, if necessary */
27155105Storek switch (ks->kbd_id) {
27255105Storek
27355105Storek case KB_SUN2:
27455105Storek /* Type 2 keyboards don't support keyclick */
27555105Storek break;
27655105Storek
27755105Storek case KB_SUN3:
27855105Storek /* Type 3 keyboards come up with keyclick on */
27955105Storek if (!ks->kbd_click)
28055105Storek (void) kbd_docmd(KBD_CMD_NOCLICK, 0);
28155105Storek break;
28255105Storek
28355105Storek case KB_SUN4:
28455105Storek /* Type 4 keyboards come up with keyclick off */
28555105Storek if (ks->kbd_click)
28655105Storek (void) kbd_docmd(KBD_CMD_CLICK, 0);
28755105Storek break;
28855105Storek }
28955105Storek }
29055105Storek
29155105Storek /*
29255105Storek * Turn keyboard up/down codes into ASCII.
29355105Storek */
29455105Storek static int
kbd_translate(register int c,register struct kbd_state * ks)29555105Storek kbd_translate(register int c, register struct kbd_state *ks)
29655105Storek {
29755105Storek register int down;
29855105Storek
29955105Storek if (ks->kbd_cur == NULL) {
30055105Storek /*
30155105Storek * Do not know how to translate yet.
30255105Storek * We will find out when a RESET comes along.
30355105Storek */
30455105Storek return (-1);
30555105Storek }
30655105Storek down = !KEY_UP(c);
30755105Storek c = ks->kbd_cur[KEY_CODE(c)];
30855105Storek if (c & KEY_MAGIC) {
30955105Storek switch (c) {
31055105Storek
31155105Storek case KEY_LSHIFT:
31255105Storek ks->kbd_lshift = down;
31355105Storek break;
31455105Storek
31555105Storek case KEY_RSHIFT:
31655105Storek ks->kbd_rshift = down;
31755105Storek break;
31855105Storek
31955105Storek case KEY_ALLUP:
32055105Storek ks->kbd_anyshift = 0;
32155105Storek ks->kbd_control = 0;
32255105Storek break;
32355105Storek
32455105Storek case KEY_CONTROL:
32555105Storek ks->kbd_control = down;
32655105Storek /* FALLTHROUGH */
32755105Storek
32855105Storek case KEY_IGNORE:
32955105Storek return (-1);
33055105Storek
33155105Storek default:
33255105Storek panic("kbd_translate");
33355105Storek }
33455105Storek if (ks->kbd_anyshift)
33555105Storek ks->kbd_cur = ks->kbd_shifted;
33655105Storek else
33755105Storek ks->kbd_cur = ks->kbd_unshifted;
33855105Storek return (-1);
33955105Storek }
34055105Storek if (!down)
34155105Storek return (-1);
34255105Storek if (ks->kbd_control) {
34355105Storek /* control space and unshifted control atsign return null */
34455105Storek if (c == ' ' || c == '2')
34555105Storek return (0);
34655105Storek /* unshifted control hat */
34755105Storek if (c == '6')
34855105Storek return ('^' & 0x1f);
34955105Storek /* standard controls */
35055105Storek if (c >= '@' && c < 0x7f)
35155105Storek return (c & 0x1f);
35255105Storek }
35355105Storek return (c);
35455105Storek }
35555105Storek
35655105Storek void
kbd_rint(register int c)35755105Storek kbd_rint(register int c)
35855105Storek {
35955105Storek register struct kbd_softc *k = &kbd_softc;
36055105Storek register struct firm_event *fe;
36155105Storek register int put;
36255105Storek
36355105Storek /*
36455105Storek * Reset keyboard after serial port overrun, so we can resynch.
36555105Storek * The printf below should be shortened and/or replaced with a
36655105Storek * call to log() after this is tested (and how will we test it?!).
36755105Storek */
36855105Storek if (c & (TTY_FE|TTY_PE)) {
36955105Storek printf("keyboard input parity or framing error (0x%x)\n", c);
37055105Storek (void) ttyoutput(KBD_CMD_RESET, k->k_kbd);
37155105Storek (*k->k_kbd->t_oproc)(k->k_kbd);
37255105Storek return;
37355105Storek }
37455105Storek
37555105Storek /* Read the keyboard id if we read a KBD_RESET last time */
37655105Storek if (k->k_state.kbd_takeid) {
37755105Storek k->k_state.kbd_takeid = 0;
37855105Storek k->k_state.kbd_id = c;
37955105Storek kbd_reset(&k->k_state);
38055105Storek return;
38155105Storek }
38255105Storek
38355105Storek /* If we have been reset, setup to grab the keyboard id next time */
38455105Storek if (c == KBD_RESET) {
38555105Storek k->k_state.kbd_takeid = 1;
38655105Storek return;
38755105Storek }
38855105Storek
38955105Storek /*
39055105Storek * If /dev/kbd is not connected in event mode, but we are sending
39155105Storek * data to /dev/console, translate and send upstream. Note that
39255105Storek * we will get this while opening /dev/kbd if it is not already
39355105Storek * open and we do not know its type.
39455105Storek */
39555105Storek if (!k->k_evmode) {
39655105Storek c = kbd_translate(c, &k->k_state);
39755105Storek if (c >= 0 && k->k_cons != NULL)
39855105Storek ttyinput(c, k->k_cons);
39955105Storek return;
40055105Storek }
40155105Storek
40255105Storek /*
40355105Storek * IDLEs confuse the MIT X11R4 server badly, so we must drop them.
40455105Storek * This is bad as it means the server will not automatically resync
40555105Storek * on all-up IDLEs, but I did not drop them before, and the server
40655105Storek * goes crazy when it comes time to blank the screen....
40755105Storek */
40855105Storek if (c == KBD_IDLE)
40955105Storek return;
41055105Storek
41155105Storek /*
41255105Storek * Keyboard is generating events. Turn this keystroke into an
41355105Storek * event and put it in the queue. If the queue is full, the
41455105Storek * keystroke is lost (sorry!).
41555105Storek */
41655105Storek put = k->k_events.ev_put;
41755105Storek fe = &k->k_events.ev_q[put];
41855105Storek put = (put + 1) % EV_QSIZE;
41955105Storek if (put == k->k_events.ev_get) {
42055105Storek log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
42155105Storek return;
42255105Storek }
42355105Storek fe->id = KEY_CODE(c);
42455105Storek fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
42555105Storek fe->time = time;
42655105Storek k->k_events.ev_put = put;
42755105Storek EV_WAKEUP(&k->k_events);
42855105Storek }
42955105Storek
43055105Storek int
kbdopen(dev_t dev,int flags,int mode,struct proc * p)43155105Storek kbdopen(dev_t dev, int flags, int mode, struct proc *p)
43255105Storek {
43355105Storek int s, error;
43455105Storek
43555105Storek if (kbd_softc.k_events.ev_io)
43655105Storek return (EBUSY);
43755105Storek kbd_softc.k_events.ev_io = p;
43855105Storek /*
43955105Storek * If no console keyboard, tell the device to open up, maybe for
44055105Storek * the first time. Then make sure we know what kind of keyboard
44155105Storek * it is.
44255105Storek */
44355105Storek if (kbd_softc.k_cons == NULL)
44455105Storek (*kbd_softc.k_open)(kbd_softc.k_kbd);
44555105Storek error = 0;
44655105Storek s = spltty();
44755105Storek if (kbd_softc.k_state.kbd_cur == NULL) {
44855105Storek (void) ttyoutput(KBD_CMD_RESET, kbd_softc.k_kbd);
44955105Storek error = tsleep((caddr_t)&kbd_softc.k_state, PZERO | PCATCH,
45055105Storek devopn, hz);
45155105Storek if (error == EWOULDBLOCK) /* no response */
45255105Storek error = ENXIO;
45355105Storek }
45455105Storek splx(s);
45555105Storek if (error) {
45655105Storek kbd_softc.k_events.ev_io = NULL;
45755105Storek return (error);
45855105Storek }
45955105Storek ev_init(&kbd_softc.k_events);
46055105Storek return (0);
46155105Storek }
46255105Storek
46355105Storek int
kbdclose(dev_t dev,int flags,int mode,struct proc * p)46455105Storek kbdclose(dev_t dev, int flags, int mode, struct proc *p)
46555105Storek {
46655105Storek
46755105Storek /*
46855105Storek * Turn off event mode, dump the queue, and close the keyboard
46955105Storek * unless it is supplying console input.
47055105Storek */
47155105Storek kbd_softc.k_evmode = 0;
47255105Storek ev_fini(&kbd_softc.k_events);
47355105Storek if (kbd_softc.k_cons == NULL)
47455105Storek (*kbd_softc.k_close)(kbd_softc.k_kbd);
47555105Storek kbd_softc.k_events.ev_io = NULL;
47655105Storek return (0);
47755105Storek }
47855105Storek
47955105Storek int
kbdread(dev_t dev,struct uio * uio,int flags)48055105Storek kbdread(dev_t dev, struct uio *uio, int flags)
48155105Storek {
48255105Storek
48355105Storek return (ev_read(&kbd_softc.k_events, uio, flags));
48455105Storek }
48555105Storek
48655105Storek /* this routine should not exist, but is convenient to write here for now */
48755105Storek int
kbdwrite(dev_t dev,struct uio * uio,int flags)48855105Storek kbdwrite(dev_t dev, struct uio *uio, int flags)
48955105Storek {
49055105Storek
49155105Storek return (EOPNOTSUPP);
49255105Storek }
49355105Storek
49455105Storek int
kbdioctl(dev_t dev,int cmd,register caddr_t data,int flag,struct proc * p)49555105Storek kbdioctl(dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p)
49655105Storek {
49755105Storek register struct kbd_softc *k = &kbd_softc;
49855105Storek
49955105Storek switch (cmd) {
50055105Storek
50155105Storek case KIOCTRANS:
50255105Storek if (*(int *)data == TR_UNTRANS_EVENT)
50355105Storek return (0);
50455105Storek break;
50555105Storek
50655105Storek case KIOCGTRANS:
50755105Storek /*
50855105Storek * Get translation mode
50955105Storek */
51055105Storek *(int *)data = TR_UNTRANS_EVENT;
51155105Storek return (0);
51255105Storek
51355105Storek case KIOCGETKEY:
51455105Storek if (((struct kiockey *)data)->kio_station == 118) {
51555105Storek /*
51655105Storek * This is X11 asking if a type 3 keyboard is
51755105Storek * really a type 3 keyboard. Say yes.
51855105Storek */
51955105Storek ((struct kiockey *)data)->kio_entry = HOLE;
52055105Storek return (0);
52155105Storek }
52255105Storek break;
52355105Storek
52455105Storek case KIOCCMD:
52555105Storek /*
52655105Storek * ``unimplemented commands are ignored'' (blech)
52755105Storek * so cannot check return value from kbd_docmd
52855105Storek */
52955105Storek #ifdef notyet
53055105Storek while (kbd_docmd(*(int *)data, 1) == ENOSPC) /*ERESTART?*/
53155105Storek (void) sleep((caddr_t)&lbolt, TTOPRI);
53255105Storek #else
53355105Storek (void) kbd_docmd(*(int *)data, 1);
53455105Storek #endif
53555105Storek return (0);
53655105Storek
53755105Storek case KIOCTYPE:
53855105Storek *(int *)data = k->k_state.kbd_id;
53955105Storek return (0);
54055105Storek
54155105Storek case KIOCSDIRECT:
54255105Storek k->k_evmode = *(int *)data;
54355105Storek return (0);
54455105Storek
54555105Storek case FIONBIO: /* we will remove this someday (soon???) */
54655105Storek return (0);
54755105Storek
54855105Storek case FIOASYNC:
54955105Storek k->k_events.ev_async = *(int *)data != 0;
55055105Storek return (0);
55155105Storek
55255105Storek case TIOCSPGRP:
55355105Storek if (*(int *)data != k->k_events.ev_io->p_pgid)
55455105Storek return (EPERM);
55555105Storek return (0);
55655105Storek
55755105Storek default:
55855105Storek return (ENOTTY);
55955105Storek }
56055105Storek
56155105Storek /*
56255105Storek * We identified the ioctl, but we do not handle it.
56355105Storek */
56455105Storek return (EOPNOTSUPP); /* misuse, but what the heck */
56555105Storek }
56655105Storek
56755105Storek int
kbdselect(dev_t dev,int rw,struct proc * p)56855105Storek kbdselect(dev_t dev, int rw, struct proc *p)
56955105Storek {
57055105Storek
57155105Storek return (ev_select(&kbd_softc.k_events, rw, p));
57255105Storek }
57355105Storek
57455105Storek /*
57555105Storek * Execute a keyboard command; return 0 on success.
57655105Storek * If `isuser', force a small delay before output if output queue
57755105Storek * is flooding. (The keyboard runs at 1200 baud, or 120 cps.)
57855105Storek */
57955105Storek int
kbd_docmd(int cmd,int isuser)58055105Storek kbd_docmd(int cmd, int isuser)
58155105Storek {
58255105Storek register struct tty *tp = kbd_softc.k_kbd;
58355105Storek register struct kbd_softc *k = &kbd_softc;
58455105Storek int s;
58555105Storek
58655105Storek if (tp == NULL)
58755105Storek return (ENXIO); /* ??? */
58855105Storek switch (cmd) {
58955105Storek
59055105Storek case KBD_CMD_BELL:
59155105Storek case KBD_CMD_NOBELL:
59255105Storek /* Supported by type 2, 3, and 4 keyboards */
59355105Storek break;
59455105Storek
59555105Storek case KBD_CMD_CLICK:
59655105Storek /* Unsupported by type 2 keyboards */
59755105Storek if (k->k_state.kbd_id != KB_SUN2) {
59855105Storek k->k_state.kbd_click = 1;
59955105Storek break;
60055105Storek }
60155105Storek return (EINVAL);
60255105Storek
60355105Storek case KBD_CMD_NOCLICK:
60455105Storek /* Unsupported by type 2 keyboards */
60555105Storek if (k->k_state.kbd_id != KB_SUN2) {
60655105Storek k->k_state.kbd_click = 0;
60755105Storek break;
60855105Storek }
60955105Storek return (EINVAL);
61055105Storek
61155105Storek default:
61255105Storek return (EINVAL); /* ENOTTY? EOPNOTSUPP? */
61355105Storek }
61455105Storek
61555105Storek if (isuser) {
61655105Storek s = spltty();
61755105Storek if (tp->t_outq.c_cc > 120)
61855105Storek (void) tsleep((caddr_t)&lbolt, TTIPRI,
61955105Storek ttyout, 0);
62055105Storek splx(s);
62155105Storek }
62255105Storek if (ttyoutput(cmd, tp) >= 0)
62355105Storek return (ENOSPC); /* ERESTART? */
62455105Storek (*tp->t_oproc)(tp);
62555105Storek return (0);
62655105Storek }
627