[BACK]Return to dnkbd.c CVS log [TXT][DIR] Up to [local] / sys / arch / hp300 / dev

Annotation of sys/arch/hp300/dev/dnkbd.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: dnkbd.c,v 1.15 2007/04/10 22:37:14 miod Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005, Miodrag Vallat
        !             5:  * Copyright (c) 1997 Michael Smith.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            26:  * SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: /*
        !            30:  * Driver for the Apollo Domain keyboard and mouse.
        !            31:  */
        !            32:
        !            33: #include <sys/param.h>
        !            34: #include <sys/systm.h>
        !            35: #include <sys/device.h>
        !            36: #include <sys/ioctl.h>
        !            37: #include <sys/kernel.h>
        !            38: #include <sys/timeout.h>
        !            39:
        !            40: #include <machine/autoconf.h>
        !            41: #include <machine/bus.h>
        !            42: #include <machine/cpu.h>
        !            43:
        !            44: #include <dev/cons.h>
        !            45:
        !            46: #include <dev/wscons/wsconsio.h>
        !            47: #include <dev/wscons/wskbdvar.h>
        !            48: #include <dev/wscons/wsksymdef.h>
        !            49: #include <dev/wscons/wsksymvar.h>
        !            50: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !            51: #include <dev/wscons/wskbdraw.h>
        !            52: #endif
        !            53: #include "wsmouse.h"
        !            54: #if NWSMOUSE > 0
        !            55: #include <dev/wscons/wsmousevar.h>
        !            56: #endif
        !            57:
        !            58: #include <hp300/dev/apcireg.h>
        !            59: #include <hp300/dev/apcivar.h>
        !            60: #include <hp300/dev/dcareg.h>
        !            61: #include <hp300/dev/dnkbdmap.h>
        !            62: #include <hp300/dev/frodoreg.h>
        !            63: #include <hp300/dev/frodovar.h>
        !            64:
        !            65: #include "hilkbd.h"
        !            66:
        !            67: /*
        !            68:  * Keyboard key codes
        !            69:  */
        !            70:
        !            71: #define        DNKEY_CAPSLOCK  0x7e
        !            72: #define        DNKEY_REPEAT    0x7f
        !            73: #define        DNKEY_RELEASE   0x80
        !            74: #define        DNKEY_CHANNEL   0xff
        !            75:
        !            76: /*
        !            77:  * Channels
        !            78:  */
        !            79:
        !            80: #define        DNCHANNEL_RESET 0x00
        !            81: #define        DNCHANNEL_KBD   0x01
        !            82: #define        DNCHANNEL_MOUSE 0x02
        !            83:
        !            84: /*
        !            85:  * Keyboard modes
        !            86:  */
        !            87:
        !            88: #define        DNMODE_COOKED   0x00
        !            89: #define        DNMODE_RAW      0x01
        !            90:
        !            91: /*
        !            92:  * Keyboard commands
        !            93:  */
        !            94:
        !            95: #define        DNCMD_PREFIX    0xff
        !            96: #define        DNCMD_COOKED    DNMODE_COOKED
        !            97: #define        DNCMD_RAW       DNMODE_RAW
        !            98: #define        DNCMD_IDENT_1   0x12
        !            99: #define        DNCMD_IDENT_2   0x21
        !           100:
        !           101: /*
        !           102:  * Bell commands
        !           103:  */
        !           104:
        !           105: #define        DNCMD_BELL      0x21
        !           106: #define        DNCMD_BELL_ON   0x81
        !           107: #define        DNCMD_BELL_OFF  0x82
        !           108:
        !           109: /*
        !           110:  * Mouse status
        !           111:  */
        !           112:
        !           113: #define        DNBUTTON_L      0x10
        !           114: #define        DNBUTTON_R      0x20
        !           115: #define        DNBUTTON_M      0x40
        !           116:
        !           117: struct dnkbd_softc {
        !           118:        struct device   sc_dev;
        !           119:        struct isr      sc_isr;
        !           120:        struct apciregs *sc_regs;
        !           121:
        !           122:        int             sc_flags;
        !           123: #define        SF_ENABLED      0x01            /* keyboard enabled */
        !           124: #define        SF_CONSOLE      0x02            /* keyboard is console */
        !           125: #define        SF_POLLING      0x04            /* polling mode */
        !           126: #define        SF_PLUGGED      0x08            /* keyboard has been seen plugged */
        !           127: #define        SF_ATTACHED     0x10            /* subdevices have been attached */
        !           128: #define        SF_MOUSE        0x20            /* mouse enabled */
        !           129: #define        SF_BELL         0x40            /* bell is active */
        !           130: #define        SF_BELL_TMO     0x80            /* bell stop timeout is scheduled */
        !           131:
        !           132:        u_int           sc_identlen;
        !           133: #define        MAX_IDENTLEN    32
        !           134:        char            sc_ident[MAX_IDENTLEN];
        !           135:        kbd_t           sc_layout;
        !           136:
        !           137:        enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL, STATE_ECHO }
        !           138:                        sc_state, sc_prevstate;
        !           139:        u_int           sc_echolen;
        !           140:
        !           141:        u_int8_t        sc_mousepkt[3]; /* mouse packet being constructed */
        !           142:        u_int           sc_mousepos;    /* index in above */
        !           143:
        !           144:        struct timeout  sc_bellstop_tmo;
        !           145:
        !           146:        struct device   *sc_wskbddev;
        !           147: #if NWSMOUSE > 0
        !           148:        struct device   *sc_wsmousedev;
        !           149: #endif
        !           150:
        !           151: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           152:        int             sc_rawkbd;
        !           153:        int             sc_nrep;
        !           154:        char            sc_rep[2];      /* at most, one key */
        !           155:        struct timeout  sc_rawrepeat_ch;
        !           156: #define        REP_DELAY1      400
        !           157: #define        REP_DELAYN      100
        !           158: #endif
        !           159: };
        !           160:
        !           161: int    dnkbd_match(struct device *, void *, void *);
        !           162: void   dnkbd_attach(struct device *, struct device *, void *);
        !           163:
        !           164: struct cfdriver dnkbd_cd = {
        !           165:        NULL, "dnkbd", DV_DULL
        !           166: };
        !           167:
        !           168: struct cfattach dnkbd_ca = {
        !           169:        sizeof(struct dnkbd_softc), dnkbd_match, dnkbd_attach
        !           170: };
        !           171:
        !           172: int    dnkbd_enable(void *, int);
        !           173: void   dnkbd_set_leds(void *, int);
        !           174: int    dnkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
        !           175:
        !           176: const struct wskbd_accessops dnkbd_accessops = {
        !           177:        dnkbd_enable,
        !           178:        dnkbd_set_leds,
        !           179:        dnkbd_ioctl
        !           180: };
        !           181:
        !           182: #if NWSMOUSE > 0
        !           183: int    dnmouse_enable(void *);
        !           184: int    dnmouse_ioctl(void *, u_long, caddr_t, int, struct proc *);
        !           185: void   dnmouse_disable(void *);
        !           186:
        !           187: const struct wsmouse_accessops dnmouse_accessops = {
        !           188:        dnmouse_enable,
        !           189:        dnmouse_ioctl,
        !           190:        dnmouse_disable
        !           191: };
        !           192: #endif
        !           193:
        !           194: void   dnkbd_bell(void *, u_int, u_int, u_int);
        !           195: void   dnkbd_cngetc(void *, u_int *, int *);
        !           196: void   dnkbd_cnpollc(void *, int);
        !           197:
        !           198: const struct wskbd_consops dnkbd_consops = {
        !           199:        dnkbd_cngetc,
        !           200:        dnkbd_cnpollc,
        !           201:        dnkbd_bell
        !           202: };
        !           203:
        !           204: struct wskbd_mapdata dnkbd_keymapdata = {
        !           205:        dnkbd_keydesctab,
        !           206: #ifdef DNKBD_LAYOUT
        !           207:        DNKBD_LAYOUT
        !           208: #else
        !           209:        KB_US
        !           210: #endif
        !           211: };
        !           212:
        !           213: typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent;
        !           214:
        !           215: void   dnevent_kbd(struct dnkbd_softc *, int);
        !           216: void   dnevent_kbd_internal(struct dnkbd_softc *, int);
        !           217: void   dnevent_mouse(struct dnkbd_softc *, u_int8_t *);
        !           218: void   dnkbd_attach_subdevices(struct dnkbd_softc *);
        !           219: void   dnkbd_bellstop(void *);
        !           220: void   dnkbd_decode(int, u_int *, int *);
        !           221: int    dnkbd_init(struct apciregs *);
        !           222: dnevent        dnkbd_input(struct dnkbd_softc *, int);
        !           223: int    dnkbd_intr(void *);
        !           224: int    dnkbd_pollin(struct apciregs *, u_int);
        !           225: int    dnkbd_pollout(struct apciregs *, int);
        !           226: int    dnkbd_probe(struct dnkbd_softc *);
        !           227: void   dnkbd_rawrepeat(void *);
        !           228: int    dnkbd_send(struct apciregs *, const u_int8_t *, size_t);
        !           229: int    dnsubmatch_kbd(struct device *, void *, void *);
        !           230: int    dnsubmatch_mouse(struct device *, void *, void *);
        !           231:
        !           232: int
        !           233: dnkbd_match(struct device *parent, void *match, void *aux)
        !           234: {
        !           235:        struct frodo_attach_args *fa = aux;
        !           236:
        !           237:        if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0)
        !           238:                return (0);
        !           239:
        !           240:        /* only attach to the first frodo port */
        !           241:        return (fa->fa_offset == FRODO_APCI_OFFSET(0));
        !           242: }
        !           243:
        !           244: void
        !           245: dnkbd_attach(struct device *parent, struct device *self, void *aux)
        !           246: {
        !           247:        struct dnkbd_softc *sc = (struct dnkbd_softc *)self;
        !           248:        struct frodo_attach_args *fa = aux;
        !           249:
        !           250:        printf(": ");
        !           251:
        !           252:        sc->sc_regs = (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
        !           253:
        !           254:        timeout_set(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc);
        !           255: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           256:        timeout_set(&sc->sc_rawrepeat_ch, dnkbd_rawrepeat, sc);
        !           257: #endif
        !           258:
        !           259:        /* reset the port */
        !           260:        apciinit(sc->sc_regs, 1200, CFCR_8BITS | CFCR_PEVEN | CFCR_PENAB);
        !           261:
        !           262:        sc->sc_isr.isr_func = dnkbd_intr;
        !           263:        sc->sc_isr.isr_arg = sc;
        !           264:        sc->sc_isr.isr_priority = IPL_TTY;
        !           265:        frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
        !           266:
        !           267:        /* probe for keyboard */
        !           268:        if (dnkbd_probe(sc) != 0) {
        !           269:                printf("no keyboard\n");
        !           270:                return;
        !           271:        }
        !           272:
        !           273:        dnkbd_attach_subdevices(sc);
        !           274: }
        !           275:
        !           276: void
        !           277: dnkbd_attach_subdevices(struct dnkbd_softc *sc)
        !           278: {
        !           279:        struct wskbddev_attach_args ka;
        !           280: #if NWSMOUSE > 0
        !           281:        struct wsmousedev_attach_args ma;
        !           282: #endif
        !           283: #if NHILKBD > 0
        !           284:        extern int hil_is_console;
        !           285: #endif
        !           286:        extern struct consdev wsdisplay_cons;
        !           287:
        !           288:        /*
        !           289:         * If both hilkbd and dnkbd are configured, prefer the Domain
        !           290:         * keyboard as console (if we are here, we know the keyboard is
        !           291:         * plugged), unless the console keyboard has been claimed already
        !           292:         * (i.e. late hotplug with hil keyboard plugged first).
        !           293:         */
        !           294:        if (cn_tab == &wsdisplay_cons) {
        !           295: #if NHILKBD > 0
        !           296:                if (hil_is_console == -1) {
        !           297:                        ka.console = 1;
        !           298:                        hil_is_console = 0;
        !           299:                } else
        !           300:                        ka.console = 0;
        !           301: #else
        !           302:                ka.console = 1;
        !           303: #endif
        !           304:        } else
        !           305:                ka.console = 0;
        !           306:
        !           307:        ka.keymap = &dnkbd_keymapdata;
        !           308:        ka.accessops = &dnkbd_accessops;
        !           309:        ka.accesscookie = sc;
        !           310: #ifndef DKKBD_LAYOUT
        !           311:        dnkbd_keymapdata.layout = sc->sc_layout;
        !           312: #endif
        !           313:
        !           314:        if (ka.console) {
        !           315:                sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
        !           316:                wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
        !           317:        } else {
        !           318:                sc->sc_flags = SF_PLUGGED;
        !           319:        }
        !           320:
        !           321:        sc->sc_wskbddev = config_found_sm(&sc->sc_dev, &ka, wskbddevprint,
        !           322:            dnsubmatch_kbd);
        !           323:
        !           324: #if NWSMOUSE > 0
        !           325:        ma.accessops = &dnmouse_accessops;
        !           326:        ma.accesscookie = sc;
        !           327:
        !           328:        sc->sc_wsmousedev = config_found_sm(&sc->sc_dev, &ma, wsmousedevprint,
        !           329:            dnsubmatch_mouse);
        !           330: #endif
        !           331:
        !           332:        SET(sc->sc_flags, SF_ATTACHED);
        !           333: }
        !           334:
        !           335: int
        !           336: dnsubmatch_kbd(struct device *parent, void *match, void *aux)
        !           337: {
        !           338:        struct cfdata *cf = match;
        !           339:        extern struct cfdriver wskbd_cd;
        !           340:
        !           341:        if (strcmp(cf->cf_driver->cd_name, wskbd_cd.cd_name) != 0)
        !           342:                return (0);
        !           343:
        !           344:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
        !           345: }
        !           346:
        !           347: #if NWSMOUSE > 0
        !           348: int
        !           349: dnsubmatch_mouse(struct device *parent, void *match, void *aux)
        !           350: {
        !           351:        struct cfdata *cf = match;
        !           352:        extern struct cfdriver wsmouse_cd;
        !           353:
        !           354:        if (strcmp(cf->cf_driver->cd_name, wsmouse_cd.cd_name) != 0)
        !           355:                return (0);
        !           356:
        !           357:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
        !           358: }
        !           359: #endif
        !           360:
        !           361: int
        !           362: dnkbd_probe(struct dnkbd_softc *sc)
        !           363: {
        !           364:        int dat, rc, flags;
        !           365:        u_int8_t cmdbuf[2];
        !           366:        char rspbuf[MAX_IDENTLEN], *word, *end;
        !           367:        u_int i;
        !           368:        int s;
        !           369:
        !           370:        s = spltty();
        !           371:        flags = sc->sc_flags;
        !           372:        SET(sc->sc_flags, SF_POLLING);
        !           373:        sc->sc_state = STATE_CHANNEL;
        !           374:        splx(s);
        !           375:
        !           376:        /*
        !           377:         * Switch keyboard to raw mode.
        !           378:         */
        !           379:        cmdbuf[0] = DNCMD_RAW;
        !           380:        rc = dnkbd_send(sc->sc_regs, cmdbuf, 1);
        !           381:        if (rc != 0)
        !           382:                goto out;
        !           383:
        !           384:        /*
        !           385:         * Send the identify command.
        !           386:         */
        !           387:        cmdbuf[0] = DNCMD_IDENT_1;
        !           388:        cmdbuf[1] = DNCMD_IDENT_2;
        !           389:        rc = dnkbd_send(sc->sc_regs, cmdbuf, 2);
        !           390:        if (rc != 0)
        !           391:                goto out;
        !           392:
        !           393:        for (i = 0; ; i++) {
        !           394:                dat = dnkbd_pollin(sc->sc_regs, 10000);
        !           395:                if (dat == -1)
        !           396:                        break;
        !           397:
        !           398:                if (i < sizeof(rspbuf))
        !           399:                        rspbuf[i] = dat;
        !           400:        }
        !           401:
        !           402:        if (i > sizeof(rspbuf) || i == 0) {
        !           403:                printf("%s: unexpected identify string length %d\n",
        !           404:                    sc->sc_dev.dv_xname, i);
        !           405:                rc = ENXIO;
        !           406:                goto out;
        !           407:        }
        !           408:
        !           409:        /*
        !           410:         * Make sure the identification string is NULL terminated
        !           411:         * (overwriting the keyboard mode byte if necessary).
        !           412:         */
        !           413:        i--;
        !           414:        if (rspbuf[i] != 0)
        !           415:                rspbuf[i] = 0;
        !           416:
        !           417:        /*
        !           418:         * Now display the identification strings, if they changed.
        !           419:         */
        !           420:        if (i != sc->sc_identlen || bcmp(rspbuf, sc->sc_ident, i) != 0) {
        !           421:                sc->sc_layout = KB_US;
        !           422:                sc->sc_identlen = i;
        !           423:                bcopy(rspbuf, sc->sc_ident, i);
        !           424:
        !           425:                if (cold == 0)
        !           426:                        printf("%s: ", sc->sc_dev.dv_xname);
        !           427:                printf("model ");
        !           428:                word = rspbuf;
        !           429:                for (i = 0; i < 3; i++) {
        !           430:                        end = strchr(word, '\r');
        !           431:                        if (end == NULL)
        !           432:                                break;
        !           433:                        *end++ = '\0';
        !           434:                        printf("<%s> ", word);
        !           435:                        /*
        !           436:                         * Parse the layout code if applicable
        !           437:                         */
        !           438:                        if (i == 1 && *word++ == '3') {
        !           439:                                if (*word == '-')
        !           440:                                        word++;
        !           441:                                switch (*word) {
        !           442: #if 0
        !           443:                                default:
        !           444:                                case ' ':
        !           445:                                        sc->sc_layout = KB_US;
        !           446:                                        break;
        !           447: #endif
        !           448:                                case 'a':
        !           449:                                        sc->sc_layout = KB_DE;
        !           450:                                        break;
        !           451:                                case 'b':
        !           452:                                        sc->sc_layout = KB_FR;
        !           453:                                        break;
        !           454:                                case 'c':
        !           455:                                        sc->sc_layout = KB_DK;
        !           456:                                        break;
        !           457:                                case 'd':
        !           458:                                        sc->sc_layout = KB_SV;
        !           459:                                        break;
        !           460:                                case 'e':
        !           461:                                        sc->sc_layout = KB_UK;
        !           462:                                        break;
        !           463:                                case 'f':
        !           464:                                        sc->sc_layout = KB_JP;
        !           465:                                        break;
        !           466:                                case 'g':
        !           467:                                        sc->sc_layout = KB_SG;
        !           468:                                        break;
        !           469:                                }
        !           470:                        }
        !           471:                        word = end;
        !           472:                }
        !           473:                printf("\n");
        !           474:        }
        !           475:
        !           476:        /*
        !           477:         * Ready to work, the default channel is the keyboard.
        !           478:         */
        !           479:        sc->sc_state = STATE_KEYBOARD;
        !           480:
        !           481: out:
        !           482:        s = spltty();
        !           483:        sc->sc_flags = flags;
        !           484:        splx(s);
        !           485:
        !           486:        return (rc);
        !           487: }
        !           488:
        !           489: /*
        !           490:  * State machine.
        !           491:  *
        !           492:  * In raw mode, the keyboard may feed us the following sequences:
        !           493:  * - on the keyboard channel:
        !           494:  *   + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
        !           495:  *   + the key repeat sequence 0x7f.
        !           496:  * - on the mouse channel:
        !           497:  *   + a 3 byte mouse sequence (buttons state, dx move, dy move).
        !           498:  * - at any time:
        !           499:  *   + a 2 byte channel sequence (0xff followed by the channel number) telling
        !           500:  *     us which device the following input will come from.
        !           501:  *   + if we get 0xff but an invalid channel number, this is a command echo.
        !           502:  *     Currently we only handle this for bell commands, which size are known.
        !           503:  *     Other commands are issued through dnkbd_send() which ``eats'' the echo.
        !           504:  *
        !           505:  * Older keyboards reset the channel to the keyboard (by sending ff 01) after
        !           506:  * every mouse packet.
        !           507:  */
        !           508:
        !           509: dnevent
        !           510: dnkbd_input(struct dnkbd_softc *sc, int dat)
        !           511: {
        !           512:        dnevent event = EVENT_NONE;
        !           513:
        !           514:        switch (sc->sc_state) {
        !           515:        case STATE_KEYBOARD:
        !           516:                switch (dat) {
        !           517:                case DNKEY_REPEAT:
        !           518:                        /*
        !           519:                         * We ignore event repeats, as wskbd does its own
        !           520:                         * soft repeat processing.
        !           521:                         */
        !           522:                        break;
        !           523:                case DNKEY_CHANNEL:
        !           524:                        sc->sc_prevstate = sc->sc_state;
        !           525:                        sc->sc_state = STATE_CHANNEL;
        !           526:                        break;
        !           527:                default:
        !           528:                        event = EVENT_KEYBOARD;
        !           529:                        break;
        !           530:                }
        !           531:                break;
        !           532:
        !           533:        case STATE_MOUSE:
        !           534:                if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
        !           535:                        sc->sc_prevstate = sc->sc_state;
        !           536:                        sc->sc_state = STATE_CHANNEL;
        !           537:                } else {
        !           538:                        sc->sc_mousepkt[sc->sc_mousepos++] = dat;
        !           539:                        if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
        !           540:                                sc->sc_mousepos = 0;
        !           541:                                event = EVENT_MOUSE;
        !           542:                        }
        !           543:                }
        !           544:                break;
        !           545:
        !           546:        case STATE_CHANNEL:
        !           547:                switch (dat) {
        !           548:                case DNKEY_CHANNEL:
        !           549:                        /*
        !           550:                         * During hotplug, we might get spurious 0xff bytes.
        !           551:                         * Ignore them.
        !           552:                         */
        !           553:                        break;
        !           554:                case DNCHANNEL_RESET:
        !           555:                        /*
        !           556:                         * Identify the keyboard again. This will switch it to
        !           557:                         * raw mode again. If this fails, we'll consider the
        !           558:                         * keyboard as unplugged (to ignore further events until
        !           559:                         * a successfull reset).
        !           560:                         */
        !           561:                        if (dnkbd_probe(sc) == 0) {
        !           562:                                /*
        !           563:                                 * We need to attach wskbd and wsmouse children
        !           564:                                 * if this is a live first plug.
        !           565:                                 */
        !           566:                                if (!ISSET(sc->sc_flags, SF_ATTACHED))
        !           567:                                        dnkbd_attach_subdevices(sc);
        !           568:                                SET(sc->sc_flags, SF_PLUGGED);
        !           569:                        } else {
        !           570:                                CLR(sc->sc_flags, SF_PLUGGED);
        !           571:                        }
        !           572:
        !           573:                        sc->sc_state = STATE_KEYBOARD;
        !           574:                        break;
        !           575:                case DNCHANNEL_KBD:
        !           576:                        sc->sc_state = STATE_KEYBOARD;
        !           577:                        break;
        !           578:                case DNCHANNEL_MOUSE:
        !           579:                        sc->sc_state = STATE_MOUSE;
        !           580:                        sc->sc_mousepos = 0;    /* just in case */
        !           581:                        break;
        !           582:                case DNCMD_BELL:
        !           583:                        /*
        !           584:                         * We are getting a bell command echoed to us.
        !           585:                         * Ignore it.
        !           586:                         */
        !           587:                        sc->sc_state = STATE_ECHO;
        !           588:                        sc->sc_echolen = 1;     /* one byte to follow */
        !           589:                        break;
        !           590:                default:
        !           591:                        printf("%s: unexpected channel byte %02x\n",
        !           592:                            sc->sc_dev.dv_xname, dat);
        !           593:                        break;
        !           594:                }
        !           595:                break;
        !           596:
        !           597:        case STATE_ECHO:
        !           598:                if (--sc->sc_echolen == 0) {
        !           599:                        /* get back to the state we were in before the echo */
        !           600:                        sc->sc_state = sc->sc_prevstate;
        !           601:                }
        !           602:                break;
        !           603:        }
        !           604:
        !           605:        return (event);
        !           606: }
        !           607:
        !           608: /*
        !           609:  * Event breakers.
        !           610:  */
        !           611:
        !           612: void
        !           613: dnkbd_decode(int keycode, u_int *type, int *key)
        !           614: {
        !           615:        *type = (keycode & DNKEY_RELEASE) ?
        !           616:            WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
        !           617:        *key = (keycode & ~DNKEY_RELEASE);
        !           618: }
        !           619:
        !           620: void
        !           621: dnevent_kbd(struct dnkbd_softc *sc, int dat)
        !           622: {
        !           623:        if (!ISSET(sc->sc_flags, SF_PLUGGED))
        !           624:                return;
        !           625:
        !           626:        if (sc->sc_wskbddev == NULL)
        !           627:                return;
        !           628:
        !           629:        if (!ISSET(sc->sc_flags, SF_ENABLED))
        !           630:                return;
        !           631:
        !           632:        /*
        !           633:         * Even in raw mode, the caps lock key is treated specially:
        !           634:         * first key press causes event 0x7e, release causes no event;
        !           635:         * then a new key press causes nothing, and release causes
        !           636:         * event 0xfe. Moreover, while kept down, it does not produce
        !           637:         * repeat events.
        !           638:         *
        !           639:         * So the best we can do is fake the missed events, but this
        !           640:         * will not allow the capslock key to be remapped as a control
        !           641:         * key since it will not be possible to chord it with anything.
        !           642:         */
        !           643:        dnevent_kbd_internal(sc, dat);
        !           644:        if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK)
        !           645:                dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE);
        !           646: }
        !           647:
        !           648: void
        !           649: dnevent_kbd_internal(struct dnkbd_softc *sc, int dat)
        !           650: {
        !           651:        u_int type;
        !           652:        int key;
        !           653:        int s;
        !           654:
        !           655:        dnkbd_decode(dat, &type, &key);
        !           656:
        !           657: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           658:        if (sc->sc_rawkbd) {
        !           659:                u_char cbuf[2];
        !           660:                int c, j = 0;
        !           661:
        !           662:                c = dnkbd_raw[key];
        !           663:                if (c != RAWKEY_Null) {
        !           664:                        /* fake extended scancode if necessary */
        !           665:                        if (c & 0x80)
        !           666:                                cbuf[j++] = 0xe0;
        !           667:                        cbuf[j] = c & 0x7f;
        !           668:                        if (type == WSCONS_EVENT_KEY_UP)
        !           669:                                cbuf[j] |= 0x80;
        !           670:                        else {
        !           671:                                /* remember pressed key for autorepeat */
        !           672:                                bcopy(cbuf, sc->sc_rep, sizeof(sc->sc_rep));
        !           673:                        }
        !           674:                        j++;
        !           675:                }
        !           676:
        !           677:                if (j != 0) {
        !           678:                        s = spltty();
        !           679:                        wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
        !           680:                        splx(s);
        !           681:                        timeout_del(&sc->sc_rawrepeat_ch);
        !           682:                        sc->sc_nrep = j;
        !           683:                        timeout_add(&sc->sc_rawrepeat_ch,
        !           684:                            (hz * REP_DELAY1) / 1000);
        !           685:                }
        !           686:        } else
        !           687: #endif
        !           688:        {
        !           689:                s = spltty();
        !           690:                wskbd_input(sc->sc_wskbddev, type, key);
        !           691:                splx(s);
        !           692:        }
        !           693: }
        !           694:
        !           695: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           696: void
        !           697: dnkbd_rawrepeat(void *v)
        !           698: {
        !           699:        struct dnkbd_softc *sc = v;
        !           700:        int s;
        !           701:
        !           702:        s = spltty();
        !           703:        wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
        !           704:        splx(s);
        !           705:
        !           706:        timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
        !           707: }
        !           708: #endif
        !           709:
        !           710: #if NWSMOUSE > 0
        !           711: void
        !           712: dnevent_mouse(struct dnkbd_softc *sc, u_int8_t *dat)
        !           713: {
        !           714:        if (!ISSET(sc->sc_flags, SF_PLUGGED))
        !           715:                return;
        !           716:
        !           717:        if (sc->sc_wsmousedev == NULL)
        !           718:                return;
        !           719:
        !           720:        if (!ISSET(sc->sc_flags, SF_MOUSE))
        !           721:                return;
        !           722:
        !           723:        /*
        !           724:         * First byte is button status. It has the 0x80 bit always set, and
        !           725:         * the next 3 bits are *cleared* when the mouse buttons are pressed.
        !           726:         */
        !           727: #ifdef DEBUG
        !           728:        if (!ISSET(*dat, 0x80)) {
        !           729:                printf("%s: incorrect mouse packet %02x %02x %02x\n",
        !           730:                    sc->sc_dev.dv_xname, dat[0], dat[1], dat[2]);
        !           731:                return;
        !           732:        }
        !           733: #endif
        !           734:
        !           735:        wsmouse_input(sc->sc_wsmousedev,
        !           736:            (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
        !           737:            (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA);
        !           738: }
        !           739: #endif
        !           740:
        !           741: /*
        !           742:  * Low-level communication routines.
        !           743:  */
        !           744:
        !           745: int
        !           746: dnkbd_pollin(struct apciregs *apci, u_int tries)
        !           747: {
        !           748:        u_int cnt;
        !           749:
        !           750:        for (cnt = tries; cnt != 0; cnt--) {
        !           751:                if (apci->ap_lsr & LSR_RXRDY)
        !           752:                        break;
        !           753:                DELAY(10);
        !           754:        }
        !           755:
        !           756:        if (cnt == 0)
        !           757:                return (-1);
        !           758:        else
        !           759:                return ((int)apci->ap_data);
        !           760: }
        !           761:
        !           762: int
        !           763: dnkbd_pollout(struct apciregs *apci, int dat)
        !           764: {
        !           765:        u_int cnt;
        !           766:
        !           767:        for (cnt = 10000; cnt != 0; cnt--) {
        !           768:                if (apci->ap_lsr & LSR_TXRDY)
        !           769:                        break;
        !           770:                DELAY(10);
        !           771:        }
        !           772:        if (cnt == 0)
        !           773:                return (EBUSY);
        !           774:        else {
        !           775:                apci->ap_data = dat;
        !           776:                return (0);
        !           777:        }
        !           778: }
        !           779:
        !           780: int
        !           781: dnkbd_send(struct apciregs *apci, const u_int8_t *cmdbuf, size_t cmdlen)
        !           782: {
        !           783:        int cnt, rc, dat;
        !           784:        u_int cmdpos;
        !           785:
        !           786:        /* drain rxfifo */
        !           787:        for (cnt = 10; cnt != 0; cnt--) {
        !           788:                if (dnkbd_pollin(apci, 10) == -1)
        !           789:                        break;
        !           790:        }
        !           791:        if (cnt == 0)
        !           792:                return (EBUSY);
        !           793:
        !           794:        /* send command escape */
        !           795:        if ((rc = dnkbd_pollout(apci, DNCMD_PREFIX)) != 0)
        !           796:                return (rc);
        !           797:
        !           798:        /* send command buffer */
        !           799:        for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
        !           800:                if ((rc = dnkbd_pollout(apci, cmdbuf[cmdpos])) != 0)
        !           801:                        return (rc);
        !           802:        }
        !           803:
        !           804:        /* wait for command echo */
        !           805:        do {
        !           806:                dat = dnkbd_pollin(apci, 10000);
        !           807:                if (dat == -1)
        !           808:                        return (EIO);
        !           809:        } while (dat != DNCMD_PREFIX);
        !           810:
        !           811:        for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
        !           812:                dat = dnkbd_pollin(apci, 10000);
        !           813:                if (dat != cmdbuf[cmdpos])
        !           814:                        return (EIO);
        !           815:        }
        !           816:
        !           817:        return (0);
        !           818: }
        !           819:
        !           820: int
        !           821: dnkbd_intr(void *v)
        !           822: {
        !           823:        struct dnkbd_softc *sc = v;
        !           824:        struct apciregs *apci = sc->sc_regs;
        !           825:        u_int8_t iir, lsr, c;
        !           826:        int claimed = 0;
        !           827:
        !           828:        for (;;) {
        !           829:                iir = apci->ap_iir;
        !           830:
        !           831:                switch (iir & IIR_IMASK) {
        !           832:                case IIR_RLS:
        !           833:                        /*
        !           834:                         * Line status change. This should never happen,
        !           835:                         * so silently ack the interrupt.
        !           836:                         */
        !           837:                        c = apci->ap_lsr;
        !           838:                        break;
        !           839:
        !           840:                case IIR_RXRDY:
        !           841:                case IIR_RXTOUT:
        !           842:                        /*
        !           843:                         * Data available. We process it byte by byte,
        !           844:                         * unless we are doing polling work...
        !           845:                         */
        !           846:                        if (ISSET(sc->sc_flags, SF_POLLING)) {
        !           847:                                return (1);
        !           848:                        }
        !           849:
        !           850:                        for (;;) {
        !           851:                                c = apci->ap_data;
        !           852:                                switch (dnkbd_input(sc, c)) {
        !           853:                                case EVENT_KEYBOARD:
        !           854:                                        dnevent_kbd(sc, c);
        !           855:                                        break;
        !           856: #if NWSMOUSE > 0
        !           857:                                case EVENT_MOUSE:
        !           858:                                        dnevent_mouse(sc, sc->sc_mousepkt);
        !           859:                                        break;
        !           860: #endif
        !           861:                                default:        /* appease gcc */
        !           862:                                        break;
        !           863:                                }
        !           864:                                lsr = apci->ap_lsr & LSR_RCV_MASK;
        !           865:                                if (lsr == 0)
        !           866:                                        break;
        !           867:                                else if (lsr != LSR_RXRDY) {
        !           868:                                        /* ignore error */
        !           869:                                        break;
        !           870:                                }
        !           871:                        }
        !           872:                        break;
        !           873:
        !           874:                case IIR_TXRDY:
        !           875:                        /*
        !           876:                         * Transmit available. Since we do all our commands
        !           877:                         * in polling mode, we do not need to do anything here.
        !           878:                         */
        !           879:                        break;
        !           880:
        !           881:                default:
        !           882:                        if (iir & IIR_NOPEND)
        !           883:                                return (claimed);
        !           884:                        /* FALLTHROUGH */
        !           885:
        !           886:                case IIR_MLSC:
        !           887:                        /*
        !           888:                         * Modem status change. This should never happen,
        !           889:                         * so silently ack the interrupt.
        !           890:                         */
        !           891:                        c = apci->ap_msr;
        !           892:                        break;
        !           893:                }
        !           894:
        !           895:                claimed = 1;
        !           896:        }
        !           897: }
        !           898:
        !           899: /*
        !           900:  * Wskbd callbacks
        !           901:  */
        !           902:
        !           903: int
        !           904: dnkbd_enable(void *v, int on)
        !           905: {
        !           906:        struct dnkbd_softc *sc = v;
        !           907:
        !           908:        if (on) {
        !           909:                if (ISSET(sc->sc_flags, SF_ENABLED))
        !           910:                        return (EBUSY);
        !           911:                SET(sc->sc_flags, SF_ENABLED);
        !           912:        } else {
        !           913:                if (ISSET(sc->sc_flags, SF_CONSOLE))
        !           914:                        return (EBUSY);
        !           915:                CLR(sc->sc_flags, SF_ENABLED);
        !           916:        }
        !           917:
        !           918:        return (0);
        !           919: }
        !           920:
        !           921: void
        !           922: dnkbd_set_leds(void *v, int leds)
        !           923: {
        !           924:        /*
        !           925:         * Not supported. There is only one LED on this keyboard, and
        !           926:         * is hardware tied to the caps lock key.
        !           927:         */
        !           928: }
        !           929:
        !           930: int
        !           931: dnkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
        !           932: {
        !           933: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           934:        struct dnkbd_softc *sc = v;
        !           935: #endif
        !           936:
        !           937:        switch (cmd) {
        !           938:        case WSKBDIO_GTYPE:
        !           939:                *(int *)data = WSKBD_TYPE_DOMAIN;
        !           940:                return (0);
        !           941:        case WSKBDIO_SETLEDS:
        !           942:                return (ENXIO);
        !           943:        case WSKBDIO_GETLEDS:
        !           944:                *(int *)data = 0;
        !           945:                return (0);
        !           946:        case WSKBDIO_COMPLEXBELL:
        !           947: #define        d       ((struct wskbd_bell_data *)data)
        !           948:                dnkbd_bell(v, d->period, d->pitch, d->volume);
        !           949: #undef d
        !           950:                return (0);
        !           951: #ifdef WSDISPLAY_COMPAT_RAWKBD
        !           952:        case WSKBDIO_SETMODE:
        !           953:                sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
        !           954:                timeout_del(&sc->sc_rawrepeat_ch);
        !           955:                return (0);
        !           956: #endif
        !           957:        }
        !           958:
        !           959:        return (-1);
        !           960: }
        !           961:
        !           962: #if NWSMOUSE > 0
        !           963: /*
        !           964:  * Wsmouse callbacks
        !           965:  */
        !           966:
        !           967: int
        !           968: dnmouse_enable(void *v)
        !           969: {
        !           970:        struct dnkbd_softc *sc = v;
        !           971:
        !           972:        if (ISSET(sc->sc_flags, SF_MOUSE))
        !           973:                return (EBUSY);
        !           974:        SET(sc->sc_flags, SF_MOUSE);
        !           975:
        !           976:        return (0);
        !           977: }
        !           978:
        !           979: int
        !           980: dnmouse_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
        !           981: {
        !           982: #if 0
        !           983:        struct dnkbd_softc *sc = v;
        !           984: #endif
        !           985:
        !           986:        switch (cmd) {
        !           987:        case WSMOUSEIO_GTYPE:
        !           988:                *(int *)data = WSMOUSE_TYPE_DOMAIN;
        !           989:                return (0);
        !           990:        }
        !           991:
        !           992:        return (-1);
        !           993: }
        !           994:
        !           995: void
        !           996: dnmouse_disable(void *v)
        !           997: {
        !           998:        struct dnkbd_softc *sc = v;
        !           999:
        !          1000:        CLR(sc->sc_flags, SF_MOUSE);
        !          1001: }
        !          1002: #endif
        !          1003:
        !          1004: /*
        !          1005:  * Console support
        !          1006:  */
        !          1007:
        !          1008: void
        !          1009: dnkbd_cngetc(void *v, u_int *type, int *data)
        !          1010: {
        !          1011:        static int lastdat = 0;
        !          1012:        struct dnkbd_softc *sc = v;
        !          1013:        int s;
        !          1014:        int dat;
        !          1015:
        !          1016:        /* Take care of caps lock */
        !          1017:        if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) {
        !          1018:                dat = lastdat ^ DNKEY_RELEASE;
        !          1019:                lastdat = 0;
        !          1020:        } else {
        !          1021:                for (;;) {
        !          1022:                        s = splhigh();
        !          1023:                        dat = dnkbd_pollin(sc->sc_regs, 10000);
        !          1024:                        if (dat != -1) {
        !          1025:                                if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
        !          1026:                                        splx(s);
        !          1027:                                        break;
        !          1028:                                }
        !          1029:                        }
        !          1030:                        splx(s);
        !          1031:                }
        !          1032:                lastdat = dat;
        !          1033:        }
        !          1034:
        !          1035:        dnkbd_decode(dat, type, data);
        !          1036: }
        !          1037:
        !          1038: void
        !          1039: dnkbd_cnpollc(void *v, int on)
        !          1040: {
        !          1041:        struct dnkbd_softc *sc = v;
        !          1042:
        !          1043:        if (on)
        !          1044:                SET(sc->sc_flags, SF_POLLING);
        !          1045:        else
        !          1046:                CLR(sc->sc_flags, SF_POLLING);
        !          1047: }
        !          1048:
        !          1049: /*
        !          1050:  * Bell routines.
        !          1051:  */
        !          1052: void
        !          1053: dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume)
        !          1054: {
        !          1055:        struct dnkbd_softc *sc = v;
        !          1056:        int ticks, s;
        !          1057:
        !          1058:        s = spltty();
        !          1059:
        !          1060:        if (pitch == 0 || period == 0 || volume == 0) {
        !          1061:                if (ISSET(sc->sc_flags, SF_BELL_TMO)) {
        !          1062:                        timeout_del(&sc->sc_bellstop_tmo);
        !          1063:                        dnkbd_bellstop(v);
        !          1064:                }
        !          1065:        } else {
        !          1066:                ticks = (period * hz) / 1000;
        !          1067:                if (ticks <= 0)
        !          1068:                        ticks = 1;
        !          1069:
        !          1070:                if (!ISSET(sc->sc_flags, SF_BELL)) {
        !          1071:                        dnkbd_pollout(sc->sc_regs, DNCMD_PREFIX);
        !          1072:                        dnkbd_pollout(sc->sc_regs, DNCMD_BELL);
        !          1073:                        dnkbd_pollout(sc->sc_regs, DNCMD_BELL_ON);
        !          1074:                        SET(sc->sc_flags, SF_BELL);
        !          1075:                }
        !          1076:
        !          1077:                if (ISSET(sc->sc_flags, SF_BELL_TMO))
        !          1078:                        timeout_del(&sc->sc_bellstop_tmo);
        !          1079:                timeout_add(&sc->sc_bellstop_tmo, ticks);
        !          1080:                SET(sc->sc_flags, SF_BELL_TMO);
        !          1081:        }
        !          1082:
        !          1083:        splx(s);
        !          1084: }
        !          1085:
        !          1086: void
        !          1087: dnkbd_bellstop(void *v)
        !          1088: {
        !          1089:        struct dnkbd_softc *sc = v;
        !          1090:        int s;
        !          1091:
        !          1092:        s = spltty();
        !          1093:
        !          1094:        dnkbd_pollout(sc->sc_regs, DNCMD_PREFIX);
        !          1095:        dnkbd_pollout(sc->sc_regs, DNCMD_BELL);
        !          1096:        dnkbd_pollout(sc->sc_regs, DNCMD_BELL_OFF);
        !          1097:        CLR(sc->sc_flags, SF_BELL);
        !          1098:        CLR(sc->sc_flags, SF_BELL_TMO);
        !          1099:
        !          1100:        splx(s);
        !          1101: }

CVSweb