[BACK]Return to hilkbd.c CVS log [TXT][DIR] Up to [local] / sys / dev / hil

Annotation of sys/dev/hil/hilkbd.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: hilkbd.c,v 1.13 2006/08/10 23:43:45 miod Exp $        */
                      2: /*
                      3:  * Copyright (c) 2003, Miodrag Vallat.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     16:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     18:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     19:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     20:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     21:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     23:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     24:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     25:  * POSSIBILITY OF SUCH DAMAGE.
                     26:  *
                     27:  */
                     28:
                     29: #include <sys/param.h>
                     30: #include <sys/systm.h>
                     31: #include <sys/device.h>
                     32: #include <sys/ioctl.h>
                     33: #include <sys/kernel.h>
                     34: #include <sys/timeout.h>
                     35:
                     36: #include <machine/autoconf.h>
                     37: #include <machine/bus.h>
                     38: #include <machine/cpu.h>
                     39:
                     40: #include <dev/hil/hilreg.h>
                     41: #include <dev/hil/hilvar.h>
                     42: #include <dev/hil/hildevs.h>
                     43:
                     44: #include <dev/wscons/wsconsio.h>
                     45: #include <dev/wscons/wskbdvar.h>
                     46: #include <dev/wscons/wsksymdef.h>
                     47: #include <dev/wscons/wsksymvar.h>
                     48: #ifdef WSDISPLAY_COMPAT_RAWKBD
                     49: #include <dev/wscons/wskbdraw.h>
                     50: #endif
                     51:
                     52: #include <dev/hil/hilkbdmap.h>
                     53:
                     54: struct hilkbd_softc {
                     55:        struct hildev_softc sc_hildev;
                     56:
                     57:        int             sc_numleds;
                     58:        int             sc_ledstate;
                     59:        int             sc_enabled;
                     60:        int             sc_console;
                     61:        int             sc_lastarrow;
                     62:
                     63:        struct device   *sc_wskbddev;
                     64:
                     65: #ifdef WSDISPLAY_COMPAT_RAWKBD
                     66:        int             sc_rawkbd;
                     67:        int             sc_nrep;
                     68:        char            sc_rep[HILBUFSIZE * 2];
                     69:        struct timeout  sc_rawrepeat_ch;
                     70: #define        REP_DELAY1      400
                     71: #define        REP_DELAYN      100
                     72: #endif
                     73: };
                     74:
                     75: int    hilkbdprobe(struct device *, void *, void *);
                     76: void   hilkbdattach(struct device *, struct device *, void *);
                     77: int    hilkbddetach(struct device *, int);
                     78:
                     79: struct cfdriver hilkbd_cd = {
                     80:        NULL, "hilkbd", DV_DULL
                     81: };
                     82:
                     83: struct cfattach hilkbd_ca = {
                     84:        sizeof(struct hilkbd_softc), hilkbdprobe, hilkbdattach, hilkbddetach,
                     85: };
                     86:
                     87: int    hilkbd_enable(void *, int);
                     88: void   hilkbd_set_leds(void *, int);
                     89: int    hilkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
                     90:
                     91: const struct wskbd_accessops hilkbd_accessops = {
                     92:        hilkbd_enable,
                     93:        hilkbd_set_leds,
                     94:        hilkbd_ioctl,
                     95: };
                     96:
                     97: void   hilkbd_cngetc(void *, u_int *, int *);
                     98: void   hilkbd_cnpollc(void *, int);
                     99: void   hilkbd_cnbell(void *, u_int, u_int, u_int);
                    100:
                    101: const struct wskbd_consops hilkbd_consops = {
                    102:        hilkbd_cngetc,
                    103:        hilkbd_cnpollc,
                    104:        hilkbd_cnbell,
                    105: };
                    106:
                    107: struct wskbd_mapdata hilkbd_keymapdata = {
                    108:        hilkbd_keydesctab,
                    109: #ifdef HILKBD_LAYOUT
                    110:        HILKBD_LAYOUT,
                    111: #else
                    112:        KB_US,
                    113: #endif
                    114: };
                    115:
                    116: struct wskbd_mapdata hilkbd_keymapdata_ps2 = {
                    117:        hilkbd_keydesctab_ps2,
                    118: #ifdef HILKBD_LAYOUT
                    119:        HILKBD_LAYOUT,
                    120: #else
                    121:        KB_US,
                    122: #endif
                    123: };
                    124:
                    125: void   hilkbd_bell(struct hil_softc *, u_int, u_int, u_int);
                    126: void   hilkbd_callback(struct hildev_softc *, u_int, u_int8_t *);
                    127: void   hilkbd_decode(struct hilkbd_softc *, u_int8_t, u_int *, int *, int);
                    128: int    hilkbd_is_console(int);
                    129: void   hilkbd_rawrepeat(void *);
                    130:
                    131: int    seen_hilkbd_console;
                    132:
                    133: int
                    134: hilkbdprobe(struct device *parent, void *match, void *aux)
                    135: {
                    136:        struct hil_attach_args *ha = aux;
                    137:
                    138:        if (ha->ha_type != HIL_DEVICE_KEYBOARD &&
                    139:            ha->ha_type != HIL_DEVICE_BUTTONBOX)
                    140:                return (0);
                    141:
                    142:        return (1);
                    143: }
                    144:
                    145: void
                    146: hilkbdattach(struct device *parent, struct device *self, void *aux)
                    147: {
                    148:        struct hilkbd_softc *sc = (void *)self;
                    149:        struct hil_attach_args *ha = aux;
                    150:        struct wskbddev_attach_args a;
                    151:        u_int8_t layoutcode;
                    152:        int ps2;
                    153:
                    154:        sc->hd_code = ha->ha_code;
                    155:        sc->hd_type = ha->ha_type;
                    156:        sc->hd_infolen = ha->ha_infolen;
                    157:        bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen);
                    158:        sc->hd_fn = hilkbd_callback;
                    159:
                    160:        if (ha->ha_type == HIL_DEVICE_KEYBOARD) {
                    161:                /*
                    162:                 * Determine the keyboard language configuration, but don't
                    163:                 * override a user-specified setting.
                    164:                 */
                    165:                layoutcode = ha->ha_id & (MAXHILKBDLAYOUT - 1);
                    166: #ifndef HILKBD_LAYOUT
                    167:                if (layoutcode < MAXHILKBDLAYOUT &&
                    168:                    hilkbd_layouts[layoutcode] != -1)
                    169:                        hilkbd_keymapdata.layout =
                    170:                        hilkbd_keymapdata_ps2.layout =
                    171:                            hilkbd_layouts[layoutcode];
                    172: #endif
                    173:
                    174:                printf(", layout %x", layoutcode);
                    175:        }
                    176:
                    177:        /*
                    178:         * Interpret the identification bytes, if any
                    179:         */
                    180:        if (ha->ha_infolen > 2 && (ha->ha_info[1] & HIL_IOB) != 0) {
                    181:                /* HILIOB_PROMPT is not always reported... */
                    182:                sc->sc_numleds = (ha->ha_info[2] & HILIOB_PMASK) >> 4;
                    183:                if (sc->sc_numleds != 0)
                    184:                        printf(", %d leds", sc->sc_numleds);
                    185:        }
                    186:
                    187:        printf("\n");
                    188:
                    189:        /*
                    190:         * Red lettered keyboards come in two flavours, the old one
                    191:         * with only one control key, to the left of the escape key,
                    192:         * and the modern one which has a PS/2 like layout, and leds.
                    193:         *
                    194:         * Unfortunately for us, they use the same device ID range.
                    195:         * We'll differentiate them by looking at the leds property.
                    196:         */
                    197:        ps2 = (sc->sc_numleds != 0);
                    198:
                    199: #ifdef WSDISPLAY_COMPAT_RAWKBD
                    200:        timeout_set(&sc->sc_rawrepeat_ch, hilkbd_rawrepeat, sc);
                    201: #endif
                    202:
                    203:        /* Do not consider button boxes as console devices. */
                    204:        if (ha->ha_type == HIL_DEVICE_BUTTONBOX)
                    205:                a.console = 0;
                    206:        else
                    207:                a.console = hilkbd_is_console(ha->ha_console);
                    208:        a.keymap = ps2 ? &hilkbd_keymapdata_ps2 : &hilkbd_keymapdata;
                    209:        a.accessops = &hilkbd_accessops;
                    210:        a.accesscookie = sc;
                    211:
                    212:        if (a.console) {
                    213:                sc->sc_console = sc->sc_enabled = 1;
                    214:                wskbd_cnattach(&hilkbd_consops, sc, a.keymap);
                    215:        } else {
                    216:                sc->sc_console = sc->sc_enabled = 0;
                    217:        }
                    218:
                    219:        sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
                    220:
                    221:        /*
                    222:         * If this is an old keyboard with a numeric pad but no ``num lock''
                    223:         * key, simulate it being pressed so that the keyboard runs in
                    224:         * numeric mode.
                    225:         */
                    226:        if (!ps2 && sc->sc_wskbddev != NULL) {
                    227:                wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, 80);
                    228:                wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, 80);
                    229:        }
                    230: }
                    231:
                    232: int
                    233: hilkbddetach(struct device *self, int flags)
                    234: {
                    235:        struct hilkbd_softc *sc = (void *)self;
                    236:
                    237:        /*
                    238:         * Handle console keyboard for the best. It should have been set
                    239:         * as the first device in the loop anyways.
                    240:         */
                    241:        if (sc->sc_console) {
                    242:                wskbd_cndetach();
                    243:                seen_hilkbd_console = 0;
                    244:        }
                    245:
                    246:        if (sc->sc_wskbddev != NULL)
                    247:                return config_detach(sc->sc_wskbddev, flags);
                    248:
                    249:        return (0);
                    250: }
                    251:
                    252: int
                    253: hilkbd_enable(void *v, int on)
                    254: {
                    255:        struct hilkbd_softc *sc = v;
                    256:
                    257:        if (on) {
                    258:                if (sc->sc_enabled)
                    259:                        return (EBUSY);
                    260:        } else {
                    261:                if (sc->sc_console)
                    262:                        return (EBUSY);
                    263:        }
                    264:
                    265:        sc->sc_enabled = on;
                    266:
                    267:        return (0);
                    268: }
                    269:
                    270: void
                    271: hilkbd_set_leds(void *v, int leds)
                    272: {
                    273:        struct hilkbd_softc *sc = v;
                    274:        int changemask;
                    275:
                    276:        if (sc->sc_numleds == 0)
                    277:                return;
                    278:
                    279:        changemask = leds ^ sc->sc_ledstate;
                    280:        if (changemask == 0)
                    281:                return;
                    282:
                    283:        /* We do not handle more than 3 leds here */
                    284:        if (changemask & WSKBD_LED_SCROLL)
                    285:                send_hildev_cmd((struct hildev_softc *)sc,
                    286:                    (leds & WSKBD_LED_SCROLL) ? HIL_PROMPT1 : HIL_ACK1,
                    287:                    NULL, NULL);
                    288:        if (changemask & WSKBD_LED_NUM)
                    289:                send_hildev_cmd((struct hildev_softc *)sc,
                    290:                    (leds & WSKBD_LED_NUM) ? HIL_PROMPT2 : HIL_ACK2,
                    291:                    NULL, NULL);
                    292:        if (changemask & WSKBD_LED_CAPS)
                    293:                send_hildev_cmd((struct hildev_softc *)sc,
                    294:                    (leds & WSKBD_LED_CAPS) ? HIL_PROMPT3 : HIL_ACK3,
                    295:                    NULL, NULL);
                    296:
                    297:        sc->sc_ledstate = leds;
                    298: }
                    299:
                    300: int
                    301: hilkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
                    302: {
                    303:        struct hilkbd_softc *sc = v;
                    304:
                    305:        switch (cmd) {
                    306:        case WSKBDIO_GTYPE:
                    307:                *(int *)data = WSKBD_TYPE_HIL;
                    308:                return 0;
                    309:        case WSKBDIO_SETLEDS:
                    310:                hilkbd_set_leds(v, *(int *)data);
                    311:                return 0;
                    312:        case WSKBDIO_GETLEDS:
                    313:                *(int *)data = sc->sc_ledstate;
                    314:                return 0;
                    315: #ifdef WSDISPLAY_COMPAT_RAWKBD
                    316:        case WSKBDIO_SETMODE:
                    317:                sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
                    318:                timeout_del(&sc->sc_rawrepeat_ch);
                    319:                return 0;
                    320: #endif
                    321:        case WSKBDIO_COMPLEXBELL:
                    322: #define        d ((struct wskbd_bell_data *)data)
                    323:                hilkbd_bell((struct hil_softc *)sc->hd_parent,
                    324:                    d->pitch, d->period, d->volume);
                    325: #undef d
                    326:                return 0;
                    327:        }
                    328:
                    329:        return -1;
                    330: }
                    331:
                    332: void
                    333: hilkbd_cngetc(void *v, u_int *type, int *data)
                    334: {
                    335:        struct hilkbd_softc *sc = v;
                    336:        u_int8_t c, stat;
                    337:
                    338:        for (;;) {
                    339:                while (hil_poll_data((struct hildev_softc *)sc, &stat, &c) != 0)
                    340:                        ;
                    341:
                    342:                /*
                    343:                 * Disregard keyboard data packet header.
                    344:                 * Note that no key generates it, so we're safe.
                    345:                 */
                    346:                if (c != HIL_KBDBUTTON)
                    347:                        break;
                    348:        }
                    349:
                    350:        hilkbd_decode(sc, c, type, data, HIL_KBDBUTTON);
                    351: }
                    352:
                    353: void
                    354: hilkbd_cnpollc(void *v, int on)
                    355: {
                    356:        struct hilkbd_softc *sc = v;
                    357:
                    358:        hil_set_poll((struct hil_softc *)sc->hd_parent, on);
                    359: }
                    360:
                    361: void
                    362: hilkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
                    363: {
                    364:        struct hilkbd_softc *sc = v;
                    365:
                    366:        hilkbd_bell((struct hil_softc *)sc->hd_parent,
                    367:            pitch, period, volume);
                    368: }
                    369:
                    370: void
                    371: hilkbd_bell(struct hil_softc *sc, u_int pitch, u_int period, u_int volume)
                    372: {
                    373:        u_int8_t buf[2];
                    374:
                    375:        /* XXX there could be at least a pitch -> HIL pitch conversion here */
                    376: #define        BELLDUR         80      /* tone duration in msec (10-2560) */
                    377: #define        BELLFREQ        8       /* tone frequency (0-63) */
                    378:        buf[0] = ar_format(period - 10);
                    379:        buf[1] = BELLFREQ;
                    380:        send_hil_cmd(sc, HIL_SETTONE, buf, 2, NULL);
                    381: }
                    382:
                    383: void
                    384: hilkbd_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf)
                    385: {
                    386:        struct hilkbd_softc *sc = (struct hilkbd_softc *)dev;
                    387:        u_int type;
                    388:        int kbdtype, key;
                    389:        int i, s;
                    390:
                    391:        /*
                    392:         * Ignore packet if we don't need it
                    393:         */
                    394:        if (sc->sc_enabled == 0)
                    395:                return;
                    396:
                    397:        if (buflen == 0)
                    398:                return;
                    399:        switch ((kbdtype = *buf & HIL_KBDDATA)) {
                    400:        case HIL_BUTTONBOX:
                    401:        case HIL_KBDBUTTON:
                    402:                break;
                    403:        default:
                    404:                return;
                    405:        }
                    406:
                    407: #ifdef WSDISPLAY_COMPAT_RAWKBD
                    408:        if (sc->sc_rawkbd) {
                    409:                u_char cbuf[HILBUFSIZE * 2];
                    410:                int c, j, npress;
                    411:
                    412:                npress = j = 0;
                    413:                for (i = 1, buf++; i < buflen; i++) {
                    414:                        hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
                    415:                        c = hilkbd_raw[key];
                    416:                        if (c == RAWKEY_Null)
                    417:                                continue;
                    418:                        /* fake extended scancode if necessary */
                    419:                        if (c & 0x80)
                    420:                                cbuf[j++] = 0xe0;
                    421:                        cbuf[j] = c & 0x7f;
                    422:                        if (type == WSCONS_EVENT_KEY_UP)
                    423:                                cbuf[j] |= 0x80;
                    424:                        else {
                    425:                                /* remember pressed keys for autorepeat */
                    426:                                if (c & 0x80)
                    427:                                        sc->sc_rep[npress++] = 0xe0;
                    428:                                sc->sc_rep[npress++] = c & 0x7f;
                    429:                        }
                    430:                        j++;
                    431:                }
                    432:
                    433:                s = spltty();
                    434:                wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
                    435:                splx(s);
                    436:                timeout_del(&sc->sc_rawrepeat_ch);
                    437:                sc->sc_nrep = npress;
                    438:                if (npress != 0) {
                    439:                        timeout_add(&sc->sc_rawrepeat_ch,
                    440:                            (hz * REP_DELAY1) / 1000);
                    441:                }
                    442:        } else
                    443: #endif
                    444:        {
                    445:                s = spltty();
                    446:                for (i = 1, buf++; i < buflen; i++) {
                    447:                        hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
                    448:                        if (sc->sc_wskbddev != NULL)
                    449:                                wskbd_input(sc->sc_wskbddev, type, key);
                    450:                }
                    451:                splx(s);
                    452:        }
                    453: }
                    454:
                    455: void
                    456: hilkbd_decode(struct hilkbd_softc *sc, u_int8_t data, u_int *type, int *key,
                    457:     int kbdtype)
                    458: {
                    459:        if (kbdtype == HIL_BUTTONBOX) {
                    460:                if (data == 0x02)       /* repeat arrow */
                    461:                        data = sc->sc_lastarrow;
                    462:                else if (data >= 0xf8)
                    463:                        sc->sc_lastarrow = data;
                    464:        }
                    465:
                    466:        *type = (data & 1) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
                    467:        *key = data >> 1;
                    468: }
                    469:
                    470: int
                    471: hilkbd_is_console(int hil_is_console)
                    472: {
                    473:        /* if not first hil keyboard, then not the console */
                    474:        if (seen_hilkbd_console)
                    475:                return (0);
                    476:
                    477:        /* if PDC console does not match hil bus path, then not the console */
                    478:        if (hil_is_console == 0)
                    479:                return (0);
                    480:
                    481:        seen_hilkbd_console = 1;
                    482:        return (1);
                    483: }
                    484:
                    485: #ifdef WSDISPLAY_COMPAT_RAWKBD
                    486: void
                    487: hilkbd_rawrepeat(void *v)
                    488: {
                    489:        struct hilkbd_softc *sc = v;
                    490:        int s;
                    491:
                    492:        s = spltty();
                    493:        wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
                    494:        splx(s);
                    495:        timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
                    496: }
                    497: #endif

CVSweb