summaryrefslogtreecommitdiff
path: root/sys/arch/hp300/dev
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
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')
-rw-r--r--sys/arch/hp300/dev/apci.c55
-rw-r--r--sys/arch/hp300/dev/apci.c.orig1042
-rw-r--r--sys/arch/hp300/dev/apci_subr.c126
-rw-r--r--sys/arch/hp300/dev/apcivar.h72
-rw-r--r--sys/arch/hp300/dev/dnkbd.c881
-rw-r--r--sys/arch/hp300/dev/dnkbdmap.c293
-rw-r--r--sys/arch/hp300/dev/dnkbdmap.h28
7 files changed, 2447 insertions, 50 deletions
diff --git a/sys/arch/hp300/dev/apci.c b/sys/arch/hp300/dev/apci.c
index cd0dddfb1e3..091ff57066a 100644
--- a/sys/arch/hp300/dev/apci.c
+++ b/sys/arch/hp300/dev/apci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: apci.c,v 1.22 2005/02/27 22:08:39 miod Exp $ */
+/* $OpenBSD: apci.c,v 1.23 2005/04/22 11:59:11 miod Exp $ */
/* $NetBSD: apci.c,v 1.9 2000/11/02 00:35:05 eeh Exp $ */
/*-
@@ -115,6 +115,7 @@
#include <hp300/dev/frodoreg.h>
#include <hp300/dev/frodovar.h>
#include <hp300/dev/apcireg.h>
+#include <hp300/dev/apcivar.h>
#include <hp300/dev/dcareg.h> /* register bit definitions */
#ifdef DDB
@@ -157,7 +158,6 @@ void apcimint(struct apci_softc *, u_char);
int apciparam(struct tty *, struct termios *);
void apcistart(struct tty *);
int apcimctl(struct apci_softc *, int, int);
-void apciinit(struct apciregs *, int);
void apcitimeout(void *);
cdev_decl(apci);
@@ -167,26 +167,6 @@ cdev_decl(apci);
int apcidefaultrate = TTYDEF_SPEED;
-const struct speedtab apcispeedtab[] = {
- { 0, 0 },
- { 50, APCIBRD(50) },
- { 75, APCIBRD(75) },
- { 110, APCIBRD(110) },
- { 134, APCIBRD(134) },
- { 150, APCIBRD(150) },
- { 200, APCIBRD(200) },
- { 300, APCIBRD(300) },
- { 600, APCIBRD(600) },
- { 1200, APCIBRD(1200) },
- { 1800, APCIBRD(1800) },
- { 2400, APCIBRD(2400) },
- { 4800, APCIBRD(4800) },
- { 9600, APCIBRD(9600) },
- { 19200, APCIBRD(19200) },
- { 38400, APCIBRD(38400) },
- { -1, -1 },
-};
-
/*
* Console support.
*/
@@ -318,7 +298,7 @@ apciopen(dev, flag, mode, p)
* The chip might be left in an inconsistent state
* if it is read inadventently.
*/
- apciinit(apci, apcidefaultrate);
+ apciinit(apci, apcidefaultrate, CFCR_8BITS);
tp->t_state |= TS_WOPEN;
ttychars(tp);
@@ -863,31 +843,6 @@ apcimctl(sc, bits, how)
}
void
-apciinit(apci, rate)
- struct apciregs *apci;
- int rate;
-{
- int s;
- short stat;
-
- s = splhigh();
-
- rate = ttspeedtab(rate, apcispeedtab);
-
- apci->ap_cfcr = CFCR_DLAB;
- apci->ap_data = rate & 0xff;
- apci->ap_ier = (rate >> 8) & 0xff;
- apci->ap_cfcr = CFCR_8BITS;
- apci->ap_ier = IER_ERXRDY | IER_ETXRDY;
- apci->ap_fifo =
- FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1;
- apci->ap_mcr = MCR_DTR | MCR_RTS;
- delay(100);
- stat = apci->ap_iir;
- splx(s);
-}
-
-void
apcitimeout(arg)
void *arg;
{
@@ -984,7 +939,7 @@ apcicninit(cp)
return;
apci_cn = (struct apciregs *)IIOV(FRODO_BASE + FRODO_APCI_OFFSET(1));
- apciinit(apci_cn, apcidefaultrate);
+ apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
apciconsinit = 1;
}
@@ -1020,7 +975,7 @@ apcicnputc(dev, c)
s = splhigh();
if (apciconsinit == 0) {
- apciinit(apci_cn, apcidefaultrate);
+ apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
apciconsinit = 1;
}
diff --git a/sys/arch/hp300/dev/apci.c.orig b/sys/arch/hp300/dev/apci.c.orig
new file mode 100644
index 00000000000..2f29f253f47
--- /dev/null
+++ b/sys/arch/hp300/dev/apci.c.orig
@@ -0,0 +1,1042 @@
+/* $OpenBSD: apci.c.orig,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+/* $NetBSD: apci.c,v 1.9 2000/11/02 00:35:05 eeh Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1997 Michael Smith. All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)dca.c 8.2 (Berkeley) 1/12/94
+ */
+
+/*
+ * Device driver for the APCI 8250-like UARTs found on the Apollo
+ * Utility Chip on HP 9000/400-series workstations.
+ *
+ * There are 4 APCI UARTs on the Frodo ASIC. The first one
+ * is used to communicate with the Domain keyboard. The second
+ * one is the serial console port when the firmware is in Domain/OS
+ * mode, and is mapped to select code 9 by the HP-UX firmware (except
+ * on 425e models).
+ *
+ * We don't bother attaching a tty to the first UART; it lacks modem/flow
+ * control, and is directly connected to the keyboard connector anyhow.
+ */
+
+/*
+ * XXX This driver is very similar to the dca driver, and much
+ * XXX more code could be shared. (Currently, no code is shared.)
+ * XXX FIXME!
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/hp300spu.h>
+
+#include <dev/cons.h>
+
+#include <hp300/dev/dioreg.h> /* to check for dca at 9 */
+#include <hp300/dev/diovar.h>
+#include <hp300/dev/diodevs.h>
+
+#include <hp300/dev/frodoreg.h>
+#include <hp300/dev/frodovar.h>
+#include <hp300/dev/apcireg.h>
+#include <hp300/dev/dcareg.h> /* register bit definitions */
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#endif
+
+struct apci_softc {
+ struct device sc_dev; /* generic device glue */
+ struct isr sc_isr;
+ struct apciregs *sc_apci; /* device registers */
+ struct tty *sc_tty; /* tty glue */
+ struct timeout sc_timeout; /* timeout */
+ int sc_ferr,
+ sc_perr,
+ sc_oflow,
+ sc_toterr; /* stats */
+ int sc_flags;
+ u_char sc_cua; /* callout mode */
+};
+
+/* sc_flags */
+#define APCI_HASFIFO 0x01 /* unit has a fifo */
+#define APCI_ISCONSOLE 0x02 /* unit is console */
+#define APCI_SOFTCAR 0x04 /* soft carrier */
+
+int apcimatch(struct device *, void *, void *);
+void apciattach(struct device *, struct device *, void *);
+
+struct cfattach apci_ca = {
+ sizeof(struct apci_softc), apcimatch, apciattach
+};
+
+struct cfdriver apci_cd = {
+ NULL, "apci", DV_TTY
+};
+
+int apciintr(void *);
+void apcieint(struct apci_softc *, int);
+void apcimint(struct apci_softc *, u_char);
+int apciparam(struct tty *, struct termios *);
+void apcistart(struct tty *);
+int apcimctl(struct apci_softc *, int, int);
+void apciinit(struct apciregs *, int);
+void apcitimeout(void *);
+
+cdev_decl(apci);
+
+#define APCIUNIT(x) (minor(x) & 0x7f)
+#define APCICUA(x) (minor(x) & 0x80)
+
+int apcidefaultrate = TTYDEF_SPEED;
+
+const struct speedtab apcispeedtab[] = {
+ { 0, 0 },
+ { 50, APCIBRD(50) },
+ { 75, APCIBRD(75) },
+ { 110, APCIBRD(110) },
+ { 134, APCIBRD(134) },
+ { 150, APCIBRD(150) },
+ { 200, APCIBRD(200) },
+ { 300, APCIBRD(300) },
+ { 600, APCIBRD(600) },
+ { 1200, APCIBRD(1200) },
+ { 1800, APCIBRD(1800) },
+ { 2400, APCIBRD(2400) },
+ { 4800, APCIBRD(4800) },
+ { 9600, APCIBRD(9600) },
+ { 19200, APCIBRD(19200) },
+ { 38400, APCIBRD(38400) },
+ { -1, -1 },
+};
+
+/*
+ * Console support.
+ */
+struct apciregs *apci_cn = NULL; /* console hardware */
+int apciconsinit; /* has been initialized */
+int apcimajor; /* our major number */
+
+cons_decl(apci);
+
+int
+apcimatch(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct frodo_attach_args *fa = aux;
+
+ /* Looking for an apci? */
+ if (strcmp(fa->fa_name, apci_cd.cd_name) != 0)
+ return (0);
+
+ /* Are we checking a valid APCI offset? */
+ switch (fa->fa_offset) {
+ case FRODO_APCI_OFFSET(1):
+ case FRODO_APCI_OFFSET(2):
+ case FRODO_APCI_OFFSET(3):
+ /* Yup, we exist! */
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+apciattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct apci_softc *sc = (struct apci_softc *)self;
+ struct apciregs *apci;
+ struct frodo_attach_args *fa = aux;
+
+ sc->sc_apci = apci =
+ (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
+ sc->sc_flags = 0;
+
+ /* Initialize timeout structure */
+ timeout_set(&sc->sc_timeout, apcitimeout, sc);
+
+ /* Are we the console? */
+ if (apci == apci_cn) {
+ sc->sc_flags |= APCI_ISCONSOLE;
+ delay(100000);
+
+ /*
+ * We didn't know which unit this would be during
+ * the console probe, so we have to fixup cn_dev here.
+ */
+ cn_tab->cn_dev = makedev(apcimajor, self->dv_unit);
+ }
+
+ /* Look for a FIFO. */
+ apci->ap_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
+ delay(100);
+ if ((apci->ap_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
+ sc->sc_flags |= APCI_HASFIFO;
+
+ /* Establish our interrupt handler. */
+ sc->sc_isr.isr_func = apciintr;
+ sc->sc_isr.isr_arg = sc;
+ sc->sc_isr.isr_priority =
+ (sc->sc_flags & APCI_HASFIFO) ? IPL_TTY : IPL_TTYNOBUF;
+ frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
+
+ /* Set soft carrier if requested by operator. */
+ if (self->dv_cfdata->cf_flags)
+ sc->sc_flags |= APCI_SOFTCAR;
+
+ /*
+ * Need to reset baud rate, etc. of next print, so reset apciconsinit.
+ * Also make sure console is always "hardwired".
+ */
+ if (sc->sc_flags & APCI_ISCONSOLE) {
+ apciconsinit = 0;
+ sc->sc_flags |= APCI_SOFTCAR;
+ printf(": console, ");
+ } else
+ printf(": ");
+
+ if (sc->sc_flags & APCI_HASFIFO)
+ printf("working fifo\n");
+ else
+ printf("no fifo\n");
+}
+
+/* ARGSUSED */
+int
+apciopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = APCIUNIT(dev);
+ struct apci_softc *sc;
+ struct tty *tp;
+ struct apciregs *apci;
+ u_char code;
+ int s, error = 0;
+
+ if (unit >= apci_cd.cd_ndevs ||
+ (sc = apci_cd.cd_devs[unit]) == NULL)
+ return (ENXIO);
+
+ apci = sc->sc_apci;
+
+ s = spltty();
+ if (sc->sc_tty == NULL) {
+ tp = sc->sc_tty = ttymalloc();
+ } else
+ tp = sc->sc_tty;
+ splx(s);
+
+ tp->t_oproc = apcistart;
+ tp->t_param = apciparam;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ /*
+ * Sanity clause: reset the chip on first open.
+ * The chip might be left in an inconsistent state
+ * if it is read inadventently.
+ */
+ apciinit(apci, apcidefaultrate);
+
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = apcidefaultrate;
+
+ s = spltty();
+
+ apciparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ /* Set the FIFO threshold based on the receive speed. */
+ if (sc->sc_flags & APCI_HASFIFO)
+ apci->ap_fifo = FIFO_ENABLE | FIFO_RCV_RST |
+ FIFO_XMT_RST |
+ (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 :
+ FIFO_TRIGGER_14);
+
+ /* Flush any pending I/O. */
+ while ((apci->ap_iir & IIR_IMASK) == IIR_RXRDY)
+ code = apci->ap_data;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
+ return (EBUSY);
+ else
+ s = spltty();
+
+ /* Set the modem control state. */
+ (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMSET);
+
+ /* Set soft-carrier if so configured. */
+ if ((sc->sc_flags & APCI_SOFTCAR) || APCICUA(dev) ||
+ (apcimctl(sc, 0, DMGET) & MSR_DCD))
+ tp->t_state |= TS_CARR_ON;
+
+ if (APCICUA(dev)) {
+ if (tp->t_state & TS_ISOPEN) {
+ /* Ah, but someone already is dialed in... */
+ splx(s);
+ return (EBUSY);
+ }
+ sc->sc_cua = 1; /* We go into CUA mode */
+ }
+
+ /* Wait for carrier if necessary. */
+ if (flag & O_NONBLOCK) {
+ if (!APCICUA(dev) && sc->sc_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ splx(s);
+ return (EBUSY);
+ }
+ } else {
+ while (sc->sc_cua ||
+ ((tp->t_cflag & CLOCAL) == 0 &&
+ (tp->t_state & TS_CARR_ON) == 0)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_rawq,
+ TTIPRI | PCATCH, ttopen, 0);
+ if (!APCICUA(dev) && sc->sc_cua && error == EINTR)
+ continue;
+ if (error) {
+ if (APCICUA(dev))
+ sc->sc_cua = 0;
+ splx(s);
+ return (error);
+ }
+ if (!APCICUA(dev) && sc->sc_cua)
+ continue;
+ }
+ }
+
+ splx(s);
+
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+
+ if (error == 0) {
+ /* clear errors, start timeout */
+ sc->sc_ferr = sc->sc_perr = sc->sc_oflow = sc->sc_toterr = 0;
+ timeout_add(&sc->sc_timeout, hz);
+ }
+
+ return (error);
+}
+
+/* ARGSUSED */
+int
+apciclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct apci_softc *sc;
+ struct tty *tp;
+ struct apciregs *apci;
+ int unit = APCIUNIT(dev);
+ int s;
+
+ sc = apci_cd.cd_devs[unit];
+ apci = sc->sc_apci;
+ tp = sc->sc_tty;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = spltty();
+
+ apci->ap_cfcr &= ~CFCR_SBREAK;
+ apci->ap_ier = 0;
+ if (tp->t_cflag & HUPCL && (sc->sc_flags & APCI_SOFTCAR) == 0) {
+ /* XXX perhaps only clear DTR */
+ (void) apcimctl(sc, 0, DMSET);
+ }
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ sc->sc_cua = 0;
+ splx(s);
+ ttyclose(tp);
+#if 0
+ ttyfree(tp);
+ sc->sc_tty = NULL;
+#endif
+ return (0);
+}
+
+int
+apciread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+apciwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+apcitty(dev)
+ dev_t dev;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
+
+ return (sc->sc_tty);
+}
+
+int
+apciintr(arg)
+ void *arg;
+{
+ struct apci_softc *sc = arg;
+ struct apciregs *apci = sc->sc_apci;
+ struct tty *tp = sc->sc_tty;
+ u_char iir, lsr, c;
+ int iflowdone = 0, claimed = 0;
+
+#define RCVBYTE() \
+ c = apci->ap_data; \
+ if (tp != NULL && (tp->t_state & TS_ISOPEN) != 0) \
+ (*linesw[tp->t_line].l_rint)(c, tp)
+
+ for (;;) {
+ iir = apci->ap_iir; /* get UART status */
+
+ switch (iir & IIR_IMASK) {
+ case IIR_RLS:
+ apcieint(sc, apci->ap_lsr);
+ break;
+
+ case IIR_RXRDY:
+ case IIR_RXTOUT:
+ RCVBYTE();
+ if (sc->sc_flags & APCI_HASFIFO) {
+ while ((lsr = apci->ap_lsr) & LSR_RCV_MASK) {
+ if (lsr == LSR_RXRDY) {
+ RCVBYTE();
+ } else
+ apcieint(sc, lsr);
+ }
+ }
+ if (iflowdone == 0 && tp != NULL &&
+ (tp->t_cflag & CRTS_IFLOW) &&
+ tp->t_rawq.c_cc > (TTYHOG / 2)) {
+ apci->ap_mcr &= ~MCR_RTS;
+ iflowdone = 1;
+ }
+ break;
+
+ case IIR_TXRDY:
+ if (tp != NULL) {
+ tp->t_state &=~ (TS_BUSY|TS_FLUSH);
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ apcistart(tp);
+ }
+ break;
+
+ default:
+ if (iir & IIR_NOPEND)
+ return (claimed);
+ log(LOG_WARNING, "%s: weird interrupt: 0x%x\n",
+ sc->sc_dev.dv_xname, iir);
+ /* FALLTHROUGH */
+
+ case IIR_MLSC:
+ apcimint(sc, apci->ap_msr);
+ break;
+ }
+
+ claimed = 1;
+ }
+}
+
+void
+apcieint(sc, stat)
+ struct apci_softc *sc;
+ int stat;
+{
+ struct tty *tp = sc->sc_tty;
+ struct apciregs *apci = sc->sc_apci;
+ int c;
+
+ c = apci->ap_data;
+
+#ifdef DDB
+ if ((sc->sc_flags & APCI_ISCONSOLE) && db_console && (stat & LSR_BI)) {
+ Debugger();
+ return;
+ }
+#endif
+
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ if (stat & (LSR_BI | LSR_FE)) {
+ c |= TTY_FE;
+ sc->sc_ferr++;
+ } else if (stat & LSR_PE) {
+ c |= TTY_PE;
+ sc->sc_perr++;
+ } else if (stat & LSR_OE)
+ sc->sc_oflow++;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+}
+
+void
+apcimint(sc, stat)
+ struct apci_softc *sc;
+ u_char stat;
+{
+ struct tty *tp = sc->sc_tty;
+ struct apciregs *apci = sc->sc_apci;
+
+ if (tp == NULL)
+ return;
+
+ if ((stat & MSR_DDCD) &&
+ (sc->sc_flags & APCI_SOFTCAR) == 0) {
+ if (stat & MSR_DCD)
+ (void)(*linesw[tp->t_line].l_modem)(tp, 1);
+ else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
+ apci->ap_mcr &= ~(MCR_DTR | MCR_RTS);
+ }
+
+ /*
+ * CTS change.
+ * If doing HW output flow control, start/stop output as appropriate.
+ */
+ if ((stat & MSR_DCTS) &&
+ (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
+ if (stat & MSR_CTS) {
+ tp->t_state &=~ TS_TTSTOP;
+ apcistart(tp);
+ } else
+ tp->t_state |= TS_TTSTOP;
+ }
+}
+
+int
+apciioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+ struct apciregs *apci = sc->sc_apci;
+ int error;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ apci->ap_cfcr |= CFCR_SBREAK;
+ break;
+
+ case TIOCCBRK:
+ apci->ap_cfcr &= ~CFCR_SBREAK;
+ break;
+
+ case TIOCSDTR:
+ (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) apcimctl(sc, *(int *)data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) apcimctl(sc, *(int *)data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) apcimctl(sc, *(int *)data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = apcimctl(sc, 0, DMGET);
+ break;
+
+ case TIOCGFLAGS: {
+ int bits = 0;
+
+ if (sc->sc_flags & APCI_SOFTCAR)
+ bits |= TIOCFLAG_SOFTCAR;
+
+ if (tp->t_cflag & CLOCAL)
+ bits |= TIOCFLAG_CLOCAL;
+
+ *(int *)data = bits;
+ break;
+ }
+
+ case TIOCSFLAGS: {
+ int userbits;
+
+ error = suser(p, 0);
+ if (error)
+ return (EPERM);
+
+ userbits = *(int *)data;
+
+ if ((userbits & TIOCFLAG_SOFTCAR) ||
+ (sc->sc_flags & APCI_ISCONSOLE))
+ sc->sc_flags |= APCI_SOFTCAR;
+
+ if (userbits & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+
+ break;
+ }
+
+ default:
+ return (ENOTTY);
+ }
+ return (0);
+}
+
+int
+apciparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
+ struct apciregs *apci = sc->sc_apci;
+ int cfcr, cflag = t->c_cflag;
+ int ospeed = ttspeedtab(t->c_ospeed, apcispeedtab);
+ int s;
+
+ /* check requested parameters */
+ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return (EINVAL);
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+
+ case CS8:
+ default: /* XXX gcc whines about cfcr being uninitialized... */
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if ((cflag & PARODD) == 0)
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ s = spltty();
+
+ if (ospeed == 0)
+ (void) apcimctl(sc, 0, DMSET); /* hang up line */
+
+ /*
+ * Set the FIFO threshold based on the receive speed, if we
+ * are changing it.
+ */
+ if (tp->t_ispeed != t->c_ispeed) {
+ if (sc->sc_flags & APCI_HASFIFO)
+ apci->ap_fifo = FIFO_ENABLE |
+ (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 :
+ FIFO_TRIGGER_14);
+ }
+
+ if (ospeed != 0) {
+ apci->ap_cfcr |= CFCR_DLAB;
+ apci->ap_data = ospeed & 0xff;
+ apci->ap_ier = (ospeed >> 8) & 0xff;
+ apci->ap_cfcr = cfcr;
+ } else
+ apci->ap_cfcr = cfcr;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+
+ apci->ap_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
+
+ splx(s);
+ return (0);
+}
+
+void
+apcistart(tp)
+ struct tty *tp;
+{
+ struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
+ struct apciregs *apci = sc->sc_apci;
+ int s, c;
+
+ s = spltty();
+
+ if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
+ goto out;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ selwakeup(&tp->t_wsel);
+ }
+ if (apci->ap_lsr & LSR_TXRDY) {
+ tp->t_state |= TS_BUSY;
+ if (sc->sc_flags & APCI_HASFIFO) {
+ for (c = 0; c < 16 && tp->t_outq.c_cc; ++c)
+ apci->ap_data = getc(&tp->t_outq);
+ } else
+ apci->ap_data = getc(&tp->t_outq);
+ }
+
+ out:
+ splx(s);
+}
+
+/*
+ * Stop output on a line.
+ */
+/* ARGSUSED */
+int
+apcistop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY)
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ splx(s);
+ return (0);
+}
+
+int
+apcimctl(sc, bits, how)
+ struct apci_softc *sc;
+ int bits, how;
+{
+ struct apciregs *apci = sc->sc_apci;
+ int s;
+
+ s = spltty();
+
+ switch (how) {
+ case DMSET:
+ apci->ap_mcr = bits;
+ break;
+
+ case DMBIS:
+ apci->ap_mcr |= bits;
+ break;
+
+ case DMBIC:
+ apci->ap_mcr &= ~bits;
+ break;
+
+ case DMGET:
+ bits = apci->ap_msr;
+ break;
+ }
+
+ splx(s);
+ return (bits);
+}
+
+void
+apciinit(apci, rate)
+ struct apciregs *apci;
+ int rate;
+{
+ int s;
+ short stat;
+
+ s = splhigh();
+
+ rate = ttspeedtab(rate, apcispeedtab);
+
+ apci->ap_cfcr = CFCR_DLAB;
+ apci->ap_data = rate & 0xff;
+ apci->ap_ier = (rate >> 8) & 0xff;
+ apci->ap_cfcr = CFCR_8BITS;
+ apci->ap_ier = IER_ERXRDY | IER_ETXRDY;
+ apci->ap_fifo =
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1;
+ apci->ap_mcr = MCR_DTR | MCR_RTS;
+ delay(100);
+ stat = apci->ap_iir;
+ splx(s);
+}
+
+void
+apcitimeout(arg)
+ void *arg;
+{
+ struct apci_softc *sc = arg;
+ int ferr, perr, oflow, s;
+
+ if (sc->sc_tty == NULL ||
+ (sc->sc_tty->t_state & TS_ISOPEN) == 0)
+ return;
+
+ /* Log any errors. */
+ if (sc->sc_ferr || sc->sc_perr || sc->sc_oflow) {
+ s = spltty(); /* XXX necessary? */
+ ferr = sc->sc_ferr;
+ perr = sc->sc_perr;
+ oflow = sc->sc_oflow;
+ sc->sc_ferr = sc->sc_perr = sc->sc_oflow = 0;
+ splx(s);
+ sc->sc_toterr += ferr + perr + oflow;
+ log(LOG_WARNING,
+ "%s: %d frame, %d parity, %d overflow, %d total errors\n",
+ sc->sc_dev.dv_xname, ferr, perr, oflow, sc->sc_toterr);
+ }
+
+ timeout_add(&sc->sc_timeout, hz);
+}
+
+/*
+ * The following routines are required for the APCI to act as the console.
+ */
+
+void
+apcicnprobe(cp)
+ struct consdev *cp;
+{
+ volatile u_int8_t *frodoregs;
+
+ /* locate the major number */
+ for (apcimajor = 0; apcimajor < nchrdev; apcimajor++)
+ if (cdevsw[apcimajor].d_open == apciopen)
+ break;
+
+ /* initialize the required fields */
+ cp->cn_dev = makedev(apcimajor, 0); /* XXX */
+ cp->cn_pri = CN_DEAD;
+
+ /* Abort early if console is already forced. */
+ if (conforced)
+ return;
+
+ /*
+ * The APCI can only be a console on a 425e; on other 4xx
+ * models, the "first" serial port is mapped to the DCA
+ * at select code 9. See frodo.c for the autoconfiguration
+ * version of this check.
+ */
+ if (machineid != HP_425 || mmuid != MMUID_425_E)
+ return;
+
+ /*
+ * Check the service switch. On the 425e, this is a physical
+ * switch, unlike other frodo-based machines, so we can use it
+ * as a serial vs internal video selector, since the PROM can not
+ * be configured for serial console.
+ */
+ frodoregs = (volatile u_int8_t *)IIOV(FRODO_BASE);
+ if (badaddr((caddr_t)frodoregs) == 0 &&
+ !ISSET(frodoregs[FRODO_IISR], FRODO_IISR_SERVICE)) {
+ cp->cn_pri = CN_REMOTE;
+ conforced = 1;
+ conscode = -2; /* XXX */
+ } else {
+ cp->cn_pri = CN_NORMAL;
+ }
+
+ /*
+ * If our priority is higher than the currently-remembered
+ * console, install ourselves.
+ */
+ if (((cn_tab == NULL) || (cp->cn_pri > cn_tab->cn_pri)) || conforced)
+ cn_tab = cp;
+}
+
+/* ARGSUSED */
+void
+apcicninit(cp)
+ struct consdev *cp;
+{
+
+ /*
+ * We are not interested by the second console pass.
+ */
+ if (consolepass != 0)
+ return;
+
+ apci_cn = (struct apciregs *)IIOV(FRODO_BASE + FRODO_APCI_OFFSET(1));
+ apciinit(apci_cn, apcidefaultrate);
+ apciconsinit = 1;
+}
+
+/* ARGSUSED */
+int
+apcicngetc(dev)
+ dev_t dev;
+{
+ u_char stat;
+ int c, s;
+
+ s = splhigh();
+ while (((stat = apci_cn->ap_lsr) & LSR_RXRDY) == 0)
+ ;
+ c = apci_cn->ap_data;
+
+ /* clear any interrupts generated by this transmission */
+ stat = apci_cn->ap_iir;
+ splx(s);
+ return (c);
+}
+
+/* ARGSUSED */
+void
+apcicnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int timo;
+ u_char stat;
+ int s;
+
+ s = splhigh();
+
+ if (apciconsinit == 0) {
+ apciinit(apci_cn, apcidefaultrate);
+ apciconsinit = 1;
+ }
+
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
+ ;
+
+ apci_cn->ap_data = c & 0xff;
+
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
+ ;
+
+ /* clear any interrupts generated by this transmission */
+ stat = apci_cn->ap_iir;
+ splx(s);
+}
diff --git a/sys/arch/hp300/dev/apci_subr.c b/sys/arch/hp300/dev/apci_subr.c
new file mode 100644
index 00000000000..dafff24c2f6
--- /dev/null
+++ b/sys/arch/hp300/dev/apci_subr.c
@@ -0,0 +1,126 @@
+/* $OpenBSD: apci_subr.c,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1997 Michael Smith. All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)dca.c 8.2 (Berkeley) 1/12/94
+ */
+
+/*
+ * Routines shared by the apci and dnkbd drivers.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/tty.h>
+#include <sys/kernel.h>
+
+#include <hp300/dev/apcireg.h>
+#include <hp300/dev/apcivar.h>
+#include <hp300/dev/dcareg.h>
+
+const struct speedtab apcispeedtab[] = {
+ { 0, 0 },
+ { 50, APCIBRD(50) },
+ { 75, APCIBRD(75) },
+ { 110, APCIBRD(110) },
+ { 134, APCIBRD(134) },
+ { 150, APCIBRD(150) },
+ { 200, APCIBRD(200) },
+ { 300, APCIBRD(300) },
+ { 600, APCIBRD(600) },
+ { 1200, APCIBRD(1200) },
+ { 1800, APCIBRD(1800) },
+ { 2400, APCIBRD(2400) },
+ { 4800, APCIBRD(4800) },
+ { 9600, APCIBRD(9600) },
+ { 19200, APCIBRD(19200) },
+ { 38400, APCIBRD(38400) },
+ { -1, -1 },
+};
+
+int
+apciinit(struct apciregs *apci, u_int16_t rate, u_int16_t cfcr)
+{
+ int s, stat;
+
+ s = splhigh();
+
+ rate = ttspeedtab(rate, apcispeedtab);
+
+ apci->ap_cfcr = CFCR_DLAB;
+ apci->ap_data = rate & 0xff;
+ apci->ap_ier = (rate >> 8) & 0xff;
+ apci->ap_cfcr = cfcr;
+ apci->ap_ier = IER_ERXRDY | IER_ETXRDY;
+ apci->ap_fifo =
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1;
+ apci->ap_mcr = MCR_DTR | MCR_RTS;
+ delay(100);
+ stat = apci->ap_iir;
+ splx(s);
+
+ return (stat);
+}
diff --git a/sys/arch/hp300/dev/apcivar.h b/sys/arch/hp300/dev/apcivar.h
new file mode 100644
index 00000000000..d72bfcbe2d1
--- /dev/null
+++ b/sys/arch/hp300/dev/apcivar.h
@@ -0,0 +1,72 @@
+/* $OpenBSD: apcivar.h,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1997 Michael Smith. All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)dca.c 8.2 (Berkeley) 1/12/94
+ */
+
+int apciinit(struct apciregs *, u_int16_t, u_int16_t);
+extern const struct speedtab apcispeedtab[];
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);
+}
diff --git a/sys/arch/hp300/dev/dnkbdmap.c b/sys/arch/hp300/dev/dnkbdmap.c
new file mode 100644
index 00000000000..04165d1f916
--- /dev/null
+++ b/sys/arch/hp300/dev/dnkbdmap.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: dnkbdmap.c,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+/*
+ * Copyright (c) 2005, Miodrag Vallat
+ *
+ * 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 ``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 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.
+ */
+
+#include <sys/types.h>
+
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+#include <hp300/dev/dnkbdmap.h>
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+#include <dev/wscons/wskbdraw.h>
+
+/*
+ * Translate Domain keycodes to US keyboard XT scancodes, for proper
+ * X11-over-wsmux operation.
+ */
+const u_int8_t dnkbd_raw[0x80] = {
+ RAWKEY_Null,
+ RAWKEY_Null, /* 01 Ins Mark */
+ RAWKEY_Null, /* 02 Line Del */
+ RAWKEY_Null, /* 03 Char Del */
+ RAWKEY_f10, /* 04 f0 */
+ RAWKEY_f1,
+ RAWKEY_f2,
+ RAWKEY_f3,
+ RAWKEY_f4,
+ RAWKEY_f5,
+ RAWKEY_f6,
+ RAWKEY_f7,
+ RAWKEY_f8,
+ RAWKEY_f9,
+ RAWKEY_Null, /* 0e Again */
+ RAWKEY_Null, /* 0f Read */
+ RAWKEY_Null, /* 10 Save Edit */
+ RAWKEY_Null, /* 11 Abort Exit */
+ RAWKEY_Hold_Screen, /* 12 Help Hold */
+ RAWKEY_Null, /* 13 Cut Copy */
+ RAWKEY_Null, /* 14 Undo Paste */
+ RAWKEY_Null, /* 15 Move Grow */
+ RAWKEY_Null,
+ RAWKEY_Escape,
+ RAWKEY_1,
+ RAWKEY_2,
+ RAWKEY_3,
+ RAWKEY_4,
+ RAWKEY_5,
+ RAWKEY_6,
+ RAWKEY_7,
+ RAWKEY_8,
+ RAWKEY_9,
+ RAWKEY_0,
+ RAWKEY_minus,
+ RAWKEY_equal,
+ RAWKEY_grave,
+ RAWKEY_BackSpace,
+ RAWKEY_Null,
+ RAWKEY_Null, /* 27 Left Edge */
+ RAWKEY_Null, /* 28 Shell Cmd */
+ RAWKEY_Null, /* 29 Right Edge */
+ RAWKEY_Null,
+ RAWKEY_Null,
+ RAWKEY_Tab,
+ RAWKEY_q,
+ RAWKEY_w,
+ RAWKEY_e,
+ RAWKEY_r,
+ RAWKEY_t,
+ RAWKEY_y,
+ RAWKEY_u,
+ RAWKEY_i,
+ RAWKEY_o,
+ RAWKEY_p,
+ RAWKEY_bracketleft,
+ RAWKEY_bracketright,
+ RAWKEY_Null,
+ RAWKEY_Delete,
+ RAWKEY_Null,
+ RAWKEY_KP_Home,
+ RAWKEY_KP_Up,
+ RAWKEY_KP_Prior,
+ RAWKEY_KP_Add,
+ RAWKEY_Null, /* 40 Left Box */
+ RAWKEY_Up,
+ RAWKEY_Null, /* 42 Right Box */
+ RAWKEY_Control_L,
+ RAWKEY_Null,
+ RAWKEY_Null,
+ RAWKEY_a,
+ RAWKEY_s,
+ RAWKEY_d,
+ RAWKEY_f,
+ RAWKEY_g,
+ RAWKEY_h,
+ RAWKEY_j,
+ RAWKEY_k,
+ RAWKEY_l,
+ RAWKEY_semicolon,
+ RAWKEY_apostrophe,
+ RAWKEY_Null,
+ RAWKEY_Return,
+ RAWKEY_backslash,
+ RAWKEY_Null,
+ RAWKEY_KP_Left,
+ RAWKEY_KP_Begin,
+ RAWKEY_KP_Right,
+ RAWKEY_KP_Subtract,
+ RAWKEY_Left,
+ RAWKEY_Null, /* 5a Next Wndw */
+ RAWKEY_Right,
+ RAWKEY_Null,
+ RAWKEY_Null, /* 5d Rept */
+ RAWKEY_Shift_L,
+ RAWKEY_Null,
+ RAWKEY_z,
+ RAWKEY_x,
+ RAWKEY_c,
+ RAWKEY_v,
+ RAWKEY_b,
+ RAWKEY_n,
+ RAWKEY_m,
+ RAWKEY_comma,
+ RAWKEY_period,
+ RAWKEY_slash,
+ RAWKEY_Shift_R,
+ RAWKEY_Null,
+ RAWKEY_Null, /* 6c Pop */
+ RAWKEY_Null,
+ RAWKEY_KP_End,
+ RAWKEY_KP_Down,
+ RAWKEY_KP_Next,
+ RAWKEY_Null,
+ RAWKEY_Null, /* 72 Top Box */
+ RAWKEY_Down,
+ RAWKEY_Null, /* 74 Bottom Box */
+ RAWKEY_Alt_L,
+ RAWKEY_space,
+ RAWKEY_Alt_R,
+ RAWKEY_Null,
+ RAWKEY_KP_Insert,
+ RAWKEY_Null,
+ RAWKEY_KP_Delete,
+ RAWKEY_KP_Enter,
+ RAWKEY_Null,
+ RAWKEY_Caps_Lock,
+ RAWKEY_Null
+};
+#endif
+
+#define KC(n) KS_KEYCODE(n)
+
+const keysym_t dnkbd_keydesc_us[] = {
+/* pos command normal shifted */
+ /* 01 Ins Mark */
+ /* 02 Line Del */
+ /* 03 Char Del */
+ KC(0x04), KS_f10,
+ KC(0x05), KS_f1,
+ KC(0x06), KS_f2,
+ KC(0x07), KS_f3,
+ KC(0x08), KS_f4,
+ KC(0x09), KS_f5,
+ KC(0x0a), KS_f6,
+ KC(0x0b), KS_f7,
+ KC(0x0c), KS_f8,
+ KC(0x0d), KS_f9,
+ /* 0e Again */
+ /* 0f Read */
+ /* 10 Save Edit */
+ /* 11 Abort Exit */
+ KC(0x12), KS_Hold_Screen,
+ /* 13 Cut Copy */
+ /* 14 Undo Paste */
+ /* 15 Move Grow */
+ KC(0x17), KS_Cmd_Debugger, KS_Escape,
+ KC(0x18), KS_1, KS_exclam,
+ KC(0x19), KS_2, KS_at,
+ KC(0x1a), KS_3, KS_numbersign,
+ KC(0x1b), KS_4, KS_dollar,
+ KC(0x1c), KS_5, KS_percent,
+ KC(0x1d), KS_6, KS_asciicircum,
+ KC(0x1e), KS_7, KS_ampersand,
+ KC(0x1f), KS_8, KS_asterisk,
+ KC(0x20), KS_9, KS_parenleft,
+ KC(0x21), KS_0, KS_parenright,
+ KC(0x22), KS_minus, KS_underscore,
+ KC(0x23), KS_equal, KS_plus,
+ KC(0x24), KS_grave, KS_asciitilde,
+ KC(0x25), KS_Cmd_ResetEmul, KS_Delete, /* backspace */
+ KC(0x27), KS_Home,
+ /* 28 Shell Cmd */
+ KC(0x29), KS_End,
+ KC(0x2c), KS_Tab,
+ KC(0x2d), KS_q,
+ KC(0x2e), KS_w,
+ KC(0x2f), KS_e,
+ KC(0x30), KS_r,
+ KC(0x31), KS_t,
+ KC(0x32), KS_y,
+ KC(0x33), KS_u,
+ KC(0x34), KS_i,
+ KC(0x35), KS_o,
+ KC(0x36), KS_p,
+ KC(0x37), KS_bracketleft, KS_braceleft,
+ KC(0x38), KS_bracketright,KS_braceright,
+ KC(0x3a), KS_Delete,
+ KC(0x3c), KS_KP_7,
+ KC(0x3d), KS_KP_8,
+ KC(0x3e), KS_KP_9,
+ KC(0x3f), KS_KP_Add,
+ /* 40 Left Box */
+ KC(0x41), KS_Up,
+ /* 42 Right Box */
+ KC(0x43), KS_Cmd1, KS_Control_L,
+ KC(0x46), KS_a,
+ KC(0x47), KS_s,
+ KC(0x48), KS_d,
+ KC(0x49), KS_f,
+ KC(0x4a), KS_g,
+ KC(0x4b), KS_h,
+ KC(0x4c), KS_j,
+ KC(0x4d), KS_k,
+ KC(0x4e), KS_l,
+ KC(0x4f), KS_semicolon, KS_colon,
+ KC(0x50), KS_apostrophe, KS_quotedbl,
+ KC(0x52), KS_Return,
+ KC(0x53), KS_backslash, KS_bar,
+ KC(0x55), KS_KP_4,
+ KC(0x56), KS_KP_5,
+ KC(0x57), KS_KP_6,
+ KC(0x58), KS_KP_Subtract,
+ KC(0x59), KS_Left,
+ /* 5a Next Wndw */
+ KC(0x5b), KS_Right,
+ /* 5d Rept */
+ KC(0x5e), KS_Shift_L,
+ KC(0x60), KS_z,
+ KC(0x61), KS_x,
+ KC(0x62), KS_c,
+ KC(0x63), KS_v,
+ KC(0x64), KS_b,
+ KC(0x65), KS_n,
+ KC(0x66), KS_m,
+ KC(0x67), KS_comma, KS_less,
+ KC(0x68), KS_period, KS_greater,
+ KC(0x69), KS_slash, KS_question,
+ KC(0x6a), KS_Shift_R,
+ /* 6c Pop */
+ KC(0x6e), KS_KP_1,
+ KC(0x6f), KS_KP_2,
+ KC(0x70), KS_KP_3,
+ /* 72 Top Box */
+ KC(0x73), KS_Down,
+ /* 74 Bottom Box */
+ KC(0x75), KS_Cmd2, KS_Alt_L,
+ KC(0x76), KS_space,
+ KC(0x77), KS_Cmd2, KS_Alt_R,
+ KC(0x79), KS_KP_0,
+ KC(0x7b), KS_KP_Separator,
+ KC(0x7c), KS_KP_Enter,
+ KC(0x7e), KS_Caps_Lock
+};
+
+#define KBD_MAP(name, base, map) \
+ { name, base, sizeof(map) / sizeof(keysym_t), map }
+
+const struct wscons_keydesc dnkbd_keydesctab[] = {
+ KBD_MAP(KB_US, 0, dnkbd_keydesc_us),
+ { 0, 0, 0, 0 }
+};
diff --git a/sys/arch/hp300/dev/dnkbdmap.h b/sys/arch/hp300/dev/dnkbdmap.h
new file mode 100644
index 00000000000..90ffb046925
--- /dev/null
+++ b/sys/arch/hp300/dev/dnkbdmap.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: dnkbdmap.h,v 1.1 2005/04/22 11:59:11 miod Exp $ */
+/*
+ * Copyright (c) 2005, Miodrag Vallat
+ *
+ * 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 ``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 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.
+ */
+
+extern const struct wscons_keydesc dnkbd_keydesctab[];
+extern const u_int8_t dnkbd_raw[0x80];