[BACK]Return to pckbc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ic

Annotation of src/sys/dev/ic/pckbc.c, Revision 1.59.18.2

1.59.18.2! martin      1: /* $NetBSD$ */
1.1       thorpej     2:
                      3: /*
1.31      bjh21       4:  * Copyright (c) 2004 Ben Harris.
1.1       thorpej     5:  * Copyright (c) 1998
                      6:  *     Matthias Drochner.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     22:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     23:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     24:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     25:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     26:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     27:  */
1.16      lukem      28:
                     29: #include <sys/cdefs.h>
1.59.18.2! martin     30: __KERNEL_RCSID(0, "$NetBSD$");
1.1       thorpej    31:
                     32: #include <sys/param.h>
                     33: #include <sys/systm.h>
1.2       thorpej    34: #include <sys/callout.h>
1.1       thorpej    35: #include <sys/kernel.h>
                     36: #include <sys/proc.h>
                     37: #include <sys/device.h>
                     38: #include <sys/malloc.h>
                     39: #include <sys/errno.h>
                     40: #include <sys/queue.h>
                     41:
1.38      ad         42: #include <sys/bus.h>
1.1       thorpej    43:
                     44: #include <dev/ic/i8042reg.h>
                     45: #include <dev/ic/pckbcvar.h>
                     46:
1.31      bjh21      47: #include <dev/pckbport/pckbportvar.h>
                     48:
1.1       thorpej    49: #include "locators.h"
                     50:
1.58      riastrad   51: #include <sys/rndsource.h>
1.1       thorpej    52:
                     53: /* data per slave device */
                     54: struct pckbc_slotdata {
1.15      jdolecek   55:        int polling;    /* don't process data in interrupt handler */
                     56:        int poll_data;  /* data read from inr handler if polling */
                     57:        int poll_stat;  /* status read from inr handler if polling */
1.52      tls        58:        krndsource_t    rnd_source;
1.1       thorpej    59: };
                     60:
1.33      perry      61: static void pckbc_init_slotdata(struct pckbc_slotdata *);
                     62: static int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
1.1       thorpej    63:
                     64: struct pckbc_internal pckbc_consdata;
                     65: int pckbc_console_attached;
                     66:
                     67: static int pckbc_console;
                     68: static struct pckbc_slotdata pckbc_cons_slotdata;
                     69:
1.33      perry      70: static int pckbc_xt_translation(void *, pckbport_slot_t, int);
                     71: static int pckbc_send_devcmd(void *, pckbport_slot_t, u_char);
                     72: static void pckbc_slot_enable(void *, pckbport_slot_t, int);
                     73: static void pckbc_intr_establish(void *, pckbport_slot_t);
                     74: static void pckbc_set_poll(void *,     pckbc_slot_t, int on);
                     75:
                     76: static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
                     77:
                     78: static int pckbc_get8042cmd(struct pckbc_internal *);
                     79: static int pckbc_put8042cmd(struct pckbc_internal *);
                     80:
                     81: void pckbc_cleanqueue(struct pckbc_slotdata *);
                     82: void pckbc_cleanup(void *);
                     83: int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
                     84: void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
1.1       thorpej    85:
1.11      jdolecek   86: const char * const pckbc_slot_names[] = { "kbd", "aux" };
1.1       thorpej    87:
1.31      bjh21      88: static struct pckbport_accessops const pckbc_ops = {
                     89:        pckbc_xt_translation,
                     90:        pckbc_send_devcmd,
                     91:        pckbc_poll_data1,
                     92:        pckbc_slot_enable,
                     93:        pckbc_intr_establish,
                     94:        pckbc_set_poll
                     95: };
1.1       thorpej    96:
                     97: #define        KBD_DELAY       DELAY(8)
                     98:
                     99: static inline int
1.44      cegger    100: pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
1.1       thorpej   101: {
                    102:        u_int i;
                    103:
                    104:        for (i = 100000; i; i--)
                    105:                if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
                    106:                        KBD_DELAY;
                    107:                        return (1);
                    108:                }
                    109:        return (0);
                    110: }
                    111:
                    112: int
1.44      cegger    113: pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
1.1       thorpej   114: {
                    115:        if (!pckbc_wait_output(iot, ioh_c))
                    116:                return (0);
                    117:        bus_space_write_1(iot, ioh_c, 0, val);
                    118:        return (1);
                    119: }
                    120:
1.15      jdolecek  121: /*
                    122:  * Note: the spl games here are to deal with some strange PC kbd controllers
                    123:  * in some system configurations.
                    124:  * This is not canonical way to handle polling input.
                    125:  */
1.1       thorpej   126: int
1.44      cegger    127: pckbc_poll_data1(void *pt, pckbc_slot_t slot)
1.1       thorpej   128: {
1.14      jdolecek  129:        struct pckbc_internal *t = pt;
1.15      jdolecek  130:        struct pckbc_slotdata *q = t->t_slotdata[slot];
1.23      jdolecek  131:        int s;
1.14      jdolecek  132:        u_char stat, c;
1.45      drochner  133:        int i = 100; /* polls for ~100ms */
1.31      bjh21     134:        int checkaux = t->t_haveaux;
1.1       thorpej   135:
1.15      jdolecek  136:        s = splhigh();
                    137:
                    138:        if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
                    139:                stat    = q->poll_stat;
                    140:                c       = q->poll_data;
                    141:                q->poll_data = -1;
                    142:                q->poll_stat = -1;
                    143:                goto process;
                    144:        }
                    145:
1.45      drochner  146:        for (; i; i--, delay(1000)) {
1.14      jdolecek  147:                stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
1.1       thorpej   148:                if (stat & KBS_DIB) {
                    149:                        KBD_DELAY;
1.14      jdolecek  150:                        c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
1.34      perry     151:
1.15      jdolecek  152:                    process:
1.1       thorpej   153:                        if (checkaux && (stat & 0x20)) { /* aux data */
                    154:                                if (slot != PCKBC_AUX_SLOT) {
                    155: #ifdef PCKBCDEBUG
1.36      christos  156:                                        printf("pckbc: lost aux 0x%x\n", c);
1.1       thorpej   157: #endif
                    158:                                        continue;
                    159:                                }
                    160:                        } else {
                    161:                                if (slot == PCKBC_AUX_SLOT) {
                    162: #ifdef PCKBCDEBUG
1.36      christos  163:                                        printf("pckbc: lost kbd 0x%x\n", c);
1.1       thorpej   164: #endif
                    165:                                        continue;
                    166:                                }
                    167:                        }
1.15      jdolecek  168:                        splx(s);
1.1       thorpej   169:                        return (c);
                    170:                }
                    171:        }
1.15      jdolecek  172:
                    173:        splx(s);
1.1       thorpej   174:        return (-1);
                    175: }
                    176:
                    177: /*
                    178:  * Get the current command byte.
                    179:  */
                    180: static int
1.44      cegger    181: pckbc_get8042cmd(struct pckbc_internal *t)
1.1       thorpej   182: {
                    183:        bus_space_tag_t iot = t->t_iot;
                    184:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    185:        int data;
                    186:
                    187:        if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
                    188:                return (0);
1.31      bjh21     189:        data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
1.1       thorpej   190:        if (data == -1)
                    191:                return (0);
                    192:        t->t_cmdbyte = data;
                    193:        return (1);
                    194: }
                    195:
                    196: /*
                    197:  * Pass command byte to keyboard controller (8042).
                    198:  */
                    199: static int
1.44      cegger    200: pckbc_put8042cmd(struct pckbc_internal *t)
1.1       thorpej   201: {
                    202:        bus_space_tag_t iot = t->t_iot;
                    203:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    204:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    205:
                    206:        if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
                    207:                return (0);
                    208:        if (!pckbc_wait_output(iot, ioh_c))
                    209:                return (0);
                    210:        bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
                    211:        return (1);
                    212: }
                    213:
                    214: static int
1.44      cegger    215: pckbc_send_devcmd(void *pt, pckbc_slot_t slot, u_char val)
1.1       thorpej   216: {
1.31      bjh21     217:        struct pckbc_internal *t = pt;
1.1       thorpej   218:        bus_space_tag_t iot = t->t_iot;
                    219:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    220:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    221:
                    222:        if (slot == PCKBC_AUX_SLOT) {
                    223:                if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
                    224:                        return (0);
                    225:        }
                    226:        if (!pckbc_wait_output(iot, ioh_c))
                    227:                return (0);
                    228:        bus_space_write_1(iot, ioh_d, 0, val);
                    229:        return (1);
                    230: }
                    231:
                    232: int
1.44      cegger    233: pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
1.1       thorpej   234: {
                    235:        if (pckbc_console && !pckbc_console_attached &&
1.50      dyoung    236:            bus_space_is_equal(pckbc_consdata.t_iot, iot) &&
1.1       thorpej   237:            pckbc_consdata.t_addr == addr)
                    238:                return (1);
                    239:        return (0);
                    240: }
                    241:
1.31      bjh21     242: static int
1.44      cegger    243: pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot)
1.1       thorpej   244: {
                    245:        struct pckbc_internal *t = sc->id;
1.19      augustss  246:        void *sdata;
1.46      cegger    247:        device_t child;
1.17      christos  248:        int alloced = 0;
1.1       thorpej   249:
1.17      christos  250:        if (t->t_slotdata[slot] == NULL) {
1.19      augustss  251:                sdata = malloc(sizeof(struct pckbc_slotdata),
1.59.18.2! martin    252:                    M_DEVBUF, M_WAITOK);
1.19      augustss  253:                t->t_slotdata[slot] = sdata;
1.1       thorpej   254:                pckbc_init_slotdata(t->t_slotdata[slot]);
1.17      christos  255:                alloced++;
                    256:        }
                    257:
1.42      cube      258:        child = pckbport_attach_slot(sc->sc_dv, t->t_pt, slot);
1.17      christos  259:
1.31      bjh21     260:        if (child == NULL && alloced) {
1.17      christos  261:                free(t->t_slotdata[slot], M_DEVBUF);
                    262:                t->t_slotdata[slot] = NULL;
1.1       thorpej   263:        }
1.17      christos  264:
1.31      bjh21     265:        if (child != NULL && t->t_slotdata[slot] != NULL)
1.17      christos  266:                rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
1.57      tls       267:                    device_xname(child), RND_TYPE_TTY, RND_FLAG_DEFAULT);
1.53      tls       268:
1.31      bjh21     269:        return child != NULL;
1.1       thorpej   270: }
                    271:
                    272: void
1.44      cegger    273: pckbc_attach(struct pckbc_softc *sc)
1.1       thorpej   274: {
                    275:        struct pckbc_internal *t;
                    276:        bus_space_tag_t iot;
                    277:        bus_space_handle_t ioh_d, ioh_c;
                    278:        int res;
                    279:        u_char cmdbits = 0;
                    280:
                    281:        t = sc->id;
                    282:        iot = t->t_iot;
                    283:        ioh_d = t->t_ioh_d;
                    284:        ioh_c = t->t_ioh_c;
                    285:
1.31      bjh21     286:        t->t_pt = pckbport_attach(t, &pckbc_ops);
                    287:        if (t->t_pt == NULL) {
                    288:                aprint_error(": attach failed\n");
                    289:                return;
                    290:        }
                    291:
1.1       thorpej   292:        /* flush */
1.31      bjh21     293:        (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
1.1       thorpej   294:
                    295:        /* set initial cmd byte */
                    296:        if (!pckbc_put8042cmd(t)) {
1.59      msaitoh   297:                aprint_error("pckbc: cmd word write error\n");
1.1       thorpej   298:                return;
                    299:        }
                    300:
                    301: /*
                    302:  * XXX Don't check the keyboard port. There are broken keyboard controllers
                    303:  * which don't pass the test but work normally otherwise.
                    304:  */
                    305: #if 0
                    306:        /*
                    307:         * check kbd port ok
                    308:         */
                    309:        if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
                    310:                return;
1.14      jdolecek  311:        res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
1.1       thorpej   312:
                    313:        /*
                    314:         * Normally, we should get a "0" here.
                    315:         * But there are keyboard controllers behaving differently.
                    316:         */
                    317:        if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
                    318: #ifdef PCKBCDEBUG
                    319:                if (res != 0)
1.36      christos  320:                        printf("pckbc: returned %x on kbd slot test\n", res);
1.1       thorpej   321: #endif
                    322:                if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
                    323:                        cmdbits |= KC8_KENABLE;
                    324:        } else {
1.36      christos  325:                printf("pckbc: kbd port test: %x\n", res);
1.1       thorpej   326:                return;
                    327:        }
                    328: #else
                    329:        if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
                    330:                cmdbits |= KC8_KENABLE;
                    331: #endif /* 0 */
                    332:
                    333:        /*
1.6       drochner  334:         * Check aux port ok.
                    335:         * Avoid KBC_AUXTEST because it hangs some older controllers
                    336:         *  (eg UMC880?).
1.1       thorpej   337:         */
1.6       drochner  338:        if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
1.59      msaitoh   339:                aprint_error("pckbc: aux echo error 1\n");
1.6       drochner  340:                goto nomouse;
                    341:        }
                    342:        if (!pckbc_wait_output(iot, ioh_c)) {
1.59      msaitoh   343:                aprint_error("pckbc: aux echo error 2\n");
1.6       drochner  344:                goto nomouse;
                    345:        }
1.31      bjh21     346:        t->t_haveaux = 1;
1.6       drochner  347:        bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
1.31      bjh21     348:        res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
1.54      jdc       349:
                    350:        /*
                    351:         * The following is needed to find the aux port on the Tadpole
                    352:         * SPARCle.
                    353:         */
                    354:        if (res == -1 && ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
                    355:                /* Read of aux echo timed out, try again */
                    356:                if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
                    357:                        goto nomouse;
                    358:                if (!pckbc_wait_output(iot, ioh_c))
                    359:                        goto nomouse;
                    360:                bus_space_write_1(iot, ioh_d, 0, 0x5a);
                    361:                res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
                    362:        }
1.8       drochner  363:        if (res != -1) {
1.7       christos  364:                /*
1.8       drochner  365:                 * In most cases, the 0x5a gets echoed.
                    366:                 * Some older controllers (Gateway 2000 circa 1993)
                    367:                 * return 0xfe here.
                    368:                 * We are satisfied if there is anything in the
                    369:                 * aux output buffer.
1.7       christos  370:                 */
1.1       thorpej   371:                if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
                    372:                        cmdbits |= KC8_MENABLE;
1.31      bjh21     373:        } else {
1.54      jdc       374:
1.8       drochner  375: #ifdef PCKBCDEBUG
1.36      christos  376:                printf("pckbc: aux echo test failed\n");
1.8       drochner  377: #endif
1.31      bjh21     378:                t->t_haveaux = 0;
                    379:        }
1.1       thorpej   380:
1.6       drochner  381: nomouse:
1.1       thorpej   382:        /* enable needed interrupts */
                    383:        t->t_cmdbyte |= cmdbits;
                    384:        if (!pckbc_put8042cmd(t))
1.59      msaitoh   385:                aprint_error("pckbc: cmd word write error\n");
1.1       thorpej   386: }
                    387:
1.31      bjh21     388: static void
1.44      cegger    389: pckbc_init_slotdata(struct pckbc_slotdata *q)
1.1       thorpej   390: {
                    391:
                    392:        q->polling = 0;
                    393: }
                    394:
                    395: /*
                    396:  * switch scancode translation on / off
                    397:  * return nonzero on success
                    398:  */
1.31      bjh21     399: static int
1.44      cegger    400: pckbc_xt_translation(void *self, pckbc_slot_t slot, int on)
1.1       thorpej   401: {
                    402:        struct pckbc_internal *t = self;
                    403:        int ison;
                    404:
1.54      jdc       405:        if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE))
                    406:                return (-1);
                    407:
1.1       thorpej   408:        if (slot != PCKBC_KBD_SLOT) {
                    409:                /* translation only for kbd slot */
                    410:                if (on)
                    411:                        return (0);
                    412:                else
                    413:                        return (1);
                    414:        }
                    415:
                    416:        ison = t->t_cmdbyte & KC8_TRANS;
                    417:        if ((on && ison) || (!on && !ison))
                    418:                return (1);
                    419:
                    420:        t->t_cmdbyte ^= KC8_TRANS;
                    421:        if (!pckbc_put8042cmd(t))
                    422:                return (0);
                    423:
                    424:        /* read back to be sure */
                    425:        if (!pckbc_get8042cmd(t))
                    426:                return (0);
                    427:
                    428:        ison = t->t_cmdbyte & KC8_TRANS;
                    429:        if ((on && ison) || (!on && !ison))
                    430:                return (1);
                    431:        return (0);
                    432: }
                    433:
1.11      jdolecek  434: static const struct pckbc_portcmd {
1.1       thorpej   435:        u_char cmd_en, cmd_dis;
                    436: } pckbc_portcmd[2] = {
                    437:        {
                    438:                KBC_KBDENABLE, KBC_KBDDISABLE,
                    439:        }, {
                    440:                KBC_AUXENABLE, KBC_AUXDISABLE,
                    441:        }
                    442: };
                    443:
                    444: void
1.44      cegger    445: pckbc_slot_enable(void *self, pckbc_slot_t slot, int on)
1.1       thorpej   446: {
                    447:        struct pckbc_internal *t = (struct pckbc_internal *)self;
1.11      jdolecek  448:        const struct pckbc_portcmd *cmd;
1.1       thorpej   449:
                    450:        cmd = &pckbc_portcmd[slot];
                    451:
                    452:        if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
                    453:                            on ? cmd->cmd_en : cmd->cmd_dis))
1.36      christos  454:                printf("pckbc: pckbc_slot_enable(%d) failed\n", on);
1.1       thorpej   455: }
                    456:
1.31      bjh21     457: static void
1.44      cegger    458: pckbc_set_poll(void *self, pckbc_slot_t slot, int on)
1.1       thorpej   459: {
                    460:        struct pckbc_internal *t = (struct pckbc_internal *)self;
                    461:
                    462:        t->t_slotdata[slot]->polling = on;
                    463:
1.15      jdolecek  464:        if (on) {
                    465:                t->t_slotdata[slot]->poll_data = -1;
                    466:                t->t_slotdata[slot]->poll_stat = -1;
                    467:        } else {
1.51      isaki     468:                int s;
1.1       thorpej   469:
1.51      isaki     470:                /*
                    471:                 * If disabling polling on a device that's been configured,
                    472:                 * make sure there are no bytes left in the FIFO, holding up
                    473:                 * the interrupt line.  Otherwise we won't get any further
                    474:                 * interrupts.
                    475:                 */
1.1       thorpej   476:                if (t->t_sc) {
                    477:                        s = spltty();
                    478:                        pckbcintr(t->t_sc);
                    479:                        splx(s);
                    480:                }
                    481:        }
                    482: }
                    483:
                    484: static void
1.44      cegger    485: pckbc_intr_establish(void *pt, pckbport_slot_t slot)
1.1       thorpej   486: {
1.31      bjh21     487:        struct pckbc_internal *t = pt;
1.1       thorpej   488:
1.31      bjh21     489:        (*t->t_sc->intr_establish)(t->t_sc, slot);
1.28      martin    490: }
                    491:
                    492: int
1.44      cegger    493: pckbcintr_hard(void *vsc)
1.28      martin    494: {
                    495:        struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
                    496:        struct pckbc_internal *t = sc->id;
                    497:        u_char stat;
                    498:        pckbc_slot_t slot;
                    499:        struct pckbc_slotdata *q;
                    500:        int served = 0, data, next, s;
                    501:
                    502:        for(;;) {
                    503:                stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
                    504:                if (!(stat & KBS_DIB))
                    505:                        break;
                    506:
                    507:                served = 1;
                    508:
                    509:                slot = (t->t_haveaux && (stat & 0x20)) ?
                    510:                    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
                    511:                q = t->t_slotdata[slot];
                    512:
                    513:                if (!q) {
                    514:                        /* XXX do something for live insertion? */
1.36      christos  515:                        printf("pckbc: no dev for slot %d\n", slot);
1.28      martin    516:                        KBD_DELAY;
                    517:                        (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    518:                        continue;
                    519:                }
                    520:
                    521:                KBD_DELAY;
                    522:                data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    523:
                    524:                rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
                    525:
                    526:                if (q->polling) {
                    527:                        q->poll_data = data;
                    528:                        q->poll_stat = stat;
                    529:                        break; /* pckbc_poll_data() will get it */
                    530:                }
                    531:
1.31      bjh21     532: #if 0 /* XXXBJH */
1.28      martin    533:                if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
                    534:                        continue;
1.31      bjh21     535: #endif
1.28      martin    536:
                    537:                s = splhigh();
                    538:                next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
                    539:                if (next == t->rbuf_read) {
                    540:                        splx(s);
                    541:                        break;
                    542:                }
                    543:                t->rbuf[t->rbuf_write].data = data;
                    544:                t->rbuf[t->rbuf_write].slot = slot;
                    545:                t->rbuf_write = next;
                    546:                splx(s);
                    547:        }
                    548:
                    549:        return (served);
                    550: }
                    551:
                    552: void
1.44      cegger    553: pckbcintr_soft(void *vsc)
1.28      martin    554: {
                    555:        struct pckbc_softc *sc = vsc;
                    556:        struct pckbc_internal *t = sc->id;
                    557:        int data, slot, s;
                    558: #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
1.29      martin    559:        int st;
1.28      martin    560:
1.29      martin    561:        st = spltty();
1.28      martin    562: #endif
                    563:
                    564:        s = splhigh();
                    565:        while (t->rbuf_read != t->rbuf_write) {
                    566:                slot = t->rbuf[t->rbuf_read].slot;
                    567:                data = t->rbuf[t->rbuf_read].data;
                    568:                t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
                    569:                splx(s);
1.31      bjh21     570:                pckbportintr(t->t_pt, slot, data);
1.28      martin    571:                s = splhigh();
                    572:        }
                    573:        splx(s);
                    574:
                    575:
                    576: #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
1.29      martin    577:        splx(st);
1.28      martin    578: #endif
1.1       thorpej   579: }
                    580:
                    581: int
1.44      cegger    582: pckbcintr(void *vsc)
1.1       thorpej   583: {
                    584:        struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
                    585:        struct pckbc_internal *t = sc->id;
                    586:        u_char stat;
                    587:        pckbc_slot_t slot;
                    588:        struct pckbc_slotdata *q;
                    589:        int served = 0, data;
                    590:
                    591:        for(;;) {
                    592:                stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
                    593:                if (!(stat & KBS_DIB))
                    594:                        break;
                    595:
                    596:                slot = (t->t_haveaux && (stat & 0x20)) ?
                    597:                    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
                    598:                q = t->t_slotdata[slot];
                    599:
1.56      jakllsch  600:                if (q != NULL && q->polling)
                    601:                        return 0;
                    602:
                    603:                served = 1;
1.1       thorpej   604:                KBD_DELAY;
                    605:                data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    606:
1.59.18.1  christos  607:                if (q != NULL)
                    608:                        rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
1.15      jdolecek  609:
1.31      bjh21     610:                pckbportintr(t->t_pt, slot, data);
1.1       thorpej   611:        }
                    612:
                    613:        return (served);
                    614: }
                    615:
                    616: int
1.44      cegger    617: pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr,
1.54      jdc       618:        bus_size_t cmd_offset, pckbc_slot_t slot, int flags)
1.1       thorpej   619: {
                    620:        bus_space_handle_t ioh_d, ioh_c;
1.26      uwe       621: #ifdef PCKBC_CNATTACH_SELFTEST
                    622:        int reply;
                    623: #endif
1.1       thorpej   624:        int res = 0;
                    625:
                    626:        if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
1.51      isaki     627:                return (ENXIO);
1.5       soda      628:        if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
1.1       thorpej   629:                bus_space_unmap(iot, ioh_d, 1);
1.51      isaki     630:                return (ENXIO);
1.1       thorpej   631:        }
                    632:
1.14      jdolecek  633:        memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
1.1       thorpej   634:        pckbc_consdata.t_iot = iot;
                    635:        pckbc_consdata.t_ioh_d = ioh_d;
                    636:        pckbc_consdata.t_ioh_c = ioh_c;
                    637:        pckbc_consdata.t_addr = addr;
1.54      jdc       638:        pckbc_consdata.t_flags = flags;
1.37      ad        639:        callout_init(&pckbc_consdata.t_cleanup, 0);
1.1       thorpej   640:
                    641:        /* flush */
1.31      bjh21     642:        (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
1.1       thorpej   643:
1.26      uwe       644: #ifdef PCKBC_CNATTACH_SELFTEST
                    645:        /*
                    646:         * In some machines (e.g. netwinder) pckbc refuses to talk at
                    647:         * all until we request a self-test.
                    648:         */
                    649:        if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
1.36      christos  650:                printf("pckbc: unable to request selftest\n");
1.26      uwe       651:                res = EIO;
                    652:                goto out;
                    653:        }
                    654:
1.31      bjh21     655:        reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
1.26      uwe       656:        if (reply != 0x55) {
1.36      christos  657:                printf("pckbc: selftest returned 0x%02x\n", reply);
1.26      uwe       658:                res = EIO;
                    659:                goto out;
                    660:        }
                    661: #endif /* PCKBC_CNATTACH_SELFTEST */
1.1       thorpej   662:
                    663:        /* init cmd byte, enable ports */
                    664:        pckbc_consdata.t_cmdbyte = KC8_CPU;
                    665:        if (!pckbc_put8042cmd(&pckbc_consdata)) {
1.36      christos  666:                printf("pckbc: cmd word write error\n");
1.1       thorpej   667:                res = EIO;
1.26      uwe       668:                goto out;
1.1       thorpej   669:        }
                    670:
1.31      bjh21     671:        res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
1.1       thorpej   672:
1.26      uwe       673:   out:
1.1       thorpej   674:        if (res) {
                    675:                bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
                    676:                bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
                    677:        } else {
                    678:                pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
                    679:                pckbc_init_slotdata(&pckbc_cons_slotdata);
                    680:                pckbc_console = 1;
                    681:        }
                    682:
                    683:        return (res);
                    684: }
1.39      jmcneill  685:
                    686: bool
1.48      dyoung    687: pckbc_resume(device_t dv, const pmf_qual_t *qual)
1.39      jmcneill  688: {
                    689:        struct pckbc_softc *sc = device_private(dv);
                    690:        struct pckbc_internal *t;
                    691:
                    692:        t = sc->id;
                    693:        (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
                    694:        if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, KBC_SELFTEST))
                    695:                return false;
                    696:        (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
                    697:        (void)pckbc_put8042cmd(t);
                    698:        pckbcintr(t->t_sc);
                    699:
                    700:        return true;
                    701: }

CVSweb <webmaster@jp.NetBSD.org>