summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/pckbc.c995
-rw-r--r--sys/dev/ic/pckbcvar.h118
-rw-r--r--sys/dev/isa/pckbc_isa.c191
-rw-r--r--sys/dev/pckbc/Makefile8
-rw-r--r--sys/dev/pckbc/files.pckbc17
-rw-r--r--sys/dev/pckbc/pckbd.c692
-rw-r--r--sys/dev/pckbc/pckbdreg.h28
-rw-r--r--sys/dev/pckbc/pckbdvar.h6
-rw-r--r--sys/dev/pckbc/psm.c332
-rw-r--r--sys/dev/pckbc/psm_intelli.c357
-rw-r--r--sys/dev/pckbc/psmreg.h19
-rw-r--r--sys/dev/pckbc/wskbdmap_mfii.c515
-rw-r--r--sys/dev/pckbc/wskbdmap_mfii.h40
13 files changed, 3318 insertions, 0 deletions
diff --git a/sys/dev/ic/pckbc.c b/sys/dev/ic/pckbc.c
new file mode 100644
index 00000000000..095a899c6fc
--- /dev/null
+++ b/sys/dev/ic/pckbc.c
@@ -0,0 +1,995 @@
+/* $OpenBSD: pckbc.c,v 1.1 2000/11/13 20:12:34 aaron 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <sys/lock.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/i8042reg.h>
+#include <dev/ic/pckbcvar.h>
+
+#ifdef __HAVE_NWSCONS /* XXX: this port uses sys/dev/pckbc */
+#include "pckbd.h"
+#else /* ie: only md drivers attach to pckbc */
+#define NPCKBD 0
+#endif
+
+#if (NPCKBD > 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)
+
+void pckbc_init_slotdata __P((struct pckbc_slotdata *));
+int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
+int pckbc_submatch __P((struct device *, void *, void *));
+int pckbcprint __P((void *, const char *));
+
+struct pckbc_internal pckbc_consdata;
+int pckbc_console_attached;
+
+static int pckbc_console;
+static struct pckbc_slotdata pckbc_cons_slotdata;
+
+static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
+
+static int pckbc_get8042cmd __P((struct pckbc_internal *));
+static int pckbc_put8042cmd __P((struct pckbc_internal *));
+static int pckbc_send_devcmd __P((struct pckbc_internal *, pckbc_slot_t,
+ u_char));
+static void pckbc_poll_cmd1 __P((struct pckbc_internal *, pckbc_slot_t,
+ struct pckbc_devcmd *));
+
+void pckbc_cleanqueue __P((struct pckbc_slotdata *));
+void pckbc_cleanup __P((void *));
+int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
+void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
+
+const char *pckbc_slot_names[] = { "kbd", "aux" };
+
+#define KBC_DEVCMD_ACK 0xfa
+#define KBC_DEVCMD_RESEND 0xfe
+
+#define KBD_DELAY DELAY(8)
+
+static inline int
+pckbc_wait_output(iot, ioh_c)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh_c;
+{
+ u_int i;
+
+ for (i = 100000; i; i--)
+ if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
+ KBD_DELAY;
+ return (1);
+ }
+ return (0);
+}
+
+int
+pckbc_send_cmd(iot, ioh_c, val)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh_c;
+ u_char val;
+{
+ if (!pckbc_wait_output(iot, ioh_c))
+ return (0);
+ bus_space_write_1(iot, ioh_c, 0, val);
+ return (1);
+}
+
+int
+pckbc_poll_data1(iot, ioh_d, ioh_c, slot, checkaux)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh_d, ioh_c;
+ pckbc_slot_t slot;
+ int checkaux;
+{
+ 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_c, 0);
+ if (stat & KBS_DIB) {
+ register u_char c;
+
+ KBD_DELAY;
+ c = bus_space_read_1(iot, ioh_d, 0);
+ if (checkaux && (stat & 0x20)) { /* aux data */
+ if (slot != PCKBC_AUX_SLOT) {
+#ifdef PCKBCDEBUG
+ printf("lost aux 0x%x\n", c);
+#endif
+ continue;
+ }
+ } else {
+ if (slot == PCKBC_AUX_SLOT) {
+#ifdef PCKBCDEBUG
+ printf("lost kbd 0x%x\n", c);
+#endif
+ continue;
+ }
+ }
+ return (c);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * Get the current command byte.
+ */
+static int
+pckbc_get8042cmd(t)
+ struct pckbc_internal *t;
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh_d = t->t_ioh_d;
+ bus_space_handle_t ioh_c = t->t_ioh_c;
+ int data;
+
+ if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
+ return (0);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
+ t->t_haveaux);
+ if (data == -1)
+ return (0);
+ t->t_cmdbyte = data;
+ return (1);
+}
+
+/*
+ * Pass command byte to keyboard controller (8042).
+ */
+static int
+pckbc_put8042cmd(t)
+ struct pckbc_internal *t;
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh_d = t->t_ioh_d;
+ bus_space_handle_t ioh_c = t->t_ioh_c;
+
+ if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
+ return (0);
+ if (!pckbc_wait_output(iot, ioh_c))
+ return (0);
+ bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
+ return (1);
+}
+
+static int
+pckbc_send_devcmd(t, slot, val)
+ struct pckbc_internal *t;
+ pckbc_slot_t slot;
+ u_char val;
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh_d = t->t_ioh_d;
+ bus_space_handle_t ioh_c = t->t_ioh_c;
+
+ if (slot == PCKBC_AUX_SLOT) {
+ if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
+ return (0);
+ }
+ if (!pckbc_wait_output(iot, ioh_c))
+ return (0);
+ bus_space_write_1(iot, ioh_d, 0, val);
+ return (1);
+}
+
+int
+pckbc_is_console(iot, addr)
+ bus_space_tag_t iot;
+ bus_addr_t addr;
+{
+ if (pckbc_console && !pckbc_console_attached &&
+ pckbc_consdata.t_iot == iot &&
+ pckbc_consdata.t_addr == addr)
+ return (1);
+ return (0);
+}
+
+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);
+ pckbc_init_slotdata(t->t_slotdata[slot]);
+ }
+ return (found);
+}
+
+void
+pckbc_attach(sc)
+ struct pckbc_softc *sc;
+{
+ struct pckbc_internal *t;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh_d, ioh_c;
+ int res;
+ u_char cmdbits = 0;
+
+ t = sc->id;
+ iot = t->t_iot;
+ ioh_d = t->t_ioh_d;
+ ioh_c = t->t_ioh_c;
+
+ /* flush */
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+
+ /* set initial cmd byte */
+ if (!pckbc_put8042cmd(t)) {
+ printf("kbc: cmd word write error\n");
+ return;
+ }
+
+/*
+ * XXX Don't check the keyboard port. There are broken keyboard controllers
+ * which don't pass the test but work normally otherwise.
+ */
+#if 0
+ /*
+ * check kbd port ok
+ */
+ if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
+ return;
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+
+ /*
+ * Normally, we should get a "0" here.
+ * But there are keyboard controllers behaving differently.
+ */
+ if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
+#ifdef PCKBCDEBUG
+ if (res != 0)
+ printf("kbc: returned %x on kbd slot test\n", res);
+#endif
+ if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
+ cmdbits |= KC8_KENABLE;
+ } else {
+ printf("kbc: kbd port test: %x\n", res);
+ return;
+ }
+#else
+ if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
+ cmdbits |= KC8_KENABLE;
+#endif /* 0 */
+
+ /*
+ * check aux port ok
+ */
+ if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXTEST))
+ return;
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+
+ if (res == 0 || res == 0xfa || res == 0x01) {
+#ifdef PCKBCDEBUG
+ if (res != 0)
+ printf("kbc: returned %x on aux slot test\n", res);
+#endif
+ t->t_haveaux = 1;
+ if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
+ cmdbits |= KC8_MENABLE;
+ }
+#ifdef PCKBCDEBUG
+ else
+ printf("kbc: aux port test: %x\n", res);
+#endif
+
+ /* enable needed interrupts */
+ t->t_cmdbyte |= cmdbits;
+ if (!pckbc_put8042cmd(t))
+ printf("kbc: cmd word write error\n");
+}
+
+int
+pckbcprint(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+ struct pckbc_attach_args *pa = aux;
+
+ if (!pnp)
+ printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
+ 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;
+
+ (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
+ slot, t->t_haveaux);
+}
+
+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_c,
+ slot, t->t_haveaux);
+ 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);
+}
+
+/*
+ * switch scancode translation on / off
+ * return nonzero on success
+ */
+int
+pckbc_xt_translation(self, slot, on)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ int on;
+{
+ struct pckbc_internal *t = self;
+ int ison;
+
+ if (slot != PCKBC_KBD_SLOT) {
+ /* translation only for kbd slot */
+ if (on)
+ return (0);
+ else
+ return (1);
+ }
+
+ ison = t->t_cmdbyte & KC8_TRANS;
+ if ((on && ison) || (!on && !ison))
+ return (1);
+
+ t->t_cmdbyte ^= KC8_TRANS;
+ if (!pckbc_put8042cmd(t))
+ return (0);
+
+ /* read back to be sure */
+ if (!pckbc_get8042cmd(t))
+ return (0);
+
+ ison = t->t_cmdbyte & KC8_TRANS;
+ if ((on && ison) || (!on && !ison))
+ return (1);
+ return (0);
+}
+
+static struct pckbc_portcmd {
+ u_char cmd_en, cmd_dis;
+} pckbc_portcmd[2] = {
+ {
+ KBC_KBDENABLE, KBC_KBDDISABLE,
+ }, {
+ KBC_AUXENABLE, KBC_AUXDISABLE,
+ }
+};
+
+void
+pckbc_slot_enable(self, slot, on)
+ pckbc_tag_t self;
+ pckbc_slot_t slot;
+ int on;
+{
+ struct pckbc_internal *t = (struct pckbc_internal *)self;
+ struct pckbc_portcmd *cmd;
+
+ cmd = &pckbc_portcmd[slot];
+
+ if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
+ on ? cmd->cmd_en : cmd->cmd_dis))
+ printf("pckbc_slot_enable(%d) failed\n", on);
+}
+
+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()
+ */
+static 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_d = t->t_ioh_d;
+ bus_space_handle_t ioh_c = t->t_ioh_c;
+ 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_d, ioh_c, slot,
+ t->t_haveaux);
+ 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++ < 5)
+ 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_d, ioh_c, slot,
+ t->t_haveaux);
+ 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_c, 0) & KBS_DIB) {
+ KBD_DELAY;
+ (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
+ }
+
+ /* 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 (q->polling) {
+ 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++ < 5) {
+ /* 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 (q->polling && 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 (q->polling)
+ 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 pckbc_internal *t = sc->id;
+ u_char stat;
+ pckbc_slot_t slot;
+ struct pckbc_slotdata *q;
+ int served = 0, data;
+
+ for(;;) {
+ stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
+ if (!(stat & KBS_DIB))
+ break;
+
+ served = 1;
+
+ slot = (t->t_haveaux && (stat & 0x20)) ?
+ PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
+ q = t->t_slotdata[slot];
+
+ if (!q) {
+ /* XXX do something for live insertion? */
+ printf("pckbcintr: no dev for slot %d\n", slot);
+ KBD_DELAY;
+ (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
+ continue;
+ }
+
+ if (q->polling)
+ break; /* pckbc_poll_data() will get it */
+
+ KBD_DELAY;
+ data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
+
+ 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);
+}
+
+int
+pckbc_cnattach(iot, addr, cmd_offset, slot)
+ bus_space_tag_t iot;
+ bus_addr_t addr;
+ bus_size_t cmd_offset;
+ pckbc_slot_t slot;
+{
+ bus_space_handle_t ioh_d, ioh_c;
+ int res = 0;
+
+ if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
+ return (ENXIO);
+ if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
+ bus_space_unmap(iot, ioh_d, 1);
+ return (ENXIO);
+ }
+
+ pckbc_consdata.t_iot = iot;
+ pckbc_consdata.t_ioh_d = ioh_d;
+ pckbc_consdata.t_ioh_c = ioh_c;
+ pckbc_consdata.t_addr = addr;
+ timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata);
+
+ /* flush */
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+
+ /* selftest? */
+
+ /* init cmd byte, enable ports */
+ pckbc_consdata.t_cmdbyte = KC8_CPU;
+ if (!pckbc_put8042cmd(&pckbc_consdata)) {
+ printf("kbc: cmd word write error\n");
+ res = EIO;
+ }
+
+ if (!res) {
+#if (NPCKBD > 0)
+ res = pckbd_cnattach(&pckbc_consdata, slot);
+#else
+ /*
+ * XXX This should be replaced with the `notyet' case
+ * XXX when all of the old PC-style console drivers
+ * XXX have gone away. When that happens, all of
+ * XXX the pckbc_machdep_cnattach() should be purged,
+ * XXX as well.
+ */
+#ifdef notyet
+ res = ENXIO;
+#else
+ res = pckbc_machdep_cnattach(&pckbc_consdata, slot);
+#endif
+#endif /* NPCKBD > 0 */
+ }
+
+ if (res) {
+ bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
+ bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
+ } else {
+ pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
+ pckbc_init_slotdata(&pckbc_cons_slotdata);
+ pckbc_console = 1;
+ }
+
+ return (res);
+}
+
+struct cfdriver pckbc_cd = {
+ NULL, "pckbc", DV_DULL
+};
diff --git a/sys/dev/ic/pckbcvar.h b/sys/dev/ic/pckbcvar.h
new file mode 100644
index 00000000000..f3b5a990c51
--- /dev/null
+++ b/sys/dev/ic/pckbcvar.h
@@ -0,0 +1,118 @@
+/* $OpenBSD: pckbcvar.h,v 1.1 2000/11/13 20:12:34 aaron Exp $ */
+/* $NetBSD: pckbcvar.h,v 1.4 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.
+ *
+ */
+
+#ifndef _DEV_IC_PCKBCVAR_H_
+#define _DEV_IC_PCKBCVAR_H_
+
+#include <sys/timeout.h>
+
+#define PCKBCCF_SLOT 0
+#define PCKBCCF_SLOT_DEFAULT -1
+
+typedef void *pckbc_tag_t;
+typedef int pckbc_slot_t;
+#define PCKBC_KBD_SLOT 0
+#define PCKBC_AUX_SLOT 1
+#define PCKBC_NSLOTS 2
+
+/*
+ * external representation (pckbc_tag_t),
+ * needed early for console operation
+ */
+struct pckbc_internal {
+ bus_space_tag_t t_iot;
+ bus_space_handle_t t_ioh_d, t_ioh_c; /* data port, cmd port */
+ bus_addr_t t_addr;
+ u_char t_cmdbyte; /* shadow */
+
+ int t_haveaux; /* controller has an aux port */
+ struct pckbc_slotdata *t_slotdata[PCKBC_NSLOTS];
+
+ struct pckbc_softc *t_sc; /* back pointer */
+
+ struct timeout t_cleanup;
+};
+
+typedef void (*pckbc_inputfcn) __P((void *, int));
+
+/*
+ * State per device.
+ */
+struct pckbc_softc {
+ struct device sc_dv;
+ struct pckbc_internal *id;
+
+ pckbc_inputfcn inputhandler[PCKBC_NSLOTS];
+ void *inputarg[PCKBC_NSLOTS];
+ char *subname[PCKBC_NSLOTS];
+
+ void (*intr_establish) __P((struct pckbc_softc *, pckbc_slot_t));
+};
+
+struct pckbc_attach_args {
+ pckbc_tag_t pa_tag;
+ pckbc_slot_t pa_slot;
+};
+
+extern const char *pckbc_slot_names[];
+extern struct pckbc_internal pckbc_consdata;
+extern int pckbc_console_attached;
+
+void pckbc_set_inputhandler __P((pckbc_tag_t, pckbc_slot_t,
+ pckbc_inputfcn, void *, char *));
+
+void pckbc_flush __P((pckbc_tag_t, pckbc_slot_t));
+int pckbc_poll_cmd __P((pckbc_tag_t, pckbc_slot_t, u_char *, int,
+ int, u_char *, int));
+int pckbc_enqueue_cmd __P((pckbc_tag_t, pckbc_slot_t, u_char *, int,
+ int, int, u_char *));
+int pckbc_send_cmd __P((bus_space_tag_t, bus_space_handle_t, u_char));
+int pckbc_poll_data __P((pckbc_tag_t, pckbc_slot_t));
+int pckbc_poll_data1 __P((bus_space_tag_t, bus_space_handle_t,
+ bus_space_handle_t, pckbc_slot_t, int));
+void pckbc_set_poll __P((pckbc_tag_t, pckbc_slot_t, int));
+int pckbc_xt_translation __P((pckbc_tag_t, pckbc_slot_t, int));
+void pckbc_slot_enable __P((pckbc_tag_t, pckbc_slot_t, int));
+
+void pckbc_attach __P((struct pckbc_softc *));
+int pckbc_cnattach __P((bus_space_tag_t, bus_addr_t, bus_size_t,
+ pckbc_slot_t));
+int pckbc_is_console __P((bus_space_tag_t, bus_addr_t));
+int pckbcintr __P((void *));
+
+/* md hook for use without mi wscons */
+int pckbc_machdep_cnattach __P((pckbc_tag_t, pckbc_slot_t));
+
+#endif /* _DEV_IC_PCKBCVAR_H_ */
diff --git a/sys/dev/isa/pckbc_isa.c b/sys/dev/isa/pckbc_isa.c
new file mode 100644
index 00000000000..3e6ba5780a2
--- /dev/null
+++ b/sys/dev/isa/pckbc_isa.c
@@ -0,0 +1,191 @@
+/* $NetBSD: pckbc_isa.c,v 1.2 2000/03/23 07:01:35 thorpej 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+#include <sys/lock.h>
+
+#include <machine/bus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <dev/ic/i8042reg.h>
+#include <dev/ic/pckbcvar.h>
+
+int pckbc_isa_match __P((struct device *, void *, void *));
+void pckbc_isa_attach __P((struct device *, struct device *, void *));
+
+struct pckbc_isa_softc {
+ struct pckbc_softc sc_pckbc;
+
+ isa_chipset_tag_t sc_ic;
+ int sc_irq[PCKBC_NSLOTS];
+};
+
+struct cfattach pckbc_isa_ca = {
+ sizeof(struct pckbc_isa_softc), pckbc_isa_match, pckbc_isa_attach,
+};
+
+void pckbc_isa_intr_establish __P((struct pckbc_softc *, pckbc_slot_t));
+
+int
+pckbc_isa_match(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t iot = ia->ia_iot;
+ bus_space_handle_t ioh_d, ioh_c;
+ int res, ok = 1;
+
+ /* If values are hardwired to something that they can't be, punt. */
+ if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_KBD) ||
+ ia->ia_maddr != MADDRUNK ||
+ (ia->ia_irq != IRQUNK && ia->ia_irq != 1 /* XXX */) ||
+ ia->ia_drq != DRQUNK)
+ return (0);
+
+ if (pckbc_is_console(iot, IO_KBD) == 0) {
+ if (bus_space_map(iot, IO_KBD + KBDATAP, 1, 0, &ioh_d))
+ return (0);
+ if (bus_space_map(iot, IO_KBD + KBCMDP, 1, 0, &ioh_c)) {
+ bus_space_unmap(iot, ioh_d, 1);
+ return (0);
+ }
+
+ /* flush KBC */
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+
+ /* KBC selftest */
+ if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0) {
+ ok = 0;
+ goto out;
+ }
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ if (res != 0x55) {
+ printf("kbc selftest: %x\n", res);
+ ok = 0;
+ }
+ out:
+ bus_space_unmap(iot, ioh_d, 1);
+ bus_space_unmap(iot, ioh_c, 1);
+ }
+
+ if (ok) {
+ ia->ia_iobase = IO_KBD;
+ ia->ia_iosize = 5;
+ ia->ia_msize = 0x0;
+ }
+ return (ok);
+}
+
+void
+pckbc_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pckbc_isa_softc *isc = (void *)self;
+ struct pckbc_softc *sc = &isc->sc_pckbc;
+ struct isa_attach_args *ia = aux;
+ struct pckbc_internal *t;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh_d, ioh_c;
+
+ isc->sc_ic = ia->ia_ic;
+ iot = ia->ia_iot;
+
+ /*
+ * Set up IRQs for "normal" ISA.
+ *
+ * XXX The "aux" slot is different (9) on the Alpha AXP150 Jensen.
+ */
+ isc->sc_irq[PCKBC_KBD_SLOT] = 1;
+ isc->sc_irq[PCKBC_AUX_SLOT] = 12;
+
+ sc->intr_establish = pckbc_isa_intr_establish;
+
+ if (pckbc_is_console(iot, IO_KBD)) {
+ t = &pckbc_consdata;
+ ioh_d = t->t_ioh_d;
+ ioh_c = t->t_ioh_c;
+ pckbc_console_attached = 1;
+ /* t->t_cmdbyte was initialized by cnattach */
+ } else {
+ if (bus_space_map(iot, IO_KBD + KBDATAP, 1, 0, &ioh_d) ||
+ bus_space_map(iot, IO_KBD + KBCMDP, 1, 0, &ioh_c))
+ panic("pckbc_attach: couldn't map");
+
+ t = malloc(sizeof(struct pckbc_internal), M_DEVBUF, M_WAITOK);
+ bzero(t, sizeof(struct pckbc_internal));
+ t->t_iot = iot;
+ t->t_ioh_d = ioh_d;
+ t->t_ioh_c = ioh_c;
+ t->t_addr = IO_KBD;
+ t->t_cmdbyte = KC8_CPU; /* Enable ports */
+ }
+
+ t->t_sc = sc;
+ sc->id = t;
+
+ printf("\n");
+
+ /* Finish off the attach. */
+ pckbc_attach(sc);
+}
+
+void
+pckbc_isa_intr_establish(sc, slot)
+ struct pckbc_softc *sc;
+ pckbc_slot_t slot;
+{
+ struct pckbc_isa_softc *isc = (void *) sc;
+ void *rv;
+
+ rv = isa_intr_establish(isc->sc_ic, isc->sc_irq[slot], IST_EDGE,
+ IPL_TTY, pckbcintr, sc, sc->sc_dv.dv_xname);
+ if (rv == NULL) {
+ printf("%s: unable to establish interrupt for %s slot\n",
+ sc->sc_dv.dv_xname, pckbc_slot_names[slot]);
+ } else {
+ printf("%s: using irq %d for %s slot\n", sc->sc_dv.dv_xname,
+ isc->sc_irq[slot], pckbc_slot_names[slot]);
+ }
+}
diff --git a/sys/dev/pckbc/Makefile b/sys/dev/pckbc/Makefile
new file mode 100644
index 00000000000..4056f59643f
--- /dev/null
+++ b/sys/dev/pckbc/Makefile
@@ -0,0 +1,8 @@
+# $OpenBSD: Makefile,v 1.1 2000/11/13 20:12:34 aaron Exp $
+# $NetBSD: Makefile,v 1.1 1998/06/12 23:22:54 cgd Exp $
+
+INCSDIR= /usr/include/dev/pckbc
+
+INCS= pckbdreg.h pckbdvar.h psmreg.h
+
+.include <bsd.kinc.mk>
diff --git a/sys/dev/pckbc/files.pckbc b/sys/dev/pckbc/files.pckbc
new file mode 100644
index 00000000000..241424760ae
--- /dev/null
+++ b/sys/dev/pckbc/files.pckbc
@@ -0,0 +1,17 @@
+# $OpenBSD: files.pckbc,v 1.1 2000/11/13 20:12:34 aaron Exp $
+# $NetBSD: files.pckbc,v 1.6 1999/01/23 16:05:56 drochner Exp $
+# devices attached at pckbc, for use with wscons
+
+device pckbd: wskbddev
+attach pckbd at pckbc
+file dev/pckbc/pckbd.c pckbd needs-flag
+file dev/pckbc/wskbdmap_mfii.c pckbd
+defopt PCKBD_LAYOUT
+
+device pms: wsmousedev
+attach pms at pckbc
+file dev/pckbc/psm.c pms
+
+device pmsi: wsmousedev
+attach pmsi at pckbc
+file dev/pckbc/psm_intelli.c pmsi
diff --git a/sys/dev/pckbc/pckbd.c b/sys/dev/pckbc/pckbd.c
new file mode 100644
index 00000000000..5326bfc0088
--- /dev/null
+++ b/sys/dev/pckbc/pckbd.c
@@ -0,0 +1,692 @@
+/* $OpenBSD: pckbd.c,v 1.1 2000/11/13 20:12:34 aaron 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
+ */
+
+/*
+ * code to work keyboard for PC-style console
+ */
+
+#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/isa/isavar.h> /* XXX XXX XXX */
+
+#include <dev/ic/pckbcvar.h>
+
+#include <dev/pckbc/pckbdreg.h>
+#include <dev/pckbc/pckbdvar.h>
+#include <dev/pckbc/wskbdmap_mfii.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+#if defined(__i386__) || defined(__alpha__)
+#include <sys/kernel.h> /* XXX for hz */
+#endif
+
+#if 0
+#include "opt_pckbd_layout.h"
+#include "opt_wsdisplay_compat.h"
+#endif
+
+struct pckbd_internal {
+ int t_isconsole;
+ pckbc_tag_t t_kbctag;
+ pckbc_slot_t t_kbcslot;
+
+ int t_lastchar;
+ int t_extended;
+ int t_extended1;
+
+ struct pckbd_softc *t_sc; /* back pointer */
+};
+
+struct pckbd_softc {
+ struct device sc_dev;
+
+ struct pckbd_internal *id;
+ int sc_enabled;
+
+ int sc_ledstate;
+
+ struct device *sc_wskbddev;
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ int rawkbd;
+#endif
+};
+
+static int pckbd_is_console __P((pckbc_tag_t, pckbc_slot_t));
+
+int pckbdprobe __P((struct device *, void *, void *));
+void pckbdattach __P((struct device *, struct device *, void *));
+
+struct cfattach pckbd_ca = {
+ sizeof(struct pckbd_softc), pckbdprobe, pckbdattach,
+};
+
+int pckbd_enable __P((void *, int));
+void pckbd_set_leds __P((void *, int));
+int pckbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
+
+const struct wskbd_accessops pckbd_accessops = {
+ pckbd_enable,
+ pckbd_set_leds,
+ pckbd_ioctl,
+};
+
+void pckbd_cngetc __P((void *, u_int *, int *));
+void pckbd_cnpollc __P((void *, int));
+void pckbd_cnbell __P((void *, u_int, u_int, u_int));
+
+const struct wskbd_consops pckbd_consops = {
+ pckbd_cngetc,
+ pckbd_cnpollc,
+ pckbd_cnbell,
+};
+
+const struct wskbd_mapdata pckbd_keymapdata = {
+ pckbd_keydesctab,
+#ifdef PCKBD_LAYOUT
+ PCKBD_LAYOUT,
+#else
+ KB_US,
+#endif
+};
+
+/*
+ * Hackish support for a bell on the PC Keyboard; when a suitable feeper
+ * is found, it attaches itself into the pckbd driver here.
+ */
+void (*pckbd_bell_fn) __P((void *, u_int, u_int, u_int, int));
+void *pckbd_bell_fn_arg;
+
+void pckbd_bell __P((u_int, u_int, u_int, int));
+
+int pckbd_set_xtscancode __P((pckbc_tag_t, pckbc_slot_t));
+int pckbd_init __P((struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t,
+ int));
+void pckbd_input __P((void *, int));
+
+static int pckbd_decode __P((struct pckbd_internal *, int,
+ u_int *, int *));
+static int pckbd_led_encode __P((int));
+static int pckbd_led_decode __P((int));
+
+struct pckbd_internal pckbd_consdata;
+
+int
+pckbd_set_xtscancode(kbctag, kbcslot)
+ pckbc_tag_t kbctag;
+ pckbc_slot_t kbcslot;
+{
+ u_char cmd[2];
+ int res;
+
+ /*
+ * Some keyboard/8042 combinations do not seem to work if the keyboard
+ * is set to table 1; in fact, it would appear that some keyboards just
+ * ignore the command altogether. So by default, we use the AT scan
+ * codes and have the 8042 translate them. Unfortunately, this is
+ * known to not work on some PS/2 machines. We try desparately to deal
+ * with this by checking the (lack of a) translate bit in the 8042 and
+ * attempting to set the keyboard to XT mode. If this all fails, well,
+ * tough luck.
+ *
+ * XXX It would perhaps be a better choice to just use AT scan codes
+ * and not bother with this.
+ */
+ if (pckbc_xt_translation(kbctag, kbcslot, 1)) {
+ /* The 8042 is translating for us; use AT codes. */
+ cmd[0] = KBC_SETTABLE;
+ cmd[1] = 2;
+ res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
+ if (res) {
+ u_char cmd[1];
+#ifdef DEBUG
+ printf("pckbd: error setting scanset 2\n");
+#endif
+ /*
+ * XXX at least one keyboard is reported to lock up
+ * if a "set table" is attempted, thus the "reset".
+ * XXX ignore errors, scanset 2 should be
+ * default anyway.
+ */
+ cmd[0] = KBC_RESET;
+ (void)pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 1, 0, 1);
+ pckbc_flush(kbctag, kbcslot);
+ res = 0;
+ }
+ } else {
+ /* Stupid 8042; set keyboard to XT codes. */
+ cmd[0] = KBC_SETTABLE;
+ cmd[1] = 1;
+ res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
+#ifdef DEBUG
+ if (res)
+ printf("pckbd: error setting scanset 1\n");
+#endif
+ }
+ return (res);
+}
+
+static int
+pckbd_is_console(tag, slot)
+ pckbc_tag_t tag;
+ pckbc_slot_t slot;
+{
+ return (pckbd_consdata.t_isconsole &&
+ (tag == pckbd_consdata.t_kbctag) &&
+ (slot == pckbd_consdata.t_kbcslot));
+}
+
+/*
+ * these are both bad jokes
+ */
+int
+pckbdprobe(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("pckbdprobe: 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 (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
+ }
+ if (resp[0] != KBR_RSTDONE) {
+ printf("pckbdprobe: 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);
+
+ if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot))
+ return (0);
+
+ return (2);
+}
+
+void
+pckbdattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pckbd_softc *sc = (void *)self;
+ struct pckbc_attach_args *pa = aux;
+ int isconsole;
+ struct wskbddev_attach_args a;
+
+ printf("\n");
+
+ isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
+
+ if (isconsole) {
+ sc->id = &pckbd_consdata;
+ sc->sc_enabled = 1;
+ } else {
+ u_char cmd[1];
+
+ sc->id = malloc(sizeof(struct pckbd_internal),
+ M_DEVBUF, M_WAITOK);
+ (void) pckbd_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,
+ pckbd_input, sc, sc->sc_dev.dv_xname);
+
+ a.console = isconsole;
+
+ a.keymap = &pckbd_keymapdata;
+
+ a.accessops = &pckbd_accessops;
+ a.accesscookie = sc;
+
+ /*
+ * Attach the wskbd, saving a handle to it.
+ * XXX XXX XXX
+ */
+ sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
+}
+
+int
+pckbd_enable(v, on)
+ void *v;
+ int on;
+{
+ struct pckbd_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("pckbd_enable: command error\n");
+ return (res);
+ }
+
+ res = pckbd_set_xtscancode(sc->id->t_kbctag,
+ sc->id->t_kbcslot);
+ if (res)
+ 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("pckbd_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
+pckbd_decode(id, datain, type, dataout)
+ struct pckbd_internal *id;
+ int datain;
+ u_int *type;
+ int *dataout;
+{
+ int key;
+
+ if (datain == KBR_EXTENDED0) {
+ id->t_extended = 1;
+ return(0);
+ } else if (datain == KBR_EXTENDED1) {
+ id->t_extended1 = 2;
+ return(0);
+ }
+
+ /* map extended keys to (unused) codes 128-254 */
+ key = (datain & 0x7f) | (id->t_extended ? 0x80 : 0);
+ id->t_extended = 0;
+
+ /*
+ * process BREAK key (EXT1 1D 45 EXT1 9D C5):
+ * map to (unused) code 7F
+ */
+ if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
+ id->t_extended1 = 1;
+ return(0);
+ } else if (id->t_extended1 == 1 &&
+ (datain == 0x45 || datain == 0xc5)) {
+ id->t_extended1 = 0;
+ key = 0x7f;
+ } else if (id->t_extended1 > 0) {
+ id->t_extended1 = 0;
+ }
+
+ if (datain & 0x80) {
+ id->t_lastchar = 0;
+ *type = WSCONS_EVENT_KEY_UP;
+ } else {
+ /* Always ignore typematic keys */
+ if (key == id->t_lastchar)
+ return(0);
+ id->t_lastchar = key;
+ *type = WSCONS_EVENT_KEY_DOWN;
+ }
+
+ *dataout = key;
+ return(1);
+}
+
+int
+pckbd_init(t, kbctag, kbcslot, console)
+ struct pckbd_internal *t;
+ pckbc_tag_t kbctag;
+ pckbc_slot_t kbcslot;
+ int console;
+{
+ bzero(t, sizeof(struct pckbd_internal));
+
+ t->t_isconsole = console;
+ t->t_kbctag = kbctag;
+ t->t_kbcslot = kbcslot;
+
+ return (pckbd_set_xtscancode(kbctag, kbcslot));
+}
+
+static int
+pckbd_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
+pckbd_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
+pckbd_set_leds(v, leds)
+ void *v;
+ int leds;
+{
+ struct pckbd_softc *sc = v;
+ u_char cmd[2];
+
+ cmd[0] = KBC_MODEIND;
+ cmd[1] = pckbd_led_encode(leds);
+ sc->sc_ledstate = cmd[1];
+
+ (void) 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
+pckbd_input(vsc, data)
+ void *vsc;
+ int data;
+{
+ struct pckbd_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 (pckbd_decode(sc->id, data, &type, &key))
+ wskbd_input(sc->sc_wskbddev, type, key);
+}
+
+int
+pckbd_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct pckbd_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] = pckbd_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 = pckbd_led_decode(sc->sc_ledstate);
+ return (0);
+ case WSKBDIO_COMPLEXBELL:
+#define d ((struct wskbd_bell_data *)data)
+ /*
+ * Keyboard can't beep directly; we have an
+ * externally-provided global hook to do this.
+ */
+ pckbd_bell(d->pitch, d->period, d->volume, 0);
+#undef d
+ return (0);
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ case WSKBDIO_SETMODE:
+ sc->rawkbd = (*(int *)data == WSKBD_RAW);
+ return (0);
+#endif
+ }
+ return -1;
+}
+
+void
+pckbd_bell(pitch, period, volume, poll)
+ u_int pitch, period, volume;
+ int poll;
+{
+
+ if (pckbd_bell_fn != NULL)
+ (*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
+ volume, poll);
+}
+
+void
+pckbd_hookup_bell(fn, arg)
+ void (*fn) __P((void *, u_int, u_int, u_int, int));
+ void *arg;
+{
+
+ if (pckbd_bell_fn == NULL) {
+ pckbd_bell_fn = fn;
+ pckbd_bell_fn_arg = arg;
+ }
+}
+
+int
+pckbd_cnattach(kbctag, kbcslot)
+ pckbc_tag_t kbctag;
+ int kbcslot;
+{
+ char cmd[1];
+ int res;
+
+ res = pckbd_init(&pckbd_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(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+pckbd_cngetc(v, type, data)
+ void *v;
+ u_int *type;
+ int *data;
+{
+ struct pckbd_internal *t = v;
+ int val;
+
+ for (;;) {
+ val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
+ if ((val != -1) && pckbd_decode(t, val, type, data))
+ return;
+ }
+}
+
+void
+pckbd_cnpollc(v, on)
+ void *v;
+ int on;
+{
+ struct pckbd_internal *t = v;
+
+ pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
+}
+
+void
+pckbd_cnbell(v, pitch, period, volume)
+ void *v;
+ u_int pitch, period, volume;
+{
+
+ pckbd_bell(pitch, period, volume, 1);
+}
+
+struct cfdriver pckbd_cd = {
+ NULL, "pckbd", DV_DULL
+};
diff --git a/sys/dev/pckbc/pckbdreg.h b/sys/dev/pckbc/pckbdreg.h
new file mode 100644
index 00000000000..2c97b2d4b5e
--- /dev/null
+++ b/sys/dev/pckbc/pckbdreg.h
@@ -0,0 +1,28 @@
+/* $OpenBSD: pckbdreg.h,v 1.1 2000/11/13 20:12:35 aaron Exp $ */
+/* $NetBSD: pckbdreg.h,v 1.2 1998/04/07 13:43:16 hannken Exp $ */
+
+/*
+ * Keyboard definitions
+ */
+
+/* keyboard commands */
+#define KBC_RESET 0xFF /* reset the keyboard */
+#define KBC_RESEND 0xFE /* request the keyboard resend the last byte */
+#define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */
+#define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */
+#define KBC_ENABLE 0xF4 /* enable key scanning */
+#define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */
+#define KBC_SETTABLE 0xF0 /* set scancode translation table */
+#define KBC_MODEIND 0xED /* set mode indicators (i.e. LEDs) */
+#define KBC_ECHO 0xEE /* request an echo from the keyboard */
+
+/* keyboard responses */
+#define KBR_EXTENDED0 0xE0 /* extended key sequence */
+#define KBR_EXTENDED1 0xE1 /* extended key sequence */
+#define KBR_RESEND 0xFE /* needs resend of command */
+#define KBR_ACK 0xFA /* received a valid command */
+#define KBR_OVERRUN 0x00 /* flooded */
+#define KBR_FAILURE 0xFD /* diagnosic failure */
+#define KBR_BREAK 0xF0 /* break code prefix - sent on key release */
+#define KBR_RSTDONE 0xAA /* reset complete */
+#define KBR_ECHO 0xEE /* echo response */
diff --git a/sys/dev/pckbc/pckbdvar.h b/sys/dev/pckbc/pckbdvar.h
new file mode 100644
index 00000000000..aa68e8520d2
--- /dev/null
+++ b/sys/dev/pckbc/pckbdvar.h
@@ -0,0 +1,6 @@
+/* $OpenBSD: pckbdvar.h,v 1.1 2000/11/13 20:12:35 aaron Exp $ */
+/* $NetBSD: pckbdvar.h,v 1.3 2000/03/10 06:10:35 thorpej Exp $ */
+
+int pckbd_cnattach __P((pckbc_tag_t, int));
+void pckbd_hookup_bell __P((void (*fn)(void *, u_int, u_int, u_int, int),
+ void *));
diff --git a/sys/dev/pckbc/psm.c b/sys/dev/pckbc/psm.c
new file mode 100644
index 00000000000..16ff008f687
--- /dev/null
+++ b/sys/dev/pckbc/psm.c
@@ -0,0 +1,332 @@
+/* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */
+
+/*-
+ * Copyright (c) 1994 Charles M. Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/pckbcvar.h>
+
+#include <dev/pckbc/psmreg.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+struct pms_softc { /* driver status information */
+ struct device sc_dev;
+
+ pckbc_tag_t sc_kbctag;
+ int sc_kbcslot;
+
+ int sc_enabled; /* input enabled? */
+ int inputstate;
+ u_int buttons, oldbuttons; /* mouse button status */
+ signed char dx;
+
+ struct device *sc_wsmousedev;
+};
+
+int pmsprobe __P((struct device *, void *, void *));
+void pmsattach __P((struct device *, struct device *, void *));
+void pmsinput __P((void *, int));
+
+struct cfattach pms_ca = {
+ sizeof(struct pms_softc), pmsprobe, pmsattach,
+};
+
+int pms_enable __P((void *));
+int pms_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
+void pms_disable __P((void *));
+
+const struct wsmouse_accessops pms_accessops = {
+ pms_enable,
+ pms_ioctl,
+ pms_disable,
+};
+
+int
+pmsprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct pckbc_attach_args *pa = aux;
+ u_char cmd[1], resp[2];
+ int res;
+
+ if (pa->pa_slot != PCKBC_AUX_SLOT)
+ return (0);
+
+ /* Flush any garbage. */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ /* reset the device */
+ cmd[0] = PMS_RESET;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+ if (res) {
+#ifdef DEBUG
+ printf("pmsprobe: reset error %d\n", res);
+#endif
+ return (0);
+ }
+ if (resp[0] != PMS_RSTDONE) {
+ printf("pmsprobe: reset response 0x%x\n", resp[0]);
+ return (0);
+ }
+
+ /* get type number (0 = mouse) */
+ if (resp[1] != 0) {
+#ifdef DEBUG
+ printf("pmsprobe: type 0x%x\n", resp[1]);
+#endif
+ return (0);
+ }
+
+ return (10);
+}
+
+void
+pmsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pms_softc *sc = (void *)self;
+ struct pckbc_attach_args *pa = aux;
+ struct wsmousedev_attach_args a;
+ u_char cmd[1], resp[2];
+ int res;
+
+ sc->sc_kbctag = pa->pa_tag;
+ sc->sc_kbcslot = pa->pa_slot;
+
+ printf("\n");
+
+ /* Flush any garbage. */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ /* reset the device */
+ cmd[0] = PMS_RESET;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+#ifdef DEBUG
+ if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) {
+ printf("pmsattach: reset error\n");
+ return;
+ }
+#endif
+
+ sc->inputstate = 0;
+ sc->oldbuttons = 0;
+
+ pckbc_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot,
+ pmsinput, sc, sc->sc_dev.dv_xname);
+
+ a.accessops = &pms_accessops;
+ a.accesscookie = sc;
+
+ /*
+ * Attach the wsmouse, saving a handle to it.
+ * Note that we don't need to check this pointer against NULL
+ * here or in pmsintr, because if this fails pms_enable() will
+ * never be called, so pmsinput() will never be called.
+ */
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+
+ /* no interrupts until enabled */
+ cmd[0] = PMS_DEV_DISABLE;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, 0, 0);
+ if (res)
+ printf("pmsattach: disable error\n");
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+}
+
+int
+pms_enable(v)
+ void *v;
+{
+ struct pms_softc *sc = v;
+ u_char cmd[1];
+ int res;
+
+ if (sc->sc_enabled)
+ return EBUSY;
+
+ sc->sc_enabled = 1;
+ sc->inputstate = 0;
+ sc->oldbuttons = 0;
+
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1);
+
+ cmd[0] = PMS_DEV_ENABLE;
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
+ if (res)
+ printf("pms_enable: command error\n");
+#if 0
+ {
+ u_char scmd[2];
+
+ scmd[0] = PMS_SET_RES;
+ scmd[1] = 3; /* 8 counts/mm */
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
+ 2, 0, 1, 0);
+ if (res)
+ printf("pms_enable: setup error1 (%d)\n", res);
+
+ scmd[0] = PMS_SET_SCALE21;
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
+ 1, 0, 1, 0);
+ if (res)
+ printf("pms_enable: setup error2 (%d)\n", res);
+
+ scmd[0] = PMS_SET_SAMPLE;
+ scmd[1] = 100; /* 100 samples/sec */
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
+ 2, 0, 1, 0);
+ if (res)
+ printf("pms_enable: setup error3 (%d)\n", res);
+ }
+#endif
+
+ return 0;
+}
+
+void
+pms_disable(v)
+ void *v;
+{
+ struct pms_softc *sc = v;
+ u_char cmd[1];
+ int res;
+
+ cmd[0] = PMS_DEV_DISABLE;
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
+ if (res)
+ printf("pms_disable: command error\n");
+
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+
+ sc->sc_enabled = 0;
+}
+
+int
+pms_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct pms_softc *sc = v;
+ u_char kbcmd[2];
+ int i;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_PS2;
+ break;
+
+ case WSMOUSEIO_SRES:
+ i = (*(u_int *)data - 12) / 25;
+
+ if (i < 0)
+ i = 0;
+
+ if (i > 3)
+ i = 3;
+
+ kbcmd[0] = PMS_SET_RES;
+ kbcmd[1] = i;
+ i = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, kbcmd,
+ 2, 0, 1, 0);
+
+ if (i)
+ printf("pms_ioctl: SET_RES command error\n");
+ break;
+
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/* Masks for the first byte of a packet */
+#define PS2LBUTMASK 0x01
+#define PS2RBUTMASK 0x02
+#define PS2MBUTMASK 0x04
+
+void pmsinput(vsc, data)
+void *vsc;
+int data;
+{
+ struct pms_softc *sc = vsc;
+ signed char dy;
+ u_int changed;
+
+ if (!sc->sc_enabled) {
+ /* Interrupts are not expected. Discard the byte. */
+ return;
+ }
+
+ switch (sc->inputstate) {
+
+ case 0:
+ if ((data & 0xc0) == 0) { /* no ovfl, bit 3 == 1 too? */
+ sc->buttons = ((data & PS2LBUTMASK) ? 0x1 : 0) |
+ ((data & PS2MBUTMASK) ? 0x2 : 0) |
+ ((data & PS2RBUTMASK) ? 0x4 : 0);
+ ++sc->inputstate;
+ }
+ break;
+
+ case 1:
+ sc->dx = data;
+ /* Bounding at -127 avoids a bug in XFree86. */
+ sc->dx = (sc->dx == -128) ? -127 : sc->dx;
+ ++sc->inputstate;
+ break;
+
+ case 2:
+ dy = data;
+ dy = (dy == -128) ? -127 : dy;
+ sc->inputstate = 0;
+
+ changed = (sc->buttons ^ sc->oldbuttons);
+ sc->oldbuttons = sc->buttons;
+
+ if (sc->dx || dy || changed)
+ wsmouse_input(sc->sc_wsmousedev,
+ sc->buttons, sc->dx, dy, 0,
+ WSMOUSE_INPUT_DELTA);
+ break;
+ }
+
+ return;
+}
+
+struct cfdriver pms_cd = {
+ NULL, "pms", DV_DULL
+};
diff --git a/sys/dev/pckbc/psm_intelli.c b/sys/dev/pckbc/psm_intelli.c
new file mode 100644
index 00000000000..795b8c852f0
--- /dev/null
+++ b/sys/dev/pckbc/psm_intelli.c
@@ -0,0 +1,357 @@
+/* $NetBSD: psm_intelli.c,v 1.8 2000/06/05 22:20:57 sommerfeld Exp $ */
+
+/*-
+ * Copyright (c) 1994 Charles M. Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/pckbcvar.h>
+
+#include <dev/pckbc/psmreg.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+struct pmsi_softc { /* driver status information */
+ struct device sc_dev;
+
+ pckbc_tag_t sc_kbctag;
+ int sc_kbcslot;
+
+ int sc_enabled; /* input enabled? */
+ int inputstate;
+ u_int buttons, oldbuttons; /* mouse button status */
+ signed char dx, dy;
+
+ struct device *sc_wsmousedev;
+};
+
+int pmsiprobe __P((struct device *, void *, void *));
+void pmsiattach __P((struct device *, struct device *, void *));
+void pmsiinput __P((void *, int));
+
+struct cfattach pmsi_ca = {
+ sizeof(struct pmsi_softc), pmsiprobe, pmsiattach,
+};
+
+int pmsi_enable __P((void *));
+int pmsi_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
+void pmsi_disable __P((void *));
+
+const struct wsmouse_accessops pmsi_accessops = {
+ pmsi_enable,
+ pmsi_ioctl,
+ pmsi_disable,
+};
+
+static int pmsi_setintellimode __P((pckbc_tag_t, pckbc_slot_t));
+
+static int
+pmsi_setintellimode(tag, slot)
+ pckbc_tag_t tag;
+ pckbc_slot_t slot;
+{
+ u_char cmd[2], resp[1];
+ int i, res;
+ static u_char rates[] = {200, 100, 80};
+
+ cmd[0] = PMS_SET_SAMPLE;
+ for (i = 0; i < 3; i++) {
+ cmd[1] = rates[i];
+ res = pckbc_poll_cmd(tag, slot, cmd, 2, 0, 0, 0);
+ if (res)
+ return (res);
+ }
+
+ cmd[0] = PMS_SEND_DEV_ID;
+ res = pckbc_poll_cmd(tag, slot, cmd, 1, 1, resp, 0);
+ if (res)
+ return (res);
+ if (resp[0] != 3)
+ return (ENXIO);
+
+ return (0);
+}
+
+int
+pmsiprobe(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct pckbc_attach_args *pa = aux;
+ u_char cmd[1], resp[2];
+ int res;
+
+ if (pa->pa_slot != PCKBC_AUX_SLOT)
+ return (0);
+
+ /* Flush any garbage. */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ /* reset the device */
+ cmd[0] = PMS_RESET;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+ if (res) {
+#ifdef DEBUG
+ printf("pmsiprobe: reset error %d\n", res);
+#endif
+ return (0);
+ }
+ if (resp[0] != PMS_RSTDONE) {
+ printf("pmsiprobe: reset response 0x%x\n", resp[0]);
+ return (0);
+ }
+
+ /* get type number (0 = mouse) */
+ if (resp[1] != 0) {
+#ifdef DEBUG
+ printf("pmsiprobe: type 0x%x\n", resp[1]);
+#endif
+ return (0);
+ }
+
+ if ((res = pmsi_setintellimode(pa->pa_tag, pa->pa_slot))) {
+#ifdef DEBUG
+ printf("pmsiprobe: intellimode -> %d\n", res);
+#endif
+ return (0);
+ }
+
+ return (20);
+}
+
+void
+pmsiattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pmsi_softc *sc = (void *)self;
+ struct pckbc_attach_args *pa = aux;
+ struct wsmousedev_attach_args a;
+ u_char cmd[1], resp[2];
+ int res;
+
+ sc->sc_kbctag = pa->pa_tag;
+ sc->sc_kbcslot = pa->pa_slot;
+
+ printf("\n");
+
+ /* Flush any garbage. */
+ pckbc_flush(pa->pa_tag, pa->pa_slot);
+
+ /* reset the device */
+ cmd[0] = PMS_RESET;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+#ifdef DEBUG
+ if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) {
+ printf("pmsiattach: reset error\n");
+ return;
+ }
+#endif
+ res = pmsi_setintellimode(pa->pa_tag, pa->pa_slot);
+#ifdef DEBUG
+ if (res) {
+ printf("pmsiattach: error setting intelli mode\n");
+ return;
+ }
+#endif
+
+ /* Other initialization was done by pmsiprobe. */
+ sc->inputstate = 0;
+ sc->oldbuttons = 0;
+
+ pckbc_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot,
+ pmsiinput, sc, sc->sc_dev.dv_xname);
+
+ a.accessops = &pmsi_accessops;
+ a.accesscookie = sc;
+
+ /*
+ * Attach the wsmouse, saving a handle to it.
+ * Note that we don't need to check this pointer against NULL
+ * here or in pmsintr, because if this fails pms_enable() will
+ * never be called, so pmsiinput() will never be called.
+ */
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+
+ /* no interrupts until enabled */
+ cmd[0] = PMS_DEV_DISABLE;
+ res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, 0, 0);
+ if (res)
+ printf("pmsiattach: disable error\n");
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+}
+
+int
+pmsi_enable(v)
+ void *v;
+{
+ struct pmsi_softc *sc = v;
+ u_char cmd[1];
+ int res;
+
+ if (sc->sc_enabled)
+ return EBUSY;
+
+ sc->sc_enabled = 1;
+ sc->inputstate = 0;
+ sc->oldbuttons = 0;
+
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1);
+
+ cmd[0] = PMS_DEV_ENABLE;
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
+ if (res)
+ printf("pmsi_enable: command error\n");
+
+ return 0;
+}
+
+void
+pmsi_disable(v)
+ void *v;
+{
+ struct pmsi_softc *sc = v;
+ u_char cmd[1];
+ int res;
+
+ cmd[0] = PMS_DEV_DISABLE;
+ res = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
+ if (res)
+ printf("pmsi_disable: command error\n");
+
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+
+ sc->sc_enabled = 0;
+}
+
+int
+pmsi_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct pmsi_softc *sc = v;
+ u_char kbcmd[2];
+ int i;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_PS2;
+ break;
+
+ case WSMOUSEIO_SRES:
+ i = (*(u_int *)data - 12) / 25;
+
+ if (i < 0)
+ i = 0;
+
+ if (i > 3)
+ i = 3;
+
+ kbcmd[0] = PMS_SET_RES;
+ kbcmd[1] = i;
+ i = pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, kbcmd,
+ 2, 0, 1, 0);
+
+ if (i)
+ printf("pms_ioctl: SET_RES command error\n");
+ break;
+
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/* Masks for the first byte of a packet */
+#define PS2LBUTMASK 0x01
+#define PS2RBUTMASK 0x02
+#define PS2MBUTMASK 0x04
+
+void pmsiinput(vsc, data)
+void *vsc;
+int data;
+{
+ struct pmsi_softc *sc = vsc;
+ signed char dz;
+ u_int changed;
+
+ if (!sc->sc_enabled) {
+ /* Interrupts are not expected. Discard the byte. */
+ return;
+ }
+
+ switch (sc->inputstate) {
+
+ case 0:
+ if ((data & 0xc0) == 0) { /* no ovfl, bit 3 == 1 too? */
+ sc->buttons = ((data & PS2LBUTMASK) ? 0x1 : 0) |
+ ((data & PS2MBUTMASK) ? 0x2 : 0) |
+ ((data & PS2RBUTMASK) ? 0x4 : 0);
+ ++sc->inputstate;
+ }
+ break;
+
+ case 1:
+ sc->dx = data;
+ /* Bounding at -127 avoids a bug in XFree86. */
+ sc->dx = (sc->dx == -128) ? -127 : sc->dx;
+ ++sc->inputstate;
+ break;
+
+ case 2:
+ sc->dy = data;
+ sc->dy = (sc->dy == -128) ? -127 : sc->dy;
+ ++sc->inputstate;
+ break;
+
+ case 3:
+ dz = data;
+ dz = (dz == -128) ? -127 : dz;
+ sc->inputstate = 0;
+
+ changed = (sc->buttons ^ sc->oldbuttons);
+ sc->oldbuttons = sc->buttons;
+
+ if (sc->dx || sc->dy || dz || changed)
+ wsmouse_input(sc->sc_wsmousedev,
+ sc->buttons, sc->dx, sc->dy, dz,
+ WSMOUSE_INPUT_DELTA);
+ break;
+ }
+
+ return;
+}
+
+struct cfdriver pmsi_cd = {
+ NULL, "pmsi", DV_DULL
+};
diff --git a/sys/dev/pckbc/psmreg.h b/sys/dev/pckbc/psmreg.h
new file mode 100644
index 00000000000..c6da5dbf969
--- /dev/null
+++ b/sys/dev/pckbc/psmreg.h
@@ -0,0 +1,19 @@
+/* $NetBSD: psmreg.h,v 1.1 1998/03/22 15:41:28 drochner Exp $ */
+
+/* mouse commands */
+#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */
+#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */
+#define PMS_SET_RES 0xe8 /* set resolution (0..3) */
+#define PMS_GET_SCALE 0xe9 /* get scaling factor */
+#define PMS_SEND_DEV_STATUS 0xe9
+#define PMS_SET_STREAM 0xea /* set streaming mode */
+#define PMS_SEND_DEV_DATA 0xeb
+#define PMS_SET_REMOTE_MODE 0xf0
+#define PMS_SEND_DEV_ID 0xf2
+#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
+#define PMS_DEV_ENABLE 0xf4 /* mouse on */
+#define PMS_DEV_DISABLE 0xf5 /* mouse off */
+#define PMS_SET_DEFAULTS 0xf6
+#define PMS_RESET 0xff /* reset */
+
+#define PMS_RSTDONE 0xaa
diff --git a/sys/dev/pckbc/wskbdmap_mfii.c b/sys/dev/pckbc/wskbdmap_mfii.c
new file mode 100644
index 00000000000..369232e0af1
--- /dev/null
+++ b/sys/dev/pckbc/wskbdmap_mfii.c
@@ -0,0 +1,515 @@
+/* $OpenBSD: wskbdmap_mfii.c,v 1.1 2000/11/13 20:12:35 aaron Exp $ */
+/* $NetBSD: wskbdmap_mfii.c,v 1.15 2000/05/19 16:40:04 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juergen Hannken-Illjes.
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+#include <dev/pckbc/wskbdmap_mfii.h>
+
+#define KC(n) KS_KEYCODE(n)
+
+static const keysym_t pckbd_keydesc_us[] = {
+/* pos command normal shifted */
+ KC(1), KS_Cmd_Debugger, KS_Escape,
+ KC(2), KS_1, KS_exclam,
+ KC(3), KS_2, KS_at,
+ KC(4), KS_3, KS_numbersign,
+ KC(5), KS_4, KS_dollar,
+ KC(6), KS_5, KS_percent,
+ KC(7), KS_6, KS_asciicircum,
+ KC(8), KS_7, KS_ampersand,
+ KC(9), KS_8, KS_asterisk,
+ KC(10), KS_9, KS_parenleft,
+ KC(11), KS_0, KS_parenright,
+ KC(12), KS_minus, KS_underscore,
+ KC(13), KS_equal, KS_plus,
+ KC(14), KS_Cmd_ResetEmul, KS_Delete,
+ KC(15), KS_Tab,
+ KC(16), KS_q,
+ KC(17), KS_w,
+ KC(18), KS_e,
+ KC(19), KS_r,
+ KC(20), KS_t,
+ KC(21), KS_y,
+ KC(22), KS_u,
+ KC(23), KS_i,
+ KC(24), KS_o,
+ KC(25), KS_p,
+ KC(26), KS_bracketleft, KS_braceleft,
+ KC(27), KS_bracketright, KS_braceright,
+ KC(28), KS_Return,
+ KC(29), KS_Cmd1, KS_Control_L,
+ KC(30), KS_a,
+ KC(31), KS_s,
+ KC(32), KS_d,
+ KC(33), KS_f,
+ KC(34), KS_g,
+ KC(35), KS_h,
+ KC(36), KS_j,
+ KC(37), KS_k,
+ KC(38), KS_l,
+ KC(39), KS_semicolon, KS_colon,
+ KC(40), KS_apostrophe, KS_quotedbl,
+ KC(41), KS_grave, KS_asciitilde,
+ KC(42), KS_Shift_L,
+ KC(43), KS_backslash, KS_bar,
+ KC(44), KS_z,
+ KC(45), KS_x,
+ KC(46), KS_c,
+ KC(47), KS_v,
+ KC(48), KS_b,
+ KC(49), KS_n,
+ KC(50), KS_m,
+ KC(51), KS_comma, KS_less,
+ KC(52), KS_period, KS_greater,
+ KC(53), KS_slash, KS_question,
+ KC(54), KS_Shift_R,
+ KC(55), KS_KP_Multiply,
+ KC(56), KS_Cmd2, KS_Alt_L,
+ KC(57), KS_space,
+ KC(58), KS_Caps_Lock,
+ KC(59), KS_Cmd_Screen0, KS_f1,
+ KC(60), KS_Cmd_Screen1, KS_f2,
+ KC(61), KS_Cmd_Screen2, KS_f3,
+ KC(62), KS_Cmd_Screen3, KS_f4,
+ KC(63), KS_Cmd_Screen4, KS_f5,
+ KC(64), KS_Cmd_Screen5, KS_f6,
+ KC(65), KS_Cmd_Screen6, KS_f7,
+ KC(66), KS_Cmd_Screen7, KS_f8,
+ KC(67), KS_Cmd_Screen8, KS_f9,
+ KC(68), KS_Cmd_Screen9, KS_f10,
+ KC(69), KS_Num_Lock,
+ KC(70), KS_Hold_Screen,
+ KC(71), KS_KP_Home, KS_KP_7,
+ KC(72), KS_KP_Up, KS_KP_8,
+ KC(73), KS_KP_Prior, KS_KP_9,
+ KC(74), KS_KP_Subtract,
+ KC(75), KS_KP_Left, KS_KP_4,
+ KC(76), KS_KP_Begin, KS_KP_5,
+ KC(77), KS_KP_Right, KS_KP_6,
+ KC(78), KS_KP_Add,
+ KC(79), KS_KP_End, KS_KP_1,
+ KC(80), KS_KP_Down, KS_KP_2,
+ KC(81), KS_KP_Next, KS_KP_3,
+ KC(82), KS_KP_Insert, KS_KP_0,
+ KC(83), KS_KP_Delete, KS_KP_Decimal,
+ KC(87), KS_f11,
+ KC(88), KS_f12,
+ KC(127), KS_Pause, /* Break */
+ KC(156), KS_KP_Enter,
+ KC(157), KS_Control_R,
+ KC(170), KS_Print_Screen,
+ KC(181), KS_KP_Divide,
+ KC(183), KS_Print_Screen,
+ KC(184), KS_Alt_R, KS_Multi_key,
+#if 0
+ KC(198), KS_Cmd_ResetClose, /* CTL-Break */
+#endif
+ KC(199), KS_Home,
+ KC(200), KS_Up,
+ KC(201), KS_Prior,
+ KC(203), KS_Left,
+ KC(205), KS_Right,
+ KC(207), KS_End,
+ KC(208), KS_Down,
+ KC(209), KS_Next,
+ KC(210), KS_Insert,
+ KC(211), KS_KP_Delete,
+ KC(219), KS_Meta_L,
+ KC(220), KS_Meta_R,
+ KC(221), KS_Menu,
+};
+
+static const keysym_t pckbd_keydesc_de[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(3), KS_2, KS_quotedbl, KS_twosuperior,
+ KC(4), KS_3, KS_section, KS_threesuperior,
+ KC(7), KS_6, KS_ampersand,
+ KC(8), KS_7, KS_slash, KS_braceleft,
+ KC(9), KS_8, KS_parenleft, KS_bracketleft,
+ KC(10), KS_9, KS_parenright, KS_bracketright,
+ KC(11), KS_0, KS_equal, KS_braceright,
+ KC(12), KS_ssharp, KS_question, KS_backslash,
+ KC(13), KS_dead_acute, KS_dead_grave,
+ KC(16), KS_q, KS_Q, KS_at,
+ KC(21), KS_z,
+ KC(26), KS_udiaeresis,
+ KC(27), KS_plus, KS_asterisk, KS_dead_tilde,
+ KC(39), KS_odiaeresis,
+ KC(40), KS_adiaeresis,
+ KC(41), KS_dead_circumflex,KS_dead_abovering,
+ KC(43), KS_numbersign, KS_apostrophe,
+ KC(44), KS_y,
+ KC(50), KS_m, KS_M, KS_mu,
+ KC(51), KS_comma, KS_semicolon,
+ KC(52), KS_period, KS_colon,
+ KC(53), KS_minus, KS_underscore,
+ KC(86), KS_less, KS_greater, KS_bar, KS_brokenbar,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_de_nodead[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(13), KS_apostrophe, KS_grave,
+ KC(27), KS_plus, KS_asterisk, KS_asciitilde,
+ KC(41), KS_asciicircum, KS_degree,
+};
+
+static const keysym_t pckbd_keydesc_dk[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(3), KS_2, KS_quotedbl, KS_at,
+ KC(4), KS_3, KS_numbersign, KS_sterling,
+ KC(5), KS_4, KS_currency, KS_dollar,
+ KC(7), KS_6, KS_ampersand,
+ KC(8), KS_7, KS_slash, KS_braceleft,
+ KC(9), KS_8, KS_parenleft, KS_bracketleft,
+ KC(10), KS_9, KS_parenright, KS_bracketright,
+ KC(11), KS_0, KS_equal, KS_braceright,
+ KC(12), KS_plus, KS_question,
+ KC(13), KS_dead_acute, KS_dead_grave, KS_bar,
+ KC(26), KS_aring,
+ KC(27), KS_dead_diaeresis, KS_dead_circumflex, KS_dead_tilde,
+ KC(39), KS_ae,
+ KC(40), KS_oslash,
+ KC(41), KS_onehalf, KS_paragraph,
+ KC(43), KS_apostrophe, KS_asterisk,
+ KC(51), KS_comma, KS_semicolon,
+ KC(52), KS_period, KS_colon,
+ KC(53), KS_minus, KS_underscore,
+ KC(86), KS_less, KS_greater, KS_backslash,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_dk_nodead[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(13), KS_apostrophe, KS_grave, KS_bar,
+ KC(27), KS_diaeresis, KS_asciicircum, KS_asciitilde,
+};
+
+static const keysym_t pckbd_keydesc_sv[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(12), KS_plus, KS_question, KS_backslash,
+ KC(27), KS_dead_diaeresis, KS_dead_circumflex, KS_dead_tilde,
+ KC(39), KS_odiaeresis,
+ KC(40), KS_adiaeresis,
+ KC(41), KS_paragraph, KS_onehalf,
+ KC(86), KS_less, KS_greater, KS_bar,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_sv_nodead[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(13), KS_apostrophe, KS_grave, KS_bar,
+ KC(27), KS_diaeresis, KS_asciicircum, KS_asciitilde,
+};
+
+static const keysym_t pckbd_keydesc_no[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(13), KS_backslash, KS_dead_grave, KS_dead_acute,
+ KC(27), KS_dead_diaeresis, KS_dead_circumflex, KS_dead_tilde,
+ KC(39), KS_oslash,
+ KC(40), KS_ae,
+ KC(41), KS_bar, KS_paragraph,
+ KC(86), KS_less, KS_greater,
+};
+
+static const keysym_t pckbd_keydesc_no_nodead[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(13), KS_backslash, KS_grave, KS_acute,
+ KC(27), KS_diaeresis, KS_asciicircum, KS_asciitilde,
+};
+
+static const keysym_t pckbd_keydesc_fr[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(2), KS_ampersand, KS_1,
+ KC(3), KS_eacute, KS_2, KS_asciitilde,
+ KC(4), KS_quotedbl, KS_3, KS_numbersign,
+ KC(5), KS_apostrophe, KS_4, KS_braceleft,
+ KC(6), KS_parenleft, KS_5, KS_bracketleft,
+ KC(7), KS_minus, KS_6, KS_bar,
+ KC(8), KS_egrave, KS_7, KS_grave,
+ KC(9), KS_underscore, KS_8, KS_backslash,
+ KC(10), KS_ccedilla, KS_9, KS_asciicircum,
+ KC(11), KS_agrave, KS_0, KS_at,
+ KC(12), KS_parenright, KS_degree, KS_bracketright,
+ KC(13), KS_equal, KS_plus, KS_braceright,
+ KC(16), KS_a,
+ KC(17), KS_z,
+ KC(26), KS_dead_circumflex, KS_dead_diaeresis,
+ KC(27), KS_dollar, KS_sterling, KS_currency,
+ KC(30), KS_q,
+ KC(39), KS_m,
+ KC(40), KS_ugrave, KS_percent,
+ KC(41), KS_twosuperior,
+ KC(43), KS_asterisk, KS_mu,
+ KC(44), KS_w,
+ KC(50), KS_comma, KS_question,
+ KC(51), KS_semicolon, KS_period,
+ KC(52), KS_colon, KS_slash,
+ KC(53), KS_exclam, KS_section,
+ KC(86), KS_less, KS_greater,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_it[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(3), KS_2, KS_quotedbl, KS_twosuperior,
+ KC(4), KS_3, KS_sterling, KS_threesuperior,
+ KC(5), KS_4, KS_dollar,
+ KC(6), KS_5, KS_percent,
+ KC(7), KS_6, KS_ampersand,
+ KC(8), KS_7, KS_slash,
+ KC(9), KS_8, KS_parenleft,
+ KC(10), KS_9, KS_parenright,
+ KC(11), KS_0, KS_equal,
+ KC(12), KS_apostrophe, KS_question,
+ KC(13), KS_igrave, KS_asciicircum,
+ KC(26), KS_egrave, KS_eacute, KS_braceleft, KS_bracketleft,
+ KC(27), KS_plus, KS_asterisk, KS_braceright, KS_bracketright,
+ KC(39), KS_ograve, KS_Ccedilla, KS_at,
+ KC(40), KS_agrave, KS_degree, KS_numbersign,
+ KC(41), KS_backslash, KS_bar,
+ KC(43), KS_ugrave, KS_section,
+ KC(51), KS_comma, KS_semicolon,
+ KC(52), KS_period, KS_colon,
+ KC(53), KS_minus, KS_underscore,
+ KC(86), KS_less, KS_greater,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_uk[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(2), KS_1, KS_exclam, KS_plusminus, KS_exclamdown,
+ KC(3), KS_2, KS_quotedbl, KS_twosuperior, KS_cent,
+ KC(4), KS_3, KS_sterling, KS_threesuperior,
+ KC(5), KS_4, KS_dollar, KS_acute, KS_currency,
+ KC(6), KS_5, KS_percent, KS_mu, KS_yen,
+ KC(7), KS_6, KS_asciicircum, KS_paragraph,
+ KC(8), KS_7, KS_ampersand, KS_periodcentered, KS_brokenbar,
+ KC(9), KS_8, KS_asterisk, KS_cedilla, KS_ordfeminine,
+ KC(10), KS_9, KS_parenleft, KS_onesuperior, KS_diaeresis,
+ KC(11), KS_0, KS_parenright, KS_masculine, KS_copyright,
+ KC(12), KS_minus, KS_underscore, KS_hyphen, KS_ssharp,
+ KC(13), KS_equal, KS_plus, KS_onehalf, KS_guillemotleft,
+ KC(40), KS_apostrophe, KS_at, KS_section, KS_Agrave,
+ KC(41), KS_grave, KS_grave, KS_agrave, KS_agrave,
+ KC(43), KS_numbersign, KS_asciitilde, KS_sterling, KS_thorn,
+ KC(86), KS_backslash, KS_bar, KS_Udiaeresis,
+};
+
+static const keysym_t pckbd_keydesc_jp[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(3), KS_2, KS_quotedbl,
+ KC(7), KS_6, KS_ampersand,
+ KC(8), KS_7, KS_apostrophe,
+ KC(9), KS_8, KS_parenleft,
+ KC(10), KS_9, KS_parenright,
+ KC(11), KS_0,
+ KC(12), KS_minus, KS_equal,
+ KC(13), KS_asciicircum, KS_asciitilde,
+ KC(26), KS_at, KS_grave,
+ KC(27), KS_bracketleft, KS_braceleft,
+ KC(39), KS_semicolon, KS_plus,
+ KC(40), KS_colon, KS_asterisk,
+ KC(41), KS_Zenkaku_Hankaku, /* replace grave/tilde */
+ KC(43), KS_bracketright, KS_braceright,
+ KC(112), KS_Hiragana_Katakana,
+ KC(115), KS_backslash, KS_underscore,
+ KC(121), KS_Henkan,
+ KC(123), KS_Muhenkan,
+ KC(125), KS_backslash, KS_bar,
+};
+
+static const keysym_t pckbd_keydesc_es[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(2), KS_1, KS_exclam, KS_bar,
+ KC(3), KS_2, KS_quotedbl, KS_at,
+ KC(4), KS_3, KS_periodcentered, KS_numbersign,
+ KC(5), KS_4, KS_dollar, KS_asciitilde,
+ KC(7), KS_6, KS_ampersand,
+ KC(8), KS_7, KS_slash,
+ KC(9), KS_8, KS_parenleft,
+ KC(10), KS_9, KS_parenright,
+ KC(11), KS_0, KS_equal,
+ KC(12), KS_grave, KS_question,
+ KC(13), KS_exclamdown, KS_questiondown,
+ KC(26), KS_dead_grave, KS_dead_circumflex, KS_bracketleft,
+ KC(27), KS_plus, KS_asterisk, KS_bracketright,
+ KC(39), KS_ntilde,
+ KC(40), KS_dead_acute, KS_dead_diaeresis, KS_braceleft,
+ KC(41), KS_degree, KS_ordfeminine, KS_backslash,
+ KC(43), KS_ccedilla, KS_Ccedilla, KS_braceright,
+ KC(51), KS_comma, KS_semicolon,
+ KC(52), KS_period, KS_colon,
+ KC(53), KS_minus, KS_underscore,
+ KC(86), KS_less, KS_greater,
+ KC(184), KS_Mode_switch, KS_Multi_key,
+};
+
+static const keysym_t pckbd_keydesc_us_declk[] = {
+/* pos normal shifted altgr shift-altgr */
+ KC(1), KS_grave, KS_asciitilde, /* replace escape */
+ KC(41), KS_less, KS_greater, /* replace grave/tilde */
+ KC(143), KS_Multi_key, /* left compose */
+ KC(157), KS_Multi_key, /* right compose, replace right control */
+ KC(87), KS_Cmd_Debugger, KS_Escape, /* replace F11 */
+ KC(189), KS_f13,
+ KC(190), KS_f14,
+ KC(191), KS_Help,
+ KC(192), KS_Execute,
+ KC(193), KS_f17,
+ KC(183), KS_f18,
+ KC(70), KS_f19, /* replace scroll lock */
+ KC(127), KS_f20, /* replace break */
+ KC(69), KS_KP_F1, /* replace num lock */
+ KC(181), KS_KP_F2, /* replace divide */
+ KC(55), KS_KP_F3, /* replace multiply */
+ KC(74), KS_KP_F4, /* replace subtract */
+
+ /* keypad is numbers only - no num lock */
+ KC(71), KS_KP_7,
+ KC(72), KS_KP_8,
+ KC(73), KS_KP_9,
+ KC(75), KS_KP_4,
+ KC(76), KS_KP_5,
+ KC(77), KS_KP_6,
+ KC(79), KS_KP_1,
+ KC(80), KS_KP_2,
+ KC(81), KS_KP_3,
+ KC(82), KS_KP_0,
+ KC(83), KS_KP_Decimal,
+
+ KC(206), KS_KP_Subtract,
+ KC(78), KS_KP_Separator, /* replace add */
+ KC(199), KS_Find, /* replace home */
+ KC(207), KS_Select, /* replace end */
+};
+
+static const keysym_t pckbd_keydesc_us_dvorak[] = {
+/* pos command normal shifted */
+ KC(12), KS_bracketleft, KS_braceleft,
+ KC(13), KS_bracketright, KS_braceright,
+ KC(16), KS_apostrophe, KS_quotedbl,
+ KC(17), KS_comma, KS_less,
+ KC(18), KS_period, KS_greater,
+ KC(19), KS_p,
+ KC(20), KS_y,
+ KC(21), KS_f,
+ KC(22), KS_g,
+ KC(23), KS_c,
+ KC(24), KS_r,
+ KC(25), KS_l,
+ KC(26), KS_slash, KS_question,
+ KC(27), KS_equal, KS_plus,
+ KC(31), KS_o,
+ KC(32), KS_e,
+ KC(33), KS_u,
+ KC(34), KS_i,
+ KC(35), KS_d,
+ KC(36), KS_h,
+ KC(37), KS_t,
+ KC(38), KS_n,
+ KC(39), KS_s,
+ KC(40), KS_minus, KS_underscore,
+ KC(44), KS_semicolon, KS_colon,
+ KC(45), KS_q,
+ KC(46), KS_j,
+ KC(47), KS_k,
+ KC(48), KS_x,
+ KC(49), KS_b,
+ KC(51), KS_w,
+ KC(52), KS_v,
+ KC(53), KS_z,
+};
+
+static const keysym_t pckbd_keydesc_swapctrlcaps[] = {
+/* pos command normal shifted */
+ KC(29), KS_Caps_Lock,
+ KC(58), KS_Cmd1, KS_Control_L,
+};
+
+static const keysym_t pckbd_keydesc_iopener[] = {
+/* pos command normal shifted */
+ KC(59), KS_Cmd_Debugger, KS_Escape,
+ KC(60), KS_Cmd_Screen0, KS_f1,
+ KC(61), KS_Cmd_Screen1, KS_f2,
+ KC(62), KS_Cmd_Screen2, KS_f3,
+ KC(63), KS_Cmd_Screen3, KS_f4,
+ KC(64), KS_Cmd_Screen4, KS_f5,
+ KC(65), KS_Cmd_Screen5, KS_f6,
+ KC(66), KS_Cmd_Screen6, KS_f7,
+ KC(67), KS_Cmd_Screen7, KS_f8,
+ KC(68), KS_Cmd_Screen8, KS_f9,
+ KC(87), KS_Cmd_Screen9, KS_f10,
+ KC(88), KS_f11,
+};
+
+#define KBD_MAP(name, base, map) \
+ { name, base, sizeof(map)/sizeof(keysym_t), map }
+
+const struct wscons_keydesc pckbd_keydesctab[] = {
+ KBD_MAP(KB_US, 0, pckbd_keydesc_us),
+ KBD_MAP(KB_DE, KB_US, pckbd_keydesc_de),
+ KBD_MAP(KB_DE | KB_NODEAD, KB_DE, pckbd_keydesc_de_nodead),
+ KBD_MAP(KB_FR, KB_US, pckbd_keydesc_fr),
+ KBD_MAP(KB_DK, KB_US, pckbd_keydesc_dk),
+ KBD_MAP(KB_DK | KB_NODEAD, KB_DK, pckbd_keydesc_dk_nodead),
+ KBD_MAP(KB_IT, KB_US, pckbd_keydesc_it),
+ KBD_MAP(KB_UK, KB_US, pckbd_keydesc_uk),
+ KBD_MAP(KB_JP, KB_US, pckbd_keydesc_jp),
+ KBD_MAP(KB_SV, KB_DK, pckbd_keydesc_sv),
+ KBD_MAP(KB_SV | KB_NODEAD, KB_SV, pckbd_keydesc_sv_nodead),
+ KBD_MAP(KB_NO, KB_DK, pckbd_keydesc_no),
+ KBD_MAP(KB_NO | KB_NODEAD, KB_NO, pckbd_keydesc_no_nodead),
+ KBD_MAP(KB_US | KB_DECLK, KB_US, pckbd_keydesc_us_declk),
+ KBD_MAP(KB_US | KB_DVORAK, KB_US, pckbd_keydesc_us_dvorak),
+ KBD_MAP(KB_US | KB_SWAPCTRLCAPS, KB_US, pckbd_keydesc_swapctrlcaps),
+ KBD_MAP(KB_US | KB_IOPENER, KB_US, pckbd_keydesc_iopener),
+ KBD_MAP(KB_JP | KB_SWAPCTRLCAPS, KB_JP, pckbd_keydesc_swapctrlcaps),
+ KBD_MAP(KB_FR | KB_SWAPCTRLCAPS, KB_FR, pckbd_keydesc_swapctrlcaps),
+ KBD_MAP(KB_US | KB_DVORAK | KB_SWAPCTRLCAPS, KB_US | KB_DVORAK,
+ pckbd_keydesc_swapctrlcaps),
+ KBD_MAP(KB_US | KB_IOPENER | KB_SWAPCTRLCAPS, KB_US | KB_IOPENER,
+ pckbd_keydesc_swapctrlcaps),
+ KBD_MAP(KB_ES , KB_US, pckbd_keydesc_es),
+ {0, 0, 0, 0}
+};
+
+#undef KBD_MAP
+#undef KC
diff --git a/sys/dev/pckbc/wskbdmap_mfii.h b/sys/dev/pckbc/wskbdmap_mfii.h
new file mode 100644
index 00000000000..b35bbbeff95
--- /dev/null
+++ b/sys/dev/pckbc/wskbdmap_mfii.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: wskbdmap_mfii.h,v 1.1 2000/11/13 20:12:35 aaron Exp $ */
+/* $NetBSD: wskbdmap_mfii.h,v 1.1 1998/09/17 18:21:04 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juergen Hannken-Illjes.
+ *
+ * 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.
+ */
+
+extern const struct wscons_keydesc pckbd_keydesctab[];