[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

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