summaryrefslogtreecommitdiff
path: root/sys/arch/hppa/gsc
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2003-01-31 22:50:20 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2003-01-31 22:50:20 +0000
commit06cc3bda31bd3d5f24d4ca8606317cf1ae361230 (patch)
tree3bd75b44de4c04b9c978382b04502970d240488f /sys/arch/hppa/gsc
parent588475d783a52d61a2bf8807a16cbba243f246d1 (diff)
Enter gsckbc, a driver for the ps/2-like input device ports found on many
hppa machines, and gsckbd, a driver for the ps/2-like keyboard. Both are derived from pckbc and pckbd, but the differences in port wiring and keyboard behaviour prevented the creation of a thin pckbc wrapper. Currently, only us and uk keyboard layouts are provided. The adventurous person can enable gsckb[cd], wsdisplay at sti and wskbd, but this will only work correctly on machines featuring a modern-prom sti graphics device, and a ps/2 keyboard port.
Diffstat (limited to 'sys/arch/hppa/gsc')
-rw-r--r--sys/arch/hppa/gsc/gsckbc.c1019
-rw-r--r--sys/arch/hppa/gsc/gsckbcreg.h64
-rw-r--r--sys/arch/hppa/gsc/gsckbd.c607
-rw-r--r--sys/arch/hppa/gsc/gsckbdmap.c169
-rw-r--r--sys/arch/hppa/gsc/gsckbdmap.h29
-rw-r--r--sys/arch/hppa/gsc/gsckbdvar.h29
6 files changed, 1917 insertions, 0 deletions
diff --git a/sys/arch/hppa/gsc/gsckbc.c b/sys/arch/hppa/gsc/gsckbc.c
new file mode 100644
index 00000000000..f598a3e8427
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbc.c
@@ -0,0 +1,1019 @@
+/* $OpenBSD: gsckbc.c,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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 MIND,
+ * 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.
+ */
+
+/*
+ * Derived from /sys/dev/ic/pckbd.c under the following terms:
+ * OpenBSD: pckbc.c,v 1.5 2002/06/09 00:58:03 nordin Exp
+ * NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp
+ */
+/*
+ * Copyright (c) 1998
+ * Matthias Drochner. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project
+ * by Matthias Drochner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the PS/2-like keyboard and mouse ports found on 712 and 715
+ * models, among others.
+ *
+ * Contrary to the ``pckbc'' port set found on other arches, the
+ * keyboard and mouse port are two separate entities on the snakes, and
+ * they are driven by a custom chip not 8042-compatible.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/autoconf.h>
+
+#include <hppa/dev/cpudevs.h>
+#include <hppa/gsc/gscbusvar.h>
+
+#include <hppa/gsc/gsckbcreg.h>
+#include <dev/ic/pckbcvar.h>
+
+#include <dev/pckbc/pckbdreg.h> /* constants for probe magic */
+#include <hppa/gsc/gsckbdvar.h>
+
+int gsckbc_match(struct device *, void *, void *);
+void gsckbc_attach(struct device *, struct device *, void *);
+
+struct gsckbc_softc {
+ struct pckbc_softc sc_pckbc;
+
+ int sc_irq;
+ void *sc_ih;
+ int sc_type;
+};
+
+struct cfattach gsckbc_ca = {
+ sizeof(struct gsckbc_softc), gsckbc_match, gsckbc_attach
+};
+
+struct cfdriver gsckbc_cd = {
+ NULL, "gsckbc", DV_DULL
+};
+
+void gsckbc_intr_establish(struct pckbc_softc *, pckbc_slot_t);
+
+#include "gsckbd.h"
+#if (NGSCKBD > 0)
+#include <dev/pckbc/pckbdvar.h>
+#endif
+
+/* descriptor for one device command */
+struct pckbc_devcmd {
+ TAILQ_ENTRY(pckbc_devcmd) next;
+ int flags;
+#define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
+#define KBC_CMDFLAG_SLOW 2
+ u_char cmd[4];
+ int cmdlen, cmdidx, retries;
+ u_char response[4];
+ int status, responselen, responseidx;
+};
+
+/* data per slave device */
+struct pckbc_slotdata {
+ int polling; /* don't read data port in interrupt handler */
+ TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
+ TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
+#define NCMD 5
+ struct pckbc_devcmd cmds[NCMD];
+};
+
+#define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
+/* Force polling mode behaviour for boot -a XXX */
+#define IS_POLLING(q) ((q)->polling || cold)
+
+void pckbc_init_slotdata(struct pckbc_slotdata *);
+int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
+int pckbc_submatch(struct device *, void *, void *);
+int pckbcprint(void *, const char *);
+
+int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
+int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t,
+ u_char);
+void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t,
+ struct pckbc_devcmd *);
+
+void pckbc_cleanqueue(struct pckbc_slotdata *);
+void pckbc_cleanup(void *);
+int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
+void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
+
+const char *pckbc_slot_names[] = { "kbd", "mouse" };
+
+#define KBC_DEVCMD_ACK 0xfa
+#define KBC_DEVCMD_RESEND 0xfe
+
+#define KBD_DELAY DELAY(8)
+
+int
+gsckbc_match(struct device *parent, void *match, void *aux)
+{
+ struct gsc_attach_args *ga = aux;
+ bus_space_handle_t ioh;
+ u_int8_t rv;
+
+ if (ga->ga_type.iodc_type != HPPA_TYPE_FIO ||
+ ga->ga_type.iodc_sv_model != HPPA_FIO_GPCIO)
+ return (0);
+
+ /* Map the i/o space. */
+ if (bus_space_map(ga->ga_ca.ca_iot, ga->ga_ca.ca_hpa,
+ KBMAPSIZE, 0, &ioh))
+ return 0;
+
+ rv = bus_space_read_1(ga->ga_ca.ca_iot, ioh, KBIDP);
+ bus_space_unmap(ga->ga_ca.ca_iot, ioh, KBMAPSIZE);
+
+ if (rv == PCKBC_KBD_SLOT || rv == PCKBC_AUX_SLOT)
+ return (1); /* keyboard or mouse port */
+
+ return (0);
+}
+
+/*
+ * Attachment helper functions
+ */
+
+/* state machine values */
+#define PROBE_SUCCESS 0
+#define PROBE_TIMEOUT 1
+#define PROBE_RETRANS 2
+#define PROBE_NOACK 3
+
+int probe_readtmo(bus_space_tag_t iot, bus_space_handle_t ioh, int *reply);
+int probe_readretry(bus_space_tag_t iot, bus_space_handle_t ioh, int *reply);
+int probe_sendtmo(bus_space_tag_t iot, bus_space_handle_t ioh, int cmdbyte);
+int probe_sendack(bus_space_tag_t iot, bus_space_handle_t ioh, int cmdbyte);
+int probe_ident(bus_space_tag_t iot, bus_space_handle_t ioh);
+
+#define PROBE_TRIES 1000
+
+int
+probe_readtmo(bus_space_tag_t iot, bus_space_handle_t ioh, int *reply)
+{
+ int numtries = PROBE_TRIES;
+
+ while (numtries--) {
+ if (bus_space_read_1(iot, ioh, KBSTATP) &
+ (KBS_DIB | KBS_TERR | KBS_PERR))
+ break;
+ DELAY(500);
+ }
+
+ if (numtries <= 0)
+ return (PROBE_TIMEOUT);
+
+ if (bus_space_read_1(iot, ioh, KBSTATP) & (KBS_PERR | KBS_TERR)) {
+ if (!(bus_space_read_1(iot, ioh, KBSTATP) & KBS_DIB)) {
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ return (PROBE_TIMEOUT);
+ }
+
+ *reply = bus_space_read_1(iot, ioh, KBDATAP);
+ if (!(bus_space_read_1(iot, ioh, KBSTATP) & KBS_DIB)) {
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ if (probe_sendtmo(iot, ioh, KBR_RESEND))
+ return (PROBE_TIMEOUT);
+ else
+ return (PROBE_RETRANS);
+ } else
+ return (PROBE_SUCCESS);
+ } else {
+ *reply = bus_space_read_1(iot, ioh, KBDATAP);
+ return (PROBE_SUCCESS);
+ }
+}
+
+int
+probe_readretry(bus_space_tag_t iot, bus_space_handle_t ioh, int *reply)
+{
+ int read_status;
+ int retrans = KB_MAX_RETRANS;
+
+ do {
+ read_status = probe_readtmo(iot, ioh, reply);
+ } while ((read_status == PROBE_RETRANS) && retrans--);
+
+ return (read_status);
+}
+
+int
+probe_sendtmo(bus_space_tag_t iot, bus_space_handle_t ioh, int cmdbyte)
+{
+ int numtries = PROBE_TRIES;
+
+ while (numtries--) {
+ if ((bus_space_read_1(iot, ioh, KBSTATP) & KBS_OCMD) == 0)
+ break;
+ DELAY(500);
+ }
+
+ if (bus_space_read_1(iot, ioh, KBSTATP) & KBS_OCMD)
+ return (1);
+
+ bus_space_write_1(iot, ioh, KBDATAP, cmdbyte);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ return (0);
+}
+
+int
+probe_sendack(bus_space_tag_t iot, bus_space_handle_t ioh, int cmdbyte)
+{
+ int retranscount;
+ int reply;
+
+ for (retranscount = 0; retranscount < KB_MAX_RETRANS; retranscount++) {
+ if (probe_sendtmo(iot, ioh, cmdbyte))
+ return (PROBE_TIMEOUT);
+ if (probe_readretry(iot, ioh, &reply))
+ return (PROBE_TIMEOUT);
+
+ switch (reply) {
+ case KBR_ACK:
+ return (PROBE_SUCCESS);
+ case KBR_RESEND:
+ break;
+ default:
+ return (PROBE_NOACK);
+ }
+ }
+ return (PROBE_TIMEOUT);
+
+}
+
+int
+probe_ident(bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+ int status;
+
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ DELAY(0x20000); /* XXX why 0x? */
+ bus_space_write_1(iot, ioh, KBCMDP, 0);
+ DELAY(20000);
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_DIAG);
+ DELAY(20000);
+
+ status = probe_sendack(iot, ioh, KBC_DISABLE);
+ switch (status) {
+ case PROBE_TIMEOUT:
+ if (bus_space_read_1(iot, ioh, KBSTATP) & KBS_OCMD) {
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ }
+ return (-1);
+ case PROBE_NOACK:
+ return (-1);
+ }
+
+ if (probe_sendack(iot, ioh, KBC_ID) != PROBE_SUCCESS)
+ return (-1);
+
+ if (probe_readretry(iot, ioh, &status))
+ return (-1);
+
+ switch (status) {
+ case KBR_MOUSE_ID:
+ return PCKBC_AUX_SLOT;
+ case KBR_KBD_ID1:
+ if (probe_readretry(iot, ioh, &status))
+ return (-1);
+ if (status == KBR_KBD_ID2) {
+ if (probe_sendack(iot, ioh, KBC_ENABLE) ==
+ PROBE_TIMEOUT) {
+ bus_space_write_1(iot, ioh, KBRESETP, 0);
+ bus_space_write_1(iot, ioh, KBCMDP,
+ KBCP_ENABLE);
+ }
+ return PCKBC_KBD_SLOT;
+ }
+ }
+ return (-1);
+}
+
+void
+gsckbc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gsc_attach_args *ga = aux;
+ struct gsckbc_softc *gsc = (void *)self;
+ struct pckbc_softc *sc = &gsc->sc_pckbc;
+ struct pckbc_internal *t;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int ident;
+
+ iot = ga->ga_ca.ca_iot;
+ gsc->sc_irq = ga->ga_ca.ca_irq;
+
+ if (bus_space_map(iot, ga->ga_ca.ca_hpa, KBMAPSIZE, 0, &ioh))
+ panic("gsckbc_attach: couldn't map port");
+
+ gsc->sc_type = bus_space_read_1(iot, ioh, KBIDP);
+
+ switch (gsc->sc_type) {
+ case PCKBC_KBD_SLOT:
+ case PCKBC_AUX_SLOT:
+ break;
+ default:
+ printf(": unknown port type %x\n", gsc->sc_type);
+ /* play nice and don't really attach. */
+ bus_space_unmap(iot, ioh, KBMAPSIZE);
+ return;
+ }
+
+ sc->intr_establish = gsckbc_intr_establish;
+
+ t = malloc(sizeof(struct pckbc_internal), M_DEVBUF, M_WAITOK);
+ bzero(t, sizeof(struct pckbc_internal));
+ t->t_iot = iot;
+ /* XXX it does not make sense to only map two ports here */
+ t->t_ioh_d = t->t_ioh_c = ioh;
+ t->t_addr = ga->ga_ca.ca_hpa;
+ t->t_sc = sc;
+ timeout_set(&t->t_cleanup, pckbc_cleanup, t);
+ sc->id = t;
+
+ printf("\n");
+
+ /*
+ * Reset port and probe device, if plugged
+ */
+ ident = probe_ident(iot, ioh);
+ if (ident != gsc->sc_type) {
+ /* don't whine for unplugged ports */
+ if (ident != -1)
+ printf("%s: expecting device type %d, got %d\n",
+ sc->sc_dv.dv_xname, gsc->sc_type, ident);
+ } else {
+#if (NGSCKBD > 0)
+ if (gsc->sc_type == PCKBC_KBD_SLOT)
+ gsckbd_cnattach(t, PCKBC_KBD_SLOT);
+#endif
+ pckbc_attach_slot(sc, gsc->sc_type);
+ }
+}
+
+void
+gsckbc_intr_establish(struct pckbc_softc *sc, pckbc_slot_t slot)
+{
+ struct gsckbc_softc *gsc = (void *)sc;
+
+ gsc->sc_ih = gsc_intr_establish(
+ (struct gsc_softc *)sc->sc_dv.dv_parent,
+ IPL_TTY, gsc->sc_irq, pckbcintr, sc, &sc->sc_dv);
+}
+
+/*
+ * pckbc-like interfaces
+ */
+
+int
+pckbc_wait_output(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ u_int i;
+
+ for (i = 100000; i; i--) {
+ if ((bus_space_read_1(iot, ioh, KBSTATP) & KBS_OCMD)) {
+ KBD_DELAY;
+ } else
+ return (1);
+ }
+ return (0);
+}
+
+int
+pckbc_send_cmd(iot, ioh, val)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ u_char val;
+{
+ if (!pckbc_wait_output(iot, ioh))
+ return (0);
+ bus_space_write_1(iot, ioh, KBOUTP, val);
+ bus_space_write_1(iot, ioh, KBCMDP, KBCP_ENABLE);
+ return (1);
+}
+
+/* XXX logic */
+int
+pckbc_poll_data1(iot, ioh, ioh_c, slot, checkaux)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh, ioh_c;
+ pckbc_slot_t slot;
+ int checkaux; /* ignored on hppa */
+{
+ int i;
+ u_char stat;
+
+ /* if 1 port read takes 1us (?), this polls for 100ms */
+ for (i = 100000; i; i--) {
+ stat = bus_space_read_1(iot, ioh, KBSTATP);
+ if (stat & KBS_DIB) {
+ KBD_DELAY;
+ return bus_space_read_1(iot, ioh, KBDATAP);
+ }
+ }
+ return (-1);
+}
+
+int
+pckbc_send_devcmd(t, slot, val)
+ struct pckbc_internal *t;
+ pckbc_slot_t slot;
+ u_char val;
+{
+ return pckbc_send_cmd(t->t_iot, t->t_ioh_d, val);
+}
+
+int
+pckbc_submatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct pckbc_attach_args *pa = aux;
+
+ if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
+ cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
+ return (0);
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+int
+pckbc_attach_slot(sc, slot)
+ struct pckbc_softc *sc;
+ pckbc_slot_t slot;
+{
+ struct pckbc_internal *t = sc->id;
+ struct pckbc_attach_args pa;
+ int found;
+
+ pa.pa_tag = t;
+ pa.pa_slot = slot;
+ found = (config_found_sm((struct device *)sc, &pa,
+ pckbcprint, pckbc_submatch) != NULL);
+
+ if (found && !t->t_slotdata[slot]) {
+ t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata),
+ M_DEVBUF, M_NOWAIT);
+ if (t->t_slotdata[slot] == NULL)
+ return 0;
+ pckbc_init_slotdata(t->t_slotdata[slot]);
+ }
+ return (found);
+}
+
+int
+pckbcprint(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+#if 0 /* hppa having devices for each slot, this is barely useful */
+ struct pckbc_attach_args *pa = aux;
+
+ if (!pnp)
+ printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
+#endif
+ return (QUIET);
+}
+
+void
+pckbc_init_slotdata(q)
+ struct pckbc_slotdata *q;
+{
+ int i;
+ TAILQ_INIT(&q->cmdqueue);
+ TAILQ_INIT(&q->freequeue);
+
+ for (i = 0; i < NCMD; i++) {
+ TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
+ }
+ q->polling = 0;
+}
+
+void
+pckbc_flush(self, slot)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+{
+ struct pckbc_internal *t = self;
+
+ pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, 0);
+}
+
+int
+pckbc_poll_data(self, slot)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+{
+ struct pckbc_internal *t = self;
+ struct pckbc_slotdata *q = t->t_slotdata[slot];
+ int c;
+
+ c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, 0);
+ if (c != -1 && q && CMD_IN_QUEUE(q)) {
+ /* we jumped into a running command - try to
+ deliver the response */
+ if (pckbc_cmdresponse(t, slot, c))
+ return (-1);
+ }
+ return (c);
+}
+
+void
+pckbc_slot_enable(self, slot, on)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ int on;
+{
+ /* can't enable slots here as they are different devices */
+}
+
+void
+pckbc_set_poll(self, slot, on)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ int on;
+{
+ struct pckbc_internal *t = (struct pckbc_internal *)self;
+
+ t->t_slotdata[slot]->polling = on;
+
+ if (!on) {
+ int s;
+
+ /*
+ * If disabling polling on a device that's been configured,
+ * make sure there are no bytes left in the FIFO, holding up
+ * the interrupt line. Otherwise we won't get any further
+ * interrupts.
+ */
+ if (t->t_sc) {
+ s = spltty();
+ pckbcintr(t->t_sc);
+ splx(s);
+ }
+ }
+}
+
+/*
+ * Pass command to device, poll for ACK and data.
+ * to be called at spltty()
+ */
+void
+pckbc_poll_cmd1(t, slot, cmd)
+ struct pckbc_internal *t;
+ pckbc_slot_t slot;
+ struct pckbc_devcmd *cmd;
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh = t->t_ioh_d;
+ int i, c = 0;
+
+ while (cmd->cmdidx < cmd->cmdlen) {
+ if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
+ printf("pckbc_cmd: send error\n");
+ cmd->status = EIO;
+ return;
+ }
+ for (i = 10; i; i--) { /* 1s ??? */
+ c = pckbc_poll_data1(iot, ioh, ioh, slot, 0);
+ if (c != -1)
+ break;
+ }
+
+ if (c == KBC_DEVCMD_ACK) {
+ cmd->cmdidx++;
+ continue;
+ }
+ if (c == KBC_DEVCMD_RESEND) {
+#ifdef PCKBCDEBUG
+ printf("pckbc_cmd: RESEND\n");
+#endif
+ if (cmd->retries++ < KB_MAX_RETRANS)
+ continue;
+ else {
+#ifdef PCKBCDEBUG
+ printf("pckbc: cmd failed\n");
+#endif
+ cmd->status = EIO;
+ return;
+ }
+ }
+ if (c == -1) {
+#ifdef PCKBCDEBUG
+ printf("pckbc_cmd: timeout\n");
+#endif
+ cmd->status = EIO;
+ return;
+ }
+#ifdef PCKBCDEBUG
+ printf("pckbc_cmd: lost 0x%x\n", c);
+#endif
+ }
+
+ while (cmd->responseidx < cmd->responselen) {
+ if (cmd->flags & KBC_CMDFLAG_SLOW)
+ i = 100; /* 10s ??? */
+ else
+ i = 10; /* 1s ??? */
+ while (i--) {
+ c = pckbc_poll_data1(iot, ioh, ioh, slot, 0);
+ if (c != -1)
+ break;
+ }
+ if (c == -1) {
+#ifdef PCKBCDEBUG
+ printf("pckbc_cmd: no data\n");
+#endif
+ cmd->status = ETIMEDOUT;
+ return;
+ } else
+ cmd->response[cmd->responseidx++] = c;
+ }
+}
+
+/* for use in autoconfiguration */
+int
+pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ u_char *cmd;
+ int len, responselen;
+ u_char *respbuf;
+ int slow;
+{
+ struct pckbc_internal *t = self;
+ struct pckbc_devcmd nc;
+
+ if ((len > 4) || (responselen > 4))
+ return (EINVAL);
+
+ bzero(&nc, sizeof(nc));
+ bcopy(cmd, nc.cmd, len);
+ nc.cmdlen = len;
+ nc.responselen = responselen;
+ nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
+
+ pckbc_poll_cmd1(t, slot, &nc);
+
+ if (nc.status == 0 && respbuf)
+ bcopy(nc.response, respbuf, responselen);
+
+ return (nc.status);
+}
+
+/*
+ * Clean up a command queue, throw away everything.
+ */
+void
+pckbc_cleanqueue(q)
+ struct pckbc_slotdata *q;
+{
+ struct pckbc_devcmd *cmd;
+#ifdef PCKBCDEBUG
+ int i;
+#endif
+
+ while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
+ TAILQ_REMOVE(&q->cmdqueue, cmd, next);
+#ifdef PCKBCDEBUG
+ printf("pckbc_cleanqueue: removing");
+ for (i = 0; i < cmd->cmdlen; i++)
+ printf(" %02x", cmd->cmd[i]);
+ printf("\n");
+#endif
+ TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
+ }
+}
+
+/*
+ * Timeout error handler: clean queues and data port.
+ * XXX could be less invasive.
+ */
+void
+pckbc_cleanup(self)
+ void *self;
+{
+ struct pckbc_internal *t = self;
+ int s;
+
+ printf("pckbc: command timeout\n");
+
+ s = spltty();
+
+ if (t->t_slotdata[PCKBC_KBD_SLOT])
+ pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
+ if (t->t_slotdata[PCKBC_AUX_SLOT])
+ pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
+
+ while (bus_space_read_1(t->t_iot, t->t_ioh_d, KBSTATP) & KBS_DIB) {
+ KBD_DELAY;
+ (void) bus_space_read_1(t->t_iot, t->t_ioh_d, KBDATAP);
+ }
+
+ /* reset KBC? */
+
+ splx(s);
+}
+
+/*
+ * Pass command to device during normal operation.
+ * to be called at spltty()
+ */
+void
+pckbc_start(t, slot)
+ struct pckbc_internal *t;
+ pckbc_slot_t slot;
+{
+ struct pckbc_slotdata *q = t->t_slotdata[slot];
+ struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
+
+ if (IS_POLLING(q)) {
+ do {
+ pckbc_poll_cmd1(t, slot, cmd);
+ if (cmd->status)
+ printf("pckbc_start: command error\n");
+
+ TAILQ_REMOVE(&q->cmdqueue, cmd, next);
+ if (cmd->flags & KBC_CMDFLAG_SYNC)
+ wakeup(cmd);
+ else {
+ timeout_del(&t->t_cleanup);
+ TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
+ }
+ cmd = TAILQ_FIRST(&q->cmdqueue);
+ } while (cmd);
+ return;
+ }
+
+ if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
+ printf("pckbc_start: send error\n");
+ /* XXX what now? */
+ return;
+ }
+}
+
+/*
+ * Handle command responses coming in asynchonously,
+ * return nonzero if valid response.
+ * to be called at spltty()
+ */
+int
+pckbc_cmdresponse(t, slot, data)
+ struct pckbc_internal *t;
+ pckbc_slot_t slot;
+ u_char data;
+{
+ struct pckbc_slotdata *q = t->t_slotdata[slot];
+ struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
+
+#ifdef DIAGNOSTIC
+ if (!cmd)
+ panic("pckbc_cmdresponse: no active command");
+#endif
+ if (cmd->cmdidx < cmd->cmdlen) {
+ if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
+ return (0);
+
+ if (data == KBC_DEVCMD_RESEND) {
+ if (cmd->retries++ < KB_MAX_RETRANS) {
+ /* try again last command */
+ goto restart;
+ } else {
+ printf("pckbc: cmd failed\n");
+ cmd->status = EIO;
+ /* dequeue */
+ }
+ } else {
+ if (++cmd->cmdidx < cmd->cmdlen)
+ goto restart;
+ if (cmd->responselen)
+ return (1);
+ /* else dequeue */
+ }
+ } else if (cmd->responseidx < cmd->responselen) {
+ cmd->response[cmd->responseidx++] = data;
+ if (cmd->responseidx < cmd->responselen)
+ return (1);
+ /* else dequeue */
+ } else
+ return (0);
+
+ /* dequeue: */
+ TAILQ_REMOVE(&q->cmdqueue, cmd, next);
+ if (cmd->flags & KBC_CMDFLAG_SYNC)
+ wakeup(cmd);
+ else {
+ timeout_del(&t->t_cleanup);
+ TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
+ }
+ if (!CMD_IN_QUEUE(q))
+ return (1);
+restart:
+ pckbc_start(t, slot);
+ return (1);
+}
+
+/*
+ * Put command into the device's command queue, return zero or errno.
+ */
+int
+pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ u_char *cmd;
+ int len, responselen, sync;
+ u_char *respbuf;
+{
+ struct pckbc_internal *t = self;
+ struct pckbc_slotdata *q = t->t_slotdata[slot];
+ struct pckbc_devcmd *nc;
+ int s, isactive, res = 0;
+
+ if ((len > 4) || (responselen > 4))
+ return (EINVAL);
+ s = spltty();
+ nc = TAILQ_FIRST(&q->freequeue);
+ if (nc) {
+ TAILQ_REMOVE(&q->freequeue, nc, next);
+ }
+ splx(s);
+ if (!nc)
+ return (ENOMEM);
+
+ bzero(nc, sizeof(*nc));
+ bcopy(cmd, nc->cmd, len);
+ nc->cmdlen = len;
+ nc->responselen = responselen;
+ nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
+
+ s = spltty();
+
+ if (IS_POLLING(q) && sync) {
+ /*
+ * XXX We should poll until the queue is empty.
+ * But we don't come here normally, so make
+ * it simple and throw away everything.
+ */
+ pckbc_cleanqueue(q);
+ }
+
+ isactive = CMD_IN_QUEUE(q);
+ TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
+ if (!isactive)
+ pckbc_start(t, slot);
+
+ if (IS_POLLING(q))
+ res = (sync ? nc->status : 0);
+ else if (sync) {
+ if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
+ TAILQ_REMOVE(&q->cmdqueue, nc, next);
+ pckbc_cleanup(t);
+ } else
+ res = nc->status;
+ } else
+ timeout_add(&t->t_cleanup, hz);
+
+ if (sync) {
+ if (respbuf)
+ bcopy(nc->response, respbuf, responselen);
+ TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
+ }
+
+ splx(s);
+
+ return (res);
+}
+
+void
+pckbc_set_inputhandler(self, slot, func, arg, name)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ pckbc_inputfcn func;
+ void *arg;
+ char *name;
+{
+ struct pckbc_internal *t = (struct pckbc_internal *)self;
+ struct pckbc_softc *sc = t->t_sc;
+
+ if (slot >= PCKBC_NSLOTS)
+ panic("pckbc_set_inputhandler: bad slot %d", slot);
+
+ (*sc->intr_establish)(sc, slot);
+
+ sc->inputhandler[slot] = func;
+ sc->inputarg[slot] = arg;
+ sc->subname[slot] = name;
+}
+
+int
+pckbcintr(vsc)
+ void *vsc;
+{
+ struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
+ struct gsckbc_softc *gsc = (void *)sc;
+ struct pckbc_internal *t = sc->id;
+ pckbc_slot_t slot;
+ struct pckbc_slotdata *q;
+ int served = 0, data;
+
+ while (bus_space_read_1(t->t_iot, t->t_ioh_d, KBSTATP) & KBS_DIB) {
+ served = 1;
+
+ slot = gsc->sc_type;
+ q = t->t_slotdata[slot];
+
+ if (!q) {
+ /* XXX do something for live insertion? */
+#ifdef PCKBCDEBUG
+ printf("pckbcintr: no dev for slot %d\n", slot);
+#endif
+ KBD_DELAY;
+ (void) bus_space_read_1(t->t_iot, t->t_ioh_d, KBDATAP);
+ continue;
+ }
+
+ if (IS_POLLING(q))
+ break; /* pckbc_poll_data() will get it */
+
+ KBD_DELAY;
+ data = bus_space_read_1(t->t_iot, t->t_ioh_d, KBDATAP);
+
+ if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
+ continue;
+
+ if (sc->inputhandler[slot])
+ (*sc->inputhandler[slot])(sc->inputarg[slot], data);
+#ifdef PCKBCDEBUG
+ else
+ printf("pckbcintr: slot %d lost %d\n", slot, data);
+#endif
+ }
+
+ return (served);
+}
diff --git a/sys/arch/hppa/gsc/gsckbcreg.h b/sys/arch/hppa/gsc/gsckbcreg.h
new file mode 100644
index 00000000000..b682f98a536
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbcreg.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: gsckbcreg.h,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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 MIND,
+ * 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.
+ */
+
+/*
+ * Register definitions for the GSC PS/2 compatible keyboard/mouse ports.
+ *
+ * These definitions attempt to match <dev/ic/i8042reg.h> names although the
+ * actual wiring is different.
+ */
+
+#define KBSTATP 12 /* controller status port (I) */
+#define KBS_DIB 0x01 /* data in buffer */
+#define KBS_OCMD 0x02 /* output buffer has command */
+#define KBS_PERR 0x04 /* parity error */
+#define KBS_TERR 0x08 /* transmission error */
+
+#define KBCMDP 8 /* controller port (O) */
+#define KBCP_ENABLE 0x01 /* enable device */
+#define KBCP_DIAG 0x20 /* diagnostic mode control */
+
+#define KBDATAP 4 /* data port (I) */
+#define KBOUTP 4 /* data port (O) */
+
+#define KBIDP 0 /* id port (I) */
+#define ID_KBD 0 /* slot is a keyboard port */
+#define ID_MOUSE 1 /* slot is a mouse port */
+
+#define KBRESETP 0 /* reset port (O) */
+
+#define KBMAPSIZE 16 /* size to bus_space_map() */
+
+/*
+ * Various command definitions not provided by the existing pckbc code.
+ */
+
+#define KBC_ID 0xF2 /* get device identifier */
+#define KBR_MOUSE_ID 0x00 /* mouse type */
+#define KBR_KBD_ID1 0xAB /* keyboard type */
+#define KBR_KBD_ID2 0x83
+
+#define KB_MAX_RETRANS 5 /* maximum number of command retrans attempts */
diff --git a/sys/arch/hppa/gsc/gsckbd.c b/sys/arch/hppa/gsc/gsckbd.c
new file mode 100644
index 00000000000..515983fde8d
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbd.c
@@ -0,0 +1,607 @@
+/* $OpenBSD: gsckbd.c,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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.
+ *
+ */
+
+/*
+ * Derived from /sys/dev/pckbc/pckbd.c under the following terms:
+ * OpenBSD: pckbd.c,v 1.4 2002/03/14 01:27:00 millert Exp
+ * NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp
+ */
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ *
+ * @(#)pccons.c 5.11 (Berkeley) 5/21/91
+ */
+
+/*
+ * A pckbd-like driver for the GSC keyboards found on various HP workstations.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/pckbcvar.h>
+
+#include <dev/pckbc/pckbdreg.h>
+#include <hppa/gsc/gsckbdvar.h>
+#include <hppa/gsc/gsckbdmap.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+struct gsckbd_internal {
+ int t_isconsole;
+ pckbc_tag_t t_kbctag;
+ pckbc_slot_t t_kbcslot;
+
+ int t_lastchar;
+ int t_extended;
+ int t_releasing;
+ int t_extended1;
+
+ struct gsckbd_softc *t_sc; /* back pointer */
+};
+
+struct gsckbd_softc {
+ struct device sc_dev;
+
+ struct gsckbd_internal *id;
+ int sc_enabled;
+
+ int sc_ledstate;
+
+ struct device *sc_wskbddev;
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ int rawkbd;
+#endif
+};
+
+static int gsckbd_is_console(pckbc_tag_t, pckbc_slot_t);
+
+int gsckbdprobe(struct device *, void *, void *);
+void gsckbdattach(struct device *, struct device *, void *);
+
+struct cfdriver gsckbd_cd = {
+ NULL, "gsckbd", DV_DULL
+};
+
+struct cfattach gsckbd_ca = {
+ sizeof(struct gsckbd_softc), gsckbdprobe, gsckbdattach,
+};
+
+int gsckbd_enable(void *, int);
+void gsckbd_set_leds(void *, int);
+int gsckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct wskbd_accessops gsckbd_accessops = {
+ gsckbd_enable,
+ gsckbd_set_leds,
+ gsckbd_ioctl,
+};
+
+void gsckbd_cngetc(void *, u_int *, int *);
+void gsckbd_cnpollc(void *, int);
+
+const struct wskbd_consops gsckbd_consops = {
+ gsckbd_cngetc,
+ gsckbd_cnpollc,
+ NULL
+};
+
+const struct wskbd_mapdata gsckbd_keymapdata = {
+ gsckbd_keydesctab, /* XXX */
+#ifdef GSCKBD_LAYOUT
+ GSCKBD_LAYOUT,
+#else
+ KB_US,
+#endif
+};
+
+int gsckbd_init(struct gsckbd_internal *, pckbc_tag_t, pckbc_slot_t,
+ int);
+void gsckbd_input(void *, int);
+
+static int gsckbd_decode(struct gsckbd_internal *, int,
+ u_int *, int *);
+static int gsckbd_led_encode(int);
+static int gsckbd_led_decode(int);
+
+struct gsckbd_internal gsckbd_consdata;
+
+static int
+gsckbd_is_console(tag, slot)
+ pckbc_tag_t tag;
+ pckbc_slot_t slot;
+{
+ return (gsckbd_consdata.t_isconsole &&
+ (tag == gsckbd_consdata.t_kbctag) &&
+ (slot == gsckbd_consdata.t_kbcslot));
+}
+
+/*
+ * these are both EXTREMELY bad jokes
+ */
+int
+gsckbdprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+ struct pckbc_attach_args *pa = aux;
+ u_char cmd[1], resp[1];
+ int res;
+
+ /*
+ * XXX There are rumours that a keyboard can be connected
+ * to the aux port as well. For me, this didn't work.
+ * For further experiments, allow it if explicitly
+ * wired in the config file.
+ */
+ if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
+ (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
+ return (0);
+
+ /* Flush any garbage. */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ /* Reset the keyboard. */
+ cmd[0] = KBC_RESET;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
+ if (res) {
+#ifdef DEBUG
+ printf("gsckbdprobe: reset error %d\n", res);
+#endif
+ /*
+ * There is probably no keyboard connected.
+ * Let the probe succeed if the keyboard is used
+ * as console input - it can be connected later.
+ */
+ return (gsckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
+ }
+ if (resp[0] != KBR_RSTDONE) {
+ printf("gsckbdprobe: reset response 0x%x\n", resp[0]);
+ return (0);
+ }
+
+ /*
+ * Some keyboards seem to leave a second ack byte after the reset.
+ * This is kind of stupid, but we account for them anyway by just
+ * flushing the buffer.
+ */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ return (2);
+}
+
+void
+gsckbdattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct gsckbd_softc *sc = (void *)self;
+ struct pckbc_attach_args *pa = aux;
+ int isconsole;
+ struct wskbddev_attach_args a;
+
+ printf("\n");
+
+ isconsole = gsckbd_is_console(pa->pa_tag, pa->pa_slot);
+
+ if (isconsole) {
+ sc->id = &gsckbd_consdata;
+ sc->sc_enabled = 1;
+ } else {
+ u_char cmd[1];
+
+ sc->id = malloc(sizeof(struct gsckbd_internal),
+ M_DEVBUF, M_WAITOK);
+ (void) gsckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
+
+ /* no interrupts until enabled */
+ cmd[0] = KBC_DISABLE;
+ (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
+ cmd, 1, 0, 0, 0);
+ sc->sc_enabled = 0;
+ }
+
+ sc->id->t_sc = sc;
+
+ pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
+ gsckbd_input, sc, sc->sc_dev.dv_xname);
+
+ a.console = isconsole;
+
+ a.keymap = &gsckbd_keymapdata;
+
+ a.accessops = &gsckbd_accessops;
+ a.accesscookie = sc;
+
+ /*
+ * Attach the wskbd, saving a handle to it.
+ * XXX XXX XXX
+ */
+ sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
+}
+
+int
+gsckbd_enable(v, on)
+ void *v;
+ int on;
+{
+ struct gsckbd_softc *sc = v;
+ u_char cmd[1];
+ int res;
+
+ if (on) {
+ if (sc->sc_enabled)
+ return (EBUSY);
+
+ pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
+
+ cmd[0] = KBC_ENABLE;
+ res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
+ cmd, 1, 0, 1, 0);
+ if (res) {
+ printf("gsckbd_enable: command error\n");
+ return (res);
+ }
+
+ sc->sc_enabled = 1;
+ } else {
+ if (sc->id->t_isconsole)
+ return (EBUSY);
+
+ cmd[0] = KBC_DISABLE;
+ res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
+ cmd, 1, 0, 1, 0);
+ if (res) {
+ printf("gsckbd_disable: command error\n");
+ return (res);
+ }
+
+ pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
+
+ sc->sc_enabled = 0;
+ }
+
+ return (0);
+}
+
+static int
+gsckbd_decode(id, datain, type, dataout)
+ struct gsckbd_internal *id;
+ int datain;
+ u_int *type;
+ int *dataout;
+{
+ int key;
+
+ if (datain == KBR_BREAK) {
+ id->t_releasing = 1; /* next keycode is a release */
+ return 0;
+ }
+
+ if (datain == KBR_EXTENDED0) {
+ id->t_extended = 0x80;
+ return 0;
+ } else if (datain == KBR_EXTENDED1) {
+ id->t_extended1 = 2;
+ return 0;
+ }
+
+ /*
+ * Map extended keys to codes 128-254
+ * Note that we do not use (datain & 0x7f) because function key
+ * F7 produces non-extended 0x83 code. Sucker.
+ */
+ key = datain | id->t_extended;
+ id->t_extended = 0;
+
+ /*
+ * process BREAK sequence (EXT1 14 77):
+ * map to (unused) code 7F
+ */
+ if (id->t_extended1 == 2 && datain == 0x14) {
+ id->t_extended1 = 1;
+ return 0;
+ } else if (id->t_extended1 == 1 && datain == 0x77) {
+ id->t_extended1 = 0;
+ key = 0x7f;
+ } else if (id->t_extended1 > 0) {
+ id->t_extended1 = 0;
+ }
+
+ if (id->t_releasing) {
+ id->t_releasing = 0;
+ *type = WSCONS_EVENT_KEY_UP;
+ *dataout = key;
+ id->t_lastchar = 0;
+ } else {
+ /* Always ignore typematic keys */
+ if (key == id->t_lastchar)
+ return 0;
+ *dataout = id->t_lastchar = key;
+ *type = WSCONS_EVENT_KEY_DOWN;
+ }
+
+ return 1;
+}
+
+int
+gsckbd_init(t, kbctag, kbcslot, console)
+ struct gsckbd_internal *t;
+ pckbc_tag_t kbctag;
+ pckbc_slot_t kbcslot;
+ int console;
+{
+ bzero(t, sizeof(struct gsckbd_internal));
+
+ t->t_isconsole = console;
+ t->t_kbctag = kbctag;
+ t->t_kbcslot = kbcslot;
+
+ return (0);
+}
+
+static int
+gsckbd_led_encode(led)
+ int led;
+{
+ int res;
+
+ res = 0;
+
+ if (led & WSKBD_LED_SCROLL)
+ res |= 0x01;
+ if (led & WSKBD_LED_NUM)
+ res |= 0x02;
+ if (led & WSKBD_LED_CAPS)
+ res |= 0x04;
+ return(res);
+}
+
+static int
+gsckbd_led_decode(led)
+ int led;
+{
+ int res;
+
+ res = 0;
+ if (led & 0x01)
+ res |= WSKBD_LED_SCROLL;
+ if (led & 0x02)
+ res |= WSKBD_LED_NUM;
+ if (led & 0x04)
+ res |= WSKBD_LED_CAPS;
+ return(res);
+}
+
+void
+gsckbd_set_leds(v, leds)
+ void *v;
+ int leds;
+{
+ struct gsckbd_softc *sc = v;
+ u_char cmd[2];
+
+ cmd[0] = KBC_MODEIND;
+ cmd[1] = gsckbd_led_encode(leds);
+ sc->sc_ledstate = cmd[1];
+
+ pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
+ cmd, 2, 0, 0, 0);
+}
+
+/*
+ * Got a console receive interrupt -
+ * the console processor wants to give us a character.
+ */
+void
+gsckbd_input(vsc, data)
+ void *vsc;
+ int data;
+{
+ struct gsckbd_softc *sc = vsc;
+ int type, key;
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ if (sc->rawkbd) {
+ char d = data;
+ wskbd_rawinput(sc->sc_wskbddev, &d, 1);
+ return;
+ }
+#endif
+ if (gsckbd_decode(sc->id, data, &type, &key))
+ wskbd_input(sc->sc_wskbddev, type, key);
+}
+
+int
+gsckbd_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct gsckbd_softc *sc = v;
+
+ switch (cmd) {
+ case WSKBDIO_GTYPE:
+ *(int *)data = WSKBD_TYPE_PC_XT;
+ return 0;
+ case WSKBDIO_SETLEDS:
+ {
+ char cmd[2];
+ int res;
+ cmd[0] = KBC_MODEIND;
+ cmd[1] = gsckbd_led_encode(*(int *)data);
+ sc->sc_ledstate = cmd[1];
+ res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
+ cmd, 2, 0, 1, 0);
+ return (res);
+ }
+ case WSKBDIO_GETLEDS:
+ *(int *)data = gsckbd_led_decode(sc->sc_ledstate);
+ return (0);
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ case WSKBDIO_SETMODE:
+ sc->rawkbd = (*(int *)data == WSKBD_RAW);
+ return (0);
+#endif
+ }
+ return -1;
+}
+
+int
+gsckbd_cnattach(kbctag, kbcslot)
+ pckbc_tag_t kbctag;
+ int kbcslot;
+{
+ char cmd[1];
+ int res;
+
+ res = gsckbd_init(&gsckbd_consdata, kbctag, kbcslot, 1);
+#if 0 /* we allow the console to be attached if no keyboard is present */
+ if (res)
+ return (res);
+#endif
+
+ /* Just to be sure. */
+ cmd[0] = KBC_ENABLE;
+ res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
+#if 0
+ if (res)
+ return (res);
+#endif
+
+ wskbd_cnattach(&gsckbd_consops, &gsckbd_consdata, &gsckbd_keymapdata);
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+gsckbd_cngetc(v, type, data)
+ void *v;
+ u_int *type;
+ int *data;
+{
+ struct gsckbd_internal *t = v;
+ int val;
+
+ for (;;) {
+ val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
+ if ((val != -1) && gsckbd_decode(t, val, type, data))
+ return;
+ }
+}
+
+void
+gsckbd_cnpollc(v, on)
+ void *v;
+ int on;
+{
+ struct gsckbd_internal *t = v;
+
+ pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
+}
diff --git a/sys/arch/hppa/gsc/gsckbdmap.c b/sys/arch/hppa/gsc/gsckbdmap.c
new file mode 100644
index 00000000000..688e25bd853
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbdmap.c
@@ -0,0 +1,169 @@
+/* $OpenBSD: gsckbdmap.c,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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 <hppa/gsc/gsckbdmap.h>
+
+#define KC(n) KS_KEYCODE(n)
+
+static const keysym_t gsckbd_keydesc_us[] = {
+/* pos command normal shifted */
+ KC(1), KS_Cmd_Screen8, KS_f9,
+ KC(3), KS_Cmd_Screen4, KS_f5,
+ KC(4), KS_Cmd_Screen2, KS_f3,
+ KC(5), KS_Cmd_Screen0, KS_f1,
+ KC(6), KS_Cmd_Screen1, KS_f2,
+ KC(7), KS_Cmd_Screen11, KS_f12,
+ KC(9), KS_Cmd_Screen9, KS_f10,
+ KC(10), KS_Cmd_Screen7, KS_f8,
+ KC(11), KS_Cmd_Screen5, KS_f6,
+ KC(12), KS_Cmd_Screen3, KS_f4,
+ KC(13), KS_Tab,
+ KC(14), KS_grave, KS_asciitilde,
+ KC(17), KS_Cmd2, KS_Alt_L,
+ KC(18), KS_Shift_L,
+ KC(20), KS_Cmd1, KS_Control_L,
+ KC(21), KS_q,
+ KC(22), KS_1, KS_exclam,
+ KC(26), KS_z,
+ KC(27), KS_s,
+ KC(28), KS_a,
+ KC(29), KS_w,
+ KC(30), KS_2, KS_at,
+ KC(33), KS_c,
+ KC(34), KS_x,
+ KC(35), KS_d,
+ KC(36), KS_e,
+ KC(37), KS_4, KS_dollar,
+ KC(38), KS_3, KS_numbersign,
+ KC(41), KS_space,
+ KC(42), KS_v,
+ KC(43), KS_f,
+ KC(44), KS_t,
+ KC(45), KS_r,
+ KC(46), KS_5, KS_percent,
+ KC(49), KS_n,
+ KC(50), KS_b,
+ KC(51), KS_h,
+ KC(52), KS_g,
+ KC(53), KS_y,
+ KC(54), KS_6, KS_asciicircum,
+ KC(58), KS_m,
+ KC(59), KS_j,
+ KC(60), KS_u,
+ KC(61), KS_7, KS_ampersand,
+ KC(62), KS_8, KS_asterisk,
+ KC(65), KS_comma, KS_less,
+ KC(66), KS_k,
+ KC(67), KS_i,
+ KC(68), KS_o,
+ KC(69), KS_0, KS_parenright,
+ KC(70), KS_9, KS_parenleft,
+ KC(73), KS_period, KS_greater,
+ KC(74), KS_slash, KS_question,
+ KC(75), KS_l,
+ KC(76), KS_semicolon, KS_colon,
+ KC(77), KS_p,
+ KC(78), KS_minus, KS_underscore,
+ KC(82), KS_apostrophe, KS_quotedbl,
+ KC(84), KS_bracketleft, KS_braceleft,
+ KC(85), KS_equal, KS_plus,
+ KC(88), KS_Caps_Lock,
+ KC(89), KS_Shift_R,
+ KC(90), KS_Return,
+ KC(91), KS_bracketright,KS_braceright,
+ KC(93), KS_backslash, KS_bar,
+ KC(102), KS_Cmd_ResetEmul, KS_Delete, /* Backspace */
+ KC(105), KS_KP_End, KS_KP_1,
+ KC(107), KS_KP_Left, KS_KP_4,
+ KC(108), KS_KP_Home, KS_KP_7,
+ KC(112), KS_KP_Insert, KS_KP_0,
+ KC(113), KS_Cmd_KbdReset, KS_KP_Delete, KS_KP_Decimal,
+ KC(114), KS_KP_Down, KS_KP_2,
+ KC(115), KS_KP_Begin, KS_KP_5,
+ KC(116), KS_KP_Right, KS_KP_6,
+ KC(117), KS_KP_Up, KS_KP_8,
+ KC(118), KS_Cmd_Debugger, KS_Escape,
+ KC(119), KS_Num_Lock,
+ KC(120), KS_Cmd_Screen10, KS_f11,
+ KC(121), KS_KP_Add,
+ KC(122), KS_KP_Next, KS_KP_3,
+ KC(123), KS_KP_Subtract,
+ KC(124), KS_KP_Multiply,
+ KC(125), KS_KP_Prior, KS_KP_9,
+ KC(126), KS_Hold_Screen,
+ KC(127), KS_Pause, /* Break */
+ KC(131), KS_Cmd_Screen6, KS_f7,
+ KC(145), KS_Cmd2, KS_Alt_R, KS_Multi_key,
+ KC(148), KS_Cmd1, KS_Control_R,
+ KC(202), KS_KP_Divide,
+ KC(218), KS_KP_Enter,
+ KC(233), KS_End,
+ KC(235), KS_Left,
+ KC(236), KS_Home,
+ KC(240), KS_Insert,
+ KC(241), KS_Delete,
+ KC(242), KS_Down,
+ KC(244), KS_Right,
+ KC(245), KS_Up,
+ KC(250), KS_Cmd_ScrollFwd, KS_Next,
+ /*
+ * Print Screen produces E0 12 E0 7C when pressed, then E0 7C E0 12 when
+ * depressed. Ignore the E0 12 code and recognize on E0 7C.
+ */
+ KC(252), KS_Print_Screen,
+ KC(253), KS_Cmd_ScrollBack, KS_Prior,
+ KC(254), KS_Cmd_ResetClose, /* CTL-Break */
+};
+
+static const keysym_t gsckbd_keydesc_swapctrlcaps[] = {
+/* pos command normal shifted */
+ KC(20), KS_Caps_Lock,
+ KC(88), KS_Cmd1, KS_Control_L,
+};
+
+static const keysym_t gsckbd_keydesc_uk[] = {
+ KC(14), KS_grave, KS_notsign,
+ KC(30), KS_2, KS_quotedbl,
+ KC(38), KS_3, KS_sterling,
+ KC(82), KS_apostrophe, KS_at,
+ KC(93), KS_numbersign, KS_asciitilde,
+ KC(97), KS_backslash, KS_bar,
+};
+
+#define KBD_MAP(name, base, map) \
+ { name, base, sizeof(map)/sizeof(keysym_t), map }
+
+const struct wscons_keydesc gsckbd_keydesctab[] = {
+ KBD_MAP(KB_US, 0, gsckbd_keydesc_us),
+ KBD_MAP(KB_UK, KB_US, gsckbd_keydesc_uk),
+ KBD_MAP(KB_US | KB_SWAPCTRLCAPS, KB_US, gsckbd_keydesc_swapctrlcaps),
+ {0, 0, 0, 0}
+};
diff --git a/sys/arch/hppa/gsc/gsckbdmap.h b/sys/arch/hppa/gsc/gsckbdmap.h
new file mode 100644
index 00000000000..83ec0b9119f
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbdmap.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: gsckbdmap.h,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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 gsckbd_keydesctab[];
diff --git a/sys/arch/hppa/gsc/gsckbdvar.h b/sys/arch/hppa/gsc/gsckbdvar.h
new file mode 100644
index 00000000000..6e72a0dc16c
--- /dev/null
+++ b/sys/arch/hppa/gsc/gsckbdvar.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: gsckbdvar.h,v 1.1 2003/01/31 22:50:19 miod Exp $ */
+/*
+ * Copyright (c) 2003, Miodrag Vallat.
+ * 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 ``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.
+ *
+ */
+
+int gsckbd_cnattach(pckbc_tag_t, int);