summaryrefslogtreecommitdiff
path: root/sys/arch/hp300/dev/dnkbd.c
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2005-04-22 11:59:12 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2005-04-22 11:59:12 +0000
commit45d66f70648de09cb68227f7bc36df4b3c144a6d (patch)
tree6b3e10f3990bb400d467dcadb21cf4f03b7aa764 /sys/arch/hp300/dev/dnkbd.c
parent2859385583ab340f0cbf668de9bb48e8553d3e76 (diff)
Driver for the Apollo Domain keyboard and mouse, for the HP 9000/4xx series.
Claims the console keyboard if a keyboard is detected at boot time, otherwise HIL is preferred (but due to wsmux both can be used simultaneously).
Diffstat (limited to 'sys/arch/hp300/dev/dnkbd.c')
-rw-r--r--sys/arch/hp300/dev/dnkbd.c881
1 files changed, 881 insertions, 0 deletions
diff --git a/sys/arch/hp300/dev/dnkbd.c b/sys/arch/hp300/dev/dnkbd.c
new file mode 100644
index 00000000000..917c9454ed8
--- /dev/null
+++ b/sys/arch/hp300/dev/dnkbd.c
@@ -0,0 +1,881 @@
+/* $OpenBSD: dnkbd.c,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+
+/*
+ * Copyright (c) 2005, Miodrag Vallat
+ * Copyright (c) 1997 Michael Smith. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Driver for the Apollo Domain keyboard and mouse.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/timeout.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+#include <dev/wscons/wskbdraw.h>
+#endif
+#include <dev/wscons/wsmousevar.h>
+
+#include <hp300/dev/apcireg.h>
+#include <hp300/dev/apcivar.h>
+#include <hp300/dev/dcareg.h>
+#include <hp300/dev/dnkbdmap.h>
+#include <hp300/dev/frodoreg.h>
+#include <hp300/dev/frodovar.h>
+
+#include "hilkbd.h"
+
+/*
+ * Keyboard key codes
+ */
+
+#define DNKEY_REPEAT 0x7e
+#define DNKEY_RELEASE 0x80
+#define DNKEY_CHANNEL 0xff
+
+/*
+ * Channels
+ */
+
+#define DNCHANNEL_RESET 0x00
+#define DNCHANNEL_KBD 0x01
+#define DNCHANNEL_MOUSE 0x02
+
+/*
+ * Keyboard modes
+ */
+
+#define DNMODE_COOKED 0x00
+#define DNMODE_RAW 0x01
+
+/*
+ * Keyboard commands
+ */
+
+#define DNCMD_PREFIX 0xff
+#define DNCMD_COOKED DNMODE_COOKED
+#define DNCMD_RAW DNMODE_RAW
+#define DNCMD_IDENT_1 0x12
+#define DNCMD_IDENT_2 0x21
+
+/*
+ * Mouse status
+ */
+
+#define DNBUTTON_L 0x10
+#define DNBUTTON_R 0x20
+#define DNBUTTON_M 0x40
+
+struct dnkbd_softc {
+ struct device sc_dev;
+ struct isr sc_isr;
+ struct apciregs *sc_regs;
+
+ int sc_flags;
+#define SF_ENABLED 0x01 /* keyboard enabled */
+#define SF_CONSOLE 0x02 /* keyboard is console */
+#define SF_POLLING 0x04 /* polling mode */
+#define SF_PLUGGED 0x08 /* keyboard has been seen plugged */
+#define SF_ATTACHED 0x10 /* subdevices have been attached */
+#define SF_MOUSE 0x20 /* mouse enabled */
+
+ u_int sc_identlen;
+#define MAX_IDENTLEN 32
+ char sc_ident[MAX_IDENTLEN];
+
+ enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL } sc_state;
+
+ u_int8_t sc_mousepkt[3]; /* mouse packet being constructed */
+ u_int sc_mousepos; /* index in above */
+
+ struct device *sc_wskbddev;
+ struct device *sc_wsmousedev;
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ int sc_rawkbd;
+ int sc_nrep;
+ char sc_rep[2]; /* at most, one key */
+ struct timeout sc_rawrepeat_ch;
+#define REP_DELAY1 400
+#define REP_DELAYN 100
+#endif
+};
+
+int dnkbd_match(struct device *, void *, void *);
+void dnkbd_attach(struct device *, struct device *, void *);
+
+struct cfdriver dnkbd_cd = {
+ NULL, "dnkbd", DV_DULL
+};
+
+struct cfattach dnkbd_ca = {
+ sizeof(struct dnkbd_softc), dnkbd_match, dnkbd_attach
+};
+
+int dnkbd_enable(void *, int);
+void dnkbd_set_leds(void *, int);
+int dnkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct wskbd_accessops dnkbd_accessops = {
+ dnkbd_enable,
+ dnkbd_set_leds,
+ dnkbd_ioctl
+};
+
+int dnmouse_enable(void *);
+int dnmouse_ioctl(void *, u_long, caddr_t, int, struct proc *);
+void dnmouse_disable(void *);
+
+const struct wsmouse_accessops dnmouse_accessops = {
+ dnmouse_enable,
+ dnmouse_ioctl,
+ dnmouse_disable
+};
+
+void dnkbd_cngetc(void *, u_int *, int *);
+void dnkbd_cnpollc(void *, int);
+
+const struct wskbd_consops dnkbd_consops = {
+ dnkbd_cngetc,
+ dnkbd_cnpollc,
+ NULL /* bell */
+};
+
+struct wskbd_mapdata dnkbd_keymapdata = {
+ dnkbd_keydesctab,
+ KB_US
+};
+
+typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent;
+
+void dnevent_kbd(struct dnkbd_softc *, int);
+void dnevent_mouse(struct dnkbd_softc *, u_int8_t *);
+void dnkbd_attach_subdevices(struct dnkbd_softc *);
+void dnkbd_decode(int, u_int *, int *);
+int dnkbd_init(struct apciregs *);
+dnevent dnkbd_input(struct dnkbd_softc *, int);
+int dnkbd_intr(void *);
+int dnkbd_pollin(struct apciregs *, u_int);
+int dnkbd_pollout(struct apciregs *, int);
+int dnkbd_probe(struct dnkbd_softc *);
+void dnkbd_rawrepeat(void *);
+int dnkbd_send(struct apciregs *, u_int8_t *, size_t);
+int dnsubmatch_kbd(struct device *, void *, void *);
+int dnsubmatch_mouse(struct device *, void *, void *);
+
+int
+dnkbd_match(struct device *parent, void *match, void *aux)
+{
+ struct frodo_attach_args *fa = aux;
+
+ if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0)
+ return (0);
+
+ /* only attach to the first frodo port */
+ return (fa->fa_offset == FRODO_APCI_OFFSET(0));
+}
+
+void
+dnkbd_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dnkbd_softc *sc = (struct dnkbd_softc *)self;
+ struct frodo_attach_args *fa = aux;
+
+ printf(": ");
+
+ sc->sc_regs = (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ timeout_set(&sc->sc_rawrepeat_ch, dnkbd_rawrepeat, sc);
+#endif
+
+ /* reset the port */
+ apciinit(sc->sc_regs, 1200, CFCR_8BITS | CFCR_PEVEN | CFCR_PENAB);
+
+ sc->sc_isr.isr_func = dnkbd_intr;
+ sc->sc_isr.isr_arg = sc;
+ sc->sc_isr.isr_priority = IPL_TTY;
+ frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
+
+ /* probe for keyboard */
+ if (dnkbd_probe(sc) != 0) {
+ printf("no keyboard\n");
+ return;
+ }
+
+ dnkbd_attach_subdevices(sc);
+}
+
+void
+dnkbd_attach_subdevices(struct dnkbd_softc *sc)
+{
+ struct wskbddev_attach_args ka;
+ struct wsmousedev_attach_args ma;
+#if NHILKBD > 0
+ extern int hil_is_console;
+#endif
+
+ /*
+ * If both hilkbd and dnkbd are configured, prefer the Domain
+ * keyboard as console (if we are here, we know the keyboard is
+ * plugged). But if it's a late hotplug, the hil code will have
+ * claimed the console keyboard, so don't claim it now.
+ * Unfortunately, the hil code will claim the console keyboard
+ * even if no HIL keyboard is connected...
+ */
+#if NHILKBD > 0
+ if (hil_is_console == -1) {
+ ka.console = 1;
+ hil_is_console = 0;
+ } else
+ ka.console = 0;
+#else
+ ka.console = 1;
+#endif
+ ka.keymap = &dnkbd_keymapdata;
+ ka.accessops = &dnkbd_accessops;
+ ka.accesscookie = sc;
+
+ if (ka.console) {
+ sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
+ wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
+ } else {
+ sc->sc_flags = SF_PLUGGED;
+ }
+
+ sc->sc_wskbddev = config_found_sm(&sc->sc_dev, &ka, wskbddevprint,
+ dnsubmatch_kbd);
+
+ ma.accessops = &dnmouse_accessops;
+ ma.accesscookie = sc;
+
+ sc->sc_wsmousedev = config_found_sm(&sc->sc_dev, &ma, wsmousedevprint,
+ dnsubmatch_mouse);
+
+ SET(sc->sc_flags, SF_ATTACHED);
+}
+
+int
+dnsubmatch_kbd(struct device *parent, void *match, void *aux)
+{
+ struct cfdata *cf = match;
+ extern struct cfdriver wskbd_cd;
+
+ if (strcmp(cf->cf_driver->cd_name, wskbd_cd.cd_name) != 0)
+ return (0);
+
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+int
+dnsubmatch_mouse(struct device *parent, void *match, void *aux)
+{
+ struct cfdata *cf = match;
+ extern struct cfdriver wsmouse_cd;
+
+ if (strcmp(cf->cf_driver->cd_name, wsmouse_cd.cd_name) != 0)
+ return (0);
+
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+int
+dnkbd_probe(struct dnkbd_softc *sc)
+{
+ int dat, rc;
+ u_int8_t cmdbuf[2];
+ char rspbuf[MAX_IDENTLEN], *word, *end;
+ u_int i;
+ int s;
+
+ s = splhigh();
+
+ /*
+ * Switch keyboard to raw mode.
+ */
+ cmdbuf[0] = DNCMD_RAW;
+ rc = dnkbd_send(sc->sc_regs, cmdbuf, 1);
+ if (rc != 0) {
+ splx(s);
+ return (rc);
+ }
+
+ /*
+ * Send the identify command.
+ */
+ cmdbuf[0] = DNCMD_IDENT_1;
+ cmdbuf[1] = DNCMD_IDENT_2;
+ rc = dnkbd_send(sc->sc_regs, cmdbuf, 2);
+ if (rc != 0) {
+ splx(s);
+ return (rc);
+ }
+
+ for (i = 0; ; i++) {
+ dat = dnkbd_pollin(sc->sc_regs, 10000);
+ if (dat == -1)
+ break;
+
+ if (i < sizeof(rspbuf))
+ rspbuf[i] = dat;
+ }
+
+ if (i >= sizeof(rspbuf)) {
+ printf("%s: unexpected identify string length %d\n",
+ sc->sc_dev.dv_xname, i);
+ splx(s);
+ return (ENXIO);
+ }
+
+ /*
+ * Make sure the identification string is NULL terminated
+ * (overwriting the keyboard mode byte if necessary).
+ */
+ if (i == sizeof(rspbuf) && dat != 0)
+ rspbuf[--i] = 0;
+
+ /*
+ * Now display the identification strings, if it changed.
+ */
+ if (i != sc->sc_identlen || bcmp(rspbuf, sc->sc_ident, i) != 0) {
+ sc->sc_identlen = i;
+ bcopy(rspbuf, sc->sc_ident, i);
+
+ if (cold == 0)
+ printf("%s: ", sc->sc_dev.dv_xname);
+ word = rspbuf;
+ for (i = 0; i < 3; i++) {
+ end = strchr(word, '\r');
+ if (end == NULL)
+ break;
+ *end++ = '\0';
+ printf("<%s> ", word);
+ word = end;
+ }
+ printf("\n");
+ }
+
+ splx(s);
+ return (0);
+}
+
+/*
+ * State machine.
+ *
+ * The keyboard may feed us the following sequences:
+ * - a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
+ * - the key repeat sequence 0x7f.
+ * - a 3 byte mouse sequence.
+ * - a 2 byte channel sequence (0xff followed by the channel number) telling
+ * us which device the following input will come from.
+ */
+
+dnevent
+dnkbd_input(struct dnkbd_softc *sc, int dat)
+{
+ dnevent event = EVENT_NONE;
+
+ switch (sc->sc_state) {
+ case STATE_KEYBOARD:
+ switch (dat) {
+ case DNKEY_REPEAT:
+ /*
+ * We ignore event repeats, as wskbd does its own
+ * soft repeat processing.
+ */
+ break;
+ case DNKEY_CHANNEL:
+ sc->sc_state = STATE_CHANNEL;
+ break;
+ default:
+ event = EVENT_KEYBOARD;
+ break;
+ }
+ break;
+
+ case STATE_MOUSE:
+ if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
+ sc->sc_state = STATE_CHANNEL;
+ } else {
+ sc->sc_mousepkt[sc->sc_mousepos++] = dat;
+ if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
+ sc->sc_mousepos = 0;
+ event = EVENT_MOUSE;
+ }
+ }
+ break;
+
+ case STATE_CHANNEL:
+ switch (dat) {
+ case DNKEY_CHANNEL:
+ /*
+ * During hotplug, we might get spurious 0xff bytes.
+ * Ignore them.
+ */
+ break;
+ case DNCHANNEL_RESET:
+ /*
+ * Identify the keyboard again. This will switch it to
+ * raw mode again. If this fails, we'll consider the
+ * keyboard as unplugged (to ignore further events until
+ * a successfull reset).
+ */
+ if (dnkbd_probe(sc) == 0) {
+ /*
+ * We need to attach wskbd and wsmouse children
+ * if this is a live first plug.
+ */
+ if (!ISSET(sc->sc_flags, SF_ATTACHED))
+ dnkbd_attach_subdevices(sc);
+ SET(sc->sc_flags, SF_PLUGGED);
+ } else {
+ CLR(sc->sc_flags, SF_PLUGGED);
+ }
+
+ sc->sc_state = STATE_KEYBOARD;
+ break;
+ case DNCHANNEL_KBD:
+ sc->sc_state = STATE_KEYBOARD;
+ break;
+ case DNCHANNEL_MOUSE:
+ sc->sc_state = STATE_MOUSE;
+ sc->sc_mousepos = 0; /* just in case */
+ break;
+ default:
+ printf("%s: unexpected channel byte %02x\n",
+ sc->sc_dev.dv_xname, dat);
+ break;
+ }
+ break;
+ }
+
+ return (event);
+}
+
+/*
+ * Event breakers.
+ */
+
+void
+dnkbd_decode(int keycode, u_int *type, int *key)
+{
+ *type = (keycode & DNKEY_RELEASE) ?
+ WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
+ *key = (keycode & ~DNKEY_RELEASE);
+}
+
+void
+dnevent_kbd(struct dnkbd_softc *sc, int dat)
+{
+ u_int type;
+ int key;
+ int s;
+
+ if (!ISSET(sc->sc_flags, SF_PLUGGED))
+ return;
+
+ if (sc->sc_wskbddev == NULL)
+ return;
+
+ if (!ISSET(sc->sc_flags, SF_ENABLED))
+ return;
+
+ dnkbd_decode(dat, &type, &key);
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ if (sc->sc_rawkbd) {
+ u_char cbuf[2];
+ int c, j = 0;
+
+ c = dnkbd_raw[key];
+ if (c != RAWKEY_Null) {
+ /* fake extended scancode if necessary */
+ if (c & 0x80)
+ cbuf[j++] = 0xe0;
+ cbuf[j] = c & 0x7f;
+ if (type == WSCONS_EVENT_KEY_UP)
+ cbuf[j] |= 0x80;
+ else {
+ /* remember pressed key for autorepeat */
+ bcopy(cbuf, sc->sc_rep, sizeof(sc->sc_rep));
+ }
+ }
+
+ s = spltty();
+ wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
+ splx(s);
+ timeout_del(&sc->sc_rawrepeat_ch);
+ sc->sc_nrep = j;
+ if (j != 0) {
+ timeout_add(&sc->sc_rawrepeat_ch,
+ (hz * REP_DELAY1) / 1000);
+ }
+ } else
+#endif
+ {
+ s = spltty();
+ wskbd_input(sc->sc_wskbddev, type, key);
+ splx(s);
+ }
+}
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+void
+dnkbd_rawrepeat(void *v)
+{
+ struct dnkbd_softc *sc = v;
+ int s;
+
+ s = spltty();
+ wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
+ splx(s);
+
+ timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
+}
+#endif
+
+void
+dnevent_mouse(struct dnkbd_softc *sc, u_int8_t *dat)
+{
+ if (!ISSET(sc->sc_flags, SF_PLUGGED))
+ return;
+
+ if (sc->sc_wsmousedev == NULL)
+ return;
+
+ if (!ISSET(sc->sc_flags, SF_MOUSE))
+ return;
+
+ /*
+ * First byte is button status. It has the 0x80 bit always set, and
+ * the next 3 bits are *cleared* when the mouse buttons are pressed.
+ */
+#ifdef DEBUG
+ if (!ISSET(*dat, 0x80)) {
+ printf("%s: incorrect mouse packet %02x %02x %02x\n",
+ sc->sc_dev.dv_xname, dat[0], dat[1], dat[2]);
+ return;
+ }
+#endif
+
+ wsmouse_input(sc->sc_wsmousedev,
+ (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
+ (int8_t)dat[1], (int8_t)dat[2], 0, WSMOUSE_INPUT_DELTA);
+}
+
+/*
+ * Low-level communication routines.
+ */
+
+int
+dnkbd_pollin(struct apciregs *apci, u_int tries)
+{
+ u_int cnt;
+
+ for (cnt = tries; cnt != 0; cnt--) {
+ if (apci->ap_lsr & LSR_RXRDY)
+ break;
+ DELAY(10);
+ }
+
+ if (cnt == 0)
+ return (-1);
+ else
+ return ((int)apci->ap_data);
+}
+
+int
+dnkbd_pollout(struct apciregs *apci, int dat)
+{
+ u_int cnt;
+
+ for (cnt = 10000; cnt != 0; cnt--) {
+ if (apci->ap_lsr & LSR_TXRDY)
+ break;
+ DELAY(10);
+ }
+ if (cnt == 0)
+ return (EBUSY);
+ else {
+ apci->ap_data = dat;
+ return (0);
+ }
+}
+
+int
+dnkbd_send(struct apciregs *apci, u_int8_t *cmdbuf, size_t cmdlen)
+{
+ int cnt, rc, dat;
+ u_int cmdpos;
+
+ /* drain rxfifo */
+ for (cnt = 10; cnt != 0; cnt--) {
+ if (dnkbd_pollin(apci, 10) == -1)
+ break;
+ }
+ if (cnt == 0)
+ return (EBUSY);
+
+ /* send command escape */
+ if ((rc = dnkbd_pollout(apci, DNCMD_PREFIX)) != 0)
+ return (rc);
+
+ /* send command buffer */
+ for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
+ if ((rc = dnkbd_pollout(apci, cmdbuf[cmdpos])) != 0)
+ return (rc);
+ }
+
+ /* wait for command echo */
+ do {
+ dat = dnkbd_pollin(apci, 10000);
+ if (dat == -1)
+ return (EIO);
+ } while (dat != DNCMD_PREFIX);
+
+ for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
+ dat = dnkbd_pollin(apci, 10000);
+ if (dat != cmdbuf[cmdpos])
+ return (EIO);
+ }
+
+ return (0);
+}
+
+int
+dnkbd_intr(void *v)
+{
+ struct dnkbd_softc *sc = v;
+ struct apciregs *apci = sc->sc_regs;
+ u_int8_t iir, lsr, c;
+ int claimed = 0;
+
+ for (;;) {
+ iir = apci->ap_iir;
+
+ switch (iir & IIR_IMASK) {
+ case IIR_RLS:
+ /*
+ * Line status change. This should never happen,
+ * so silently ack the interrupt.
+ */
+ c = apci->ap_lsr;
+ break;
+
+ case IIR_RXRDY:
+ case IIR_RXTOUT:
+ /*
+ * Data available. We process it byte by byte.
+ */
+ for (;;) {
+ c = apci->ap_data;
+ switch (dnkbd_input(sc, c)) {
+ case EVENT_KEYBOARD:
+ dnevent_kbd(sc, c);
+ break;
+ case EVENT_MOUSE:
+ dnevent_mouse(sc, sc->sc_mousepkt);
+ break;
+ default: /* appease gcc */
+ break;
+ }
+ lsr = apci->ap_lsr & LSR_RCV_MASK;
+ if (lsr == 0)
+ break;
+ else if (lsr != LSR_RXRDY) {
+ /* ignore error */
+ break;
+ }
+ }
+ break;
+
+ case IIR_TXRDY:
+ /*
+ * Transmit available. Since we do all our commands
+ * in polling mode, we do not need to do anything here.
+ */
+ break;
+
+ default:
+ if (iir & IIR_NOPEND)
+ return (claimed);
+ /* FALLTHROUGH */
+
+ case IIR_MLSC:
+ /*
+ * Modem status change. This should never happen,
+ * so silently ack the interrupt.
+ */
+ c = apci->ap_msr;
+ break;
+ }
+
+ claimed = 1;
+ }
+}
+
+/*
+ * Wskbd callbacks
+ */
+
+int
+dnkbd_enable(void *v, int on)
+{
+ struct dnkbd_softc *sc = v;
+
+ if (on) {
+ if (ISSET(sc->sc_flags, SF_ENABLED))
+ return (EBUSY);
+ SET(sc->sc_flags, SF_ENABLED);
+ } else {
+ if (ISSET(sc->sc_flags, SF_CONSOLE))
+ return (EBUSY);
+ CLR(sc->sc_flags, SF_ENABLED);
+ }
+
+ return (0);
+}
+
+void
+dnkbd_set_leds(void *v, int leds)
+{
+ /*
+ * Not supported. There is only one LED on this keyboard, and
+ * is hardware tied to the caps lock key.
+ */
+}
+
+int
+dnkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct dnkbd_softc *sc = v;
+
+ switch (cmd) {
+ case WSKBDIO_GTYPE:
+ *(int *)data = WSKBD_TYPE_DOMAIN;
+ return (0);
+ case WSKBDIO_SETLEDS:
+ return (ENXIO);
+ case WSKBDIO_GETLEDS:
+ *(int *)data = 0;
+ return (0);
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ case WSKBDIO_SETMODE:
+ sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
+ timeout_del(&sc->sc_rawrepeat_ch);
+ return (0);
+#endif
+ }
+
+ return (-1);
+}
+
+/*
+ * Wsmouse callbacks
+ */
+
+int
+dnmouse_enable(void *v)
+{
+ struct dnkbd_softc *sc = v;
+
+ if (ISSET(sc->sc_flags, SF_MOUSE))
+ return (EBUSY);
+ SET(sc->sc_flags, SF_MOUSE);
+
+ return (0);
+}
+
+int
+dnmouse_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+#if 0
+ struct dnkbd_softc *sc = v;
+#endif
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(int *)data = WSMOUSE_TYPE_DOMAIN;
+ return (0);
+ }
+
+ return (-1);
+}
+
+void
+dnmouse_disable(void *v)
+{
+ struct dnkbd_softc *sc = v;
+
+ CLR(sc->sc_flags, SF_MOUSE);
+}
+
+/*
+ * Console support
+ */
+
+void
+dnkbd_cngetc(void *v, u_int *type, int *data)
+{
+ struct dnkbd_softc *sc = v;
+ int s;
+ int dat;
+
+ for (;;) {
+ s = splhigh();
+ dat = dnkbd_pollin(sc->sc_regs, 10000);
+ if (dat != -1) {
+ if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
+ splx(s);
+ break;
+ }
+ }
+ splx(s);
+ }
+
+ dnkbd_decode(dat, type, data);
+}
+
+void
+dnkbd_cnpollc(void *v, int on)
+{
+ struct dnkbd_softc *sc = v;
+
+ if (on)
+ SET(sc->sc_flags, SF_POLLING);
+ else
+ CLR(sc->sc_flags, SF_POLLING);
+}