diff options
-rw-r--r-- | sys/dev/ic/pckbc.c | 995 | ||||
-rw-r--r-- | sys/dev/ic/pckbcvar.h | 118 | ||||
-rw-r--r-- | sys/dev/isa/pckbc_isa.c | 191 | ||||
-rw-r--r-- | sys/dev/pckbc/Makefile | 8 | ||||
-rw-r--r-- | sys/dev/pckbc/files.pckbc | 17 | ||||
-rw-r--r-- | sys/dev/pckbc/pckbd.c | 692 | ||||
-rw-r--r-- | sys/dev/pckbc/pckbdreg.h | 28 | ||||
-rw-r--r-- | sys/dev/pckbc/pckbdvar.h | 6 | ||||
-rw-r--r-- | sys/dev/pckbc/psm.c | 332 | ||||
-rw-r--r-- | sys/dev/pckbc/psm_intelli.c | 357 | ||||
-rw-r--r-- | sys/dev/pckbc/psmreg.h | 19 | ||||
-rw-r--r-- | sys/dev/pckbc/wskbdmap_mfii.c | 515 | ||||
-rw-r--r-- | sys/dev/pckbc/wskbdmap_mfii.h | 40 |
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[]; |