/* $NetBSD: nextkbd.c,v 1.1 1999/01/28 11:46:23 dbj Exp $ */ /* * Copyright (c) 1998 Matt DeBergalis * 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 by Matt DeBergalis * 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 /* RCS ID & Copyright macro defns */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct nextkbd_internal { int num_ints; /* interrupt total */ int polling; int isconsole; bus_space_tag_t iot; bus_space_handle_t ioh; struct nextkbd_softc *t_sc; /* back pointer */ u_int32_t mods; }; struct mon_regs { u_int32_t mon_csr; u_int32_t mon_1; u_int32_t mon_data; }; int nextkbd_match __P((struct device *, struct cfdata *, void *)); void nextkbd_attach __P((struct device *, struct device *, void *)); int nextkbc_cnattach __P((bus_space_tag_t)); struct cfattach nextkbd_ca = { sizeof(struct nextkbd_softc), nextkbd_match, nextkbd_attach }; int nextkbd_enable __P((void *, int)); void nextkbd_set_leds __P((void *, int)); int nextkbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); const struct wskbd_accessops nextkbd_accessops = { nextkbd_enable, nextkbd_set_leds, nextkbd_ioctl, }; void nextkbd_cngetc __P((void *, u_int *, int *)); void nextkbd_cnpollc __P((void *, int)); const struct wskbd_consops nextkbd_consops = { nextkbd_cngetc, nextkbd_cnpollc, }; const struct wskbd_mapdata nextkbd_keymapdata = { nextkbd_keydesctab, KB_US, }; static int nextkbd_poll_data __P((bus_space_tag_t, bus_space_handle_t)); static int nextkbd_decode __P((struct nextkbd_internal *, int, u_int *, int *)); static struct nextkbd_internal nextkbd_consdata; static int nextkbd_is_console __P((bus_space_tag_t bst)); int nextkbdhard __P((void *)); static int nextkbd_is_console(bst) bus_space_tag_t bst; { return (nextkbd_consdata.isconsole && (bst == nextkbd_consdata.iot)); } int nextkbd_match(parent, match, aux) struct device *parent; struct cfdata *match; void *aux; { return 1; } void nextkbd_attach(parent, self, aux) struct device *parent, *self; void *aux; { struct nextkbd_softc *sc = (struct nextkbd_softc *)self; int isconsole; struct wskbddev_attach_args a; printf("\n"); isconsole = nextkbd_is_console(NEXT68K_INTIO_BUS_SPACE); /* XXX */ if (isconsole) { sc->id = &nextkbd_consdata; } else { sc->id = malloc(sizeof(struct nextkbd_internal), M_DEVBUF, M_WAITOK); bzero(sc->id, sizeof(struct nextkbd_internal)); sc->id->iot = NEXT68K_INTIO_BUS_SPACE; if (bus_space_map(sc->id->iot, NEXT_P_MON, sizeof(struct mon_regs), 0, &sc->id->ioh)) { printf("%s: can't map mon status control register\n", sc->sc_dev.dv_xname); return; } } sc->id->t_sc = sc; /* set back pointer */ isrlink_autovec(nextkbdhard, sc, NEXT_I_IPL(NEXT_I_KYBD_MOUSE), 0); INTR_ENABLE(NEXT_I_KYBD_MOUSE); a.console = isconsole; a.keymap = &nextkbd_keymapdata; a.accessops = &nextkbd_accessops; a.accesscookie = sc; /* * Attach the wskbd, saving a handle to it. * XXX XXX XXX */ sc->sc_wskbddev = config_found(self, &a, wskbddevprint); } int nextkbd_enable(v, on) void *v; int on; { /* XXX not sure if this should do anything */ printf("nextkbd_enable %d\n", on); return 0; } /* XXX not yet implemented */ void nextkbd_set_leds(v, leds) void *v; int leds; { return; } int nextkbd_ioctl(v, cmd, data, flag, p) void *v; u_long cmd; caddr_t data; int flag; struct proc *p; { /* XXX struct nextkbd_softc *nc = v; */ switch (cmd) { case WSKBDIO_GTYPE: /* XXX */ *(int *)data = WSKBD_TYPE_PC_AT; return (0); case WSKBDIO_SETLEDS: return (0); case WSKBDIO_GETLEDS: *(int *)data = 0; return (0); case WSKBDIO_COMPLEXBELL: return (0); } return -1; } int nextkbdhard(arg) void *arg; { register struct nextkbd_softc *sc = arg; struct mon_regs stat; unsigned char device; u_int32_t scan_code; int type, key; if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) return 0; #define CSR_INT 0x00800000 #define CSR_DATA 0x00400000 #define KD_KEYMASK 0x007f #define KD_DIRECTION 0x0080 /* pressed or released */ #define KD_CNTL 0x0100 #define KD_LSHIFT 0x0200 #define KD_RSHIFT 0x0400 #define KD_LCOMM 0x0800 #define KD_RCOMM 0x1000 #define KD_LALT 0x2000 #define KD_RALT 0x4000 #define KD_VALID 0x8000 /* only set for scancode keys ? */ #define KD_MODS 0x4f00 bus_space_read_region_4(sc->id->iot, sc->id->ioh, 0, &stat, 3); if (stat.mon_csr & CSR_INT) { if (stat.mon_csr & CSR_DATA) { sc->id->num_ints++; stat.mon_csr &= ~CSR_INT; bus_space_write_4(sc->id->iot, sc->id->ioh, 0, stat.mon_csr); device = stat.mon_data >> 28; if (device != 1) return(0); scan_code = stat.mon_data & 0xffff; if (nextkbd_decode(sc->id, scan_code, &type, &key)) { wskbd_input(sc->sc_wskbddev, type, key); } } } return(1); } int nextkbd_cnattach(bst) bus_space_tag_t bst; { bus_space_handle_t bsh; if (bus_space_map(bst, NEXT_P_MON, sizeof(struct mon_regs), 0, &bsh)) return (ENXIO); bzero(&nextkbd_consdata, sizeof(nextkbd_consdata)); nextkbd_consdata.iot = bst; nextkbd_consdata.ioh = bsh; nextkbd_consdata.isconsole = 1; wskbd_cnattach(&nextkbd_consops, &nextkbd_consdata, &nextkbd_keymapdata); return (0); } /* ARGSUSED */ void nextkbd_cngetc(v, type, data) void *v; u_int *type; int *data; { struct nextkbd_internal *t = v; int val; /* printf("cngetc: data at %08x (%08x)\n", t, v); */ for (;;) { val = nextkbd_poll_data(t->iot, t->ioh); /* printf("%08x\n", val); */ if ((val != -1) && nextkbd_decode(t, val, type, data)) return; } } void nextkbd_cnpollc(v, on) void *v; int on; { struct nextkbd_internal *t = v; printf("cnpollc %d\n", on); t->polling = on; if (on) { INTR_DISABLE(NEXT_I_KYBD_MOUSE); } else { INTR_ENABLE(NEXT_I_KYBD_MOUSE); } } static int nextkbd_poll_data(iot, ioh) bus_space_tag_t iot; bus_space_handle_t ioh; { int i; struct mon_regs stat; /* printf("cnstart\n"); */ for (i=100000; i; i--) { bus_space_read_region_4(iot, ioh, 0, &stat, 3); if ( (stat.mon_csr & CSR_DATA) ) { stat.mon_csr &= ~CSR_INT; if ( (stat.mon_data >> 28) == 1) { /* printf("cnkey %08x %08x\n", stat.mon_csr, stat.mon_data); */ bus_space_write_4(iot, ioh, 0, stat.mon_csr); return (stat.mon_data & 0xffff); } } } /* printf("cnend %08x %08x\n", stat.mon_csr, stat.mon_data); */ return (-1); } static int nextkbd_decode(id, datain, type, dataout) struct nextkbd_internal *id; int datain; u_int *type; int *dataout; { /* printf("datain %08x mods %08x\n", datain, id->mods); */ if ((datain ^ id->mods) & KD_LSHIFT) { id->mods ^= KD_LSHIFT; *dataout = 90; if (datain & KD_LSHIFT) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_RSHIFT) { id->mods ^= KD_RSHIFT; *dataout = 91; if (datain & KD_RSHIFT) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_LALT) { id->mods ^= KD_LALT; *dataout = 92; if (datain & KD_LALT) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_RALT) { id->mods ^= KD_RALT; *dataout = 93; if (datain & KD_RALT) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_CNTL) { id->mods ^= KD_CNTL; *dataout = 94; if (datain & KD_CNTL) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_LCOMM) { id->mods ^= KD_LCOMM; *dataout = 95; if (datain & KD_LCOMM) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if ((datain ^ id->mods) & KD_RCOMM) { id->mods ^= KD_RCOMM; *dataout = 96; if (datain & KD_RCOMM) *type = WSCONS_EVENT_KEY_DOWN; else *type = WSCONS_EVENT_KEY_UP; } else if (datain & KD_KEYMASK) { if (datain & KD_DIRECTION) *type = WSCONS_EVENT_KEY_UP; else *type = WSCONS_EVENT_KEY_DOWN; *dataout = (datain & KD_KEYMASK); } else { *dataout = 0; } return 1; }