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

Annotation of sys/dev/ic/pckbc.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: pckbc.c,v 1.14 2007/01/31 14:38:54 mickey Exp $ */
                      2: /* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */
                      3:
                      4: /*
                      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:  */
                     28:
                     29: #include <sys/param.h>
                     30: #include <sys/systm.h>
                     31: #include <sys/timeout.h>
                     32: #include <sys/kernel.h>
                     33: #include <sys/proc.h>
                     34: #include <sys/device.h>
                     35: #include <sys/malloc.h>
                     36: #include <sys/errno.h>
                     37: #include <sys/queue.h>
                     38: #include <sys/lock.h>
                     39:
                     40: #include <machine/bus.h>
                     41:
                     42: #include <dev/ic/i8042reg.h>
                     43: #include <dev/ic/pckbcvar.h>
                     44:
                     45: #include "pckbd.h"
                     46:
                     47: #if (NPCKBD > 0)
                     48: #include <dev/pckbc/pckbdvar.h>
                     49: #endif
                     50:
                     51: /* descriptor for one device command */
                     52: struct pckbc_devcmd {
                     53:        TAILQ_ENTRY(pckbc_devcmd) next;
                     54:        int flags;
                     55: #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
                     56: #define KBC_CMDFLAG_SLOW 2
                     57:        u_char cmd[4];
                     58:        int cmdlen, cmdidx, retries;
                     59:        u_char response[4];
                     60:        int status, responselen, responseidx;
                     61: };
                     62:
                     63: /* data per slave device */
                     64: struct pckbc_slotdata {
                     65:        int polling; /* don't read data port in interrupt handler */
                     66:        TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
                     67:        TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
                     68: #define NCMD 5
                     69:        struct pckbc_devcmd cmds[NCMD];
                     70: };
                     71:
                     72: #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
                     73:
                     74: void pckbc_init_slotdata(struct pckbc_slotdata *);
                     75: int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
                     76: int pckbc_submatch(struct device *, void *, void *);
                     77: int pckbcprint(void *, const char *);
                     78:
                     79: struct pckbc_internal pckbc_consdata;
                     80: int pckbc_console_attached;
                     81:
                     82: static int pckbc_console;
                     83: static struct pckbc_slotdata pckbc_cons_slotdata;
                     84:
                     85: static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
                     86:
                     87: static int pckbc_get8042cmd(struct pckbc_internal *);
                     88: static int pckbc_put8042cmd(struct pckbc_internal *);
                     89: static int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t,
                     90:                                  u_char);
                     91: static void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t,
                     92:                                 struct pckbc_devcmd *);
                     93:
                     94: void pckbc_cleanqueue(struct pckbc_slotdata *);
                     95: void pckbc_cleanup(void *);
                     96: void pckbc_poll(void *);
                     97: int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
                     98: void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
                     99: int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *);
                    100:
                    101: const char *pckbc_slot_names[] = { "kbd", "aux" };
                    102:
                    103: #define KBC_DEVCMD_ACK 0xfa
                    104: #define KBC_DEVCMD_RESEND 0xfe
                    105:
                    106: #define        KBD_DELAY       DELAY(8)
                    107:
                    108: static inline int
                    109: pckbc_wait_output(iot, ioh_c)
                    110:        bus_space_tag_t iot;
                    111:        bus_space_handle_t ioh_c;
                    112: {
                    113:        u_int i;
                    114:
                    115:        for (i = 100000; i; i--)
                    116:                if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
                    117:                        KBD_DELAY;
                    118:                        return (1);
                    119:                }
                    120:        return (0);
                    121: }
                    122:
                    123: int
                    124: pckbc_send_cmd(iot, ioh_c, val)
                    125:        bus_space_tag_t iot;
                    126:        bus_space_handle_t ioh_c;
                    127:        u_char val;
                    128: {
                    129:        if (!pckbc_wait_output(iot, ioh_c))
                    130:                return (0);
                    131:        bus_space_write_1(iot, ioh_c, 0, val);
                    132:        return (1);
                    133: }
                    134:
                    135: int
                    136: pckbc_poll_data1(iot, ioh_d, ioh_c, slot, checkaux)
                    137:        bus_space_tag_t iot;
                    138:        bus_space_handle_t ioh_d, ioh_c;
                    139:        pckbc_slot_t slot;
                    140:        int checkaux;
                    141: {
                    142:        int i;
                    143:        u_char stat;
                    144:
                    145:        /* if 1 port read takes 1us (?), this polls for 100ms */
                    146:        for (i = 100000; i; i--) {
                    147:                stat = bus_space_read_1(iot, ioh_c, 0);
                    148:                if (stat & KBS_DIB) {
                    149:                        register u_char c;
                    150:
                    151:                        KBD_DELAY;
                    152:                        c = bus_space_read_1(iot, ioh_d, 0);
                    153:                        if (checkaux && (stat & 0x20)) { /* aux data */
                    154:                                if (slot != PCKBC_AUX_SLOT) {
                    155: #ifdef PCKBCDEBUG
                    156:                                        printf("lost aux 0x%x\n", c);
                    157: #endif
                    158:                                        continue;
                    159:                                }
                    160:                        } else {
                    161:                                if (slot == PCKBC_AUX_SLOT) {
                    162: #ifdef PCKBCDEBUG
                    163:                                        printf("lost kbd 0x%x\n", c);
                    164: #endif
                    165:                                        continue;
                    166:                                }
                    167:                        }
                    168:                        return (c);
                    169:                }
                    170:        }
                    171:        return (-1);
                    172: }
                    173:
                    174: /*
                    175:  * Get the current command byte.
                    176:  */
                    177: static int
                    178: pckbc_get8042cmd(t)
                    179:        struct pckbc_internal *t;
                    180: {
                    181:        bus_space_tag_t iot = t->t_iot;
                    182:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    183:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    184:        int data;
                    185:
                    186:        if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
                    187:                return (0);
                    188:        data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
                    189:                                t->t_haveaux);
                    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
                    200: pckbc_put8042cmd(t)
                    201:        struct pckbc_internal *t;
                    202: {
                    203:        bus_space_tag_t iot = t->t_iot;
                    204:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    205:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    206:
                    207:        if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
                    208:                return (0);
                    209:        if (!pckbc_wait_output(iot, ioh_c))
                    210:                return (0);
                    211:        bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
                    212:        return (1);
                    213: }
                    214:
                    215: static int
                    216: pckbc_send_devcmd(t, slot, val)
                    217:        struct pckbc_internal *t;
                    218:        pckbc_slot_t slot;
                    219:        u_char val;
                    220: {
                    221:        bus_space_tag_t iot = t->t_iot;
                    222:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    223:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    224:
                    225:        if (slot == PCKBC_AUX_SLOT) {
                    226:                if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
                    227:                        return (0);
                    228:        }
                    229:        if (!pckbc_wait_output(iot, ioh_c))
                    230:                return (0);
                    231:        bus_space_write_1(iot, ioh_d, 0, val);
                    232:        return (1);
                    233: }
                    234:
                    235: int
                    236: pckbc_is_console(iot, addr)
                    237:        bus_space_tag_t iot;
                    238:        bus_addr_t addr;
                    239: {
                    240:        if (pckbc_console && !pckbc_console_attached &&
                    241:            pckbc_consdata.t_iot == iot &&
                    242:            pckbc_consdata.t_addr == addr)
                    243:                return (1);
                    244:        return (0);
                    245: }
                    246:
                    247: int
                    248: pckbc_submatch(parent, match, aux)
                    249:        struct device *parent;
                    250:        void *match;
                    251:        void *aux;
                    252: {
                    253:        struct cfdata *cf = match;
                    254:        struct pckbc_attach_args *pa = aux;
                    255:
                    256:        if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
                    257:            cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
                    258:                return (0);
                    259:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
                    260: }
                    261:
                    262: int
                    263: pckbc_attach_slot(sc, slot)
                    264:        struct pckbc_softc *sc;
                    265:        pckbc_slot_t slot;
                    266: {
                    267:        struct pckbc_internal *t = sc->id;
                    268:        struct pckbc_attach_args pa;
                    269:        int found;
                    270:
                    271:        pa.pa_tag = t;
                    272:        pa.pa_slot = slot;
                    273:        found = (config_found_sm((struct device *)sc, &pa,
                    274:                                 pckbcprint, pckbc_submatch) != NULL);
                    275:
                    276:        if (found && !t->t_slotdata[slot]) {
                    277:                t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata),
                    278:                                             M_DEVBUF, M_NOWAIT);
                    279:                if (t->t_slotdata[slot] == NULL)
                    280:                        return 0;
                    281:                pckbc_init_slotdata(t->t_slotdata[slot]);
                    282:        }
                    283:        return (found);
                    284: }
                    285:
                    286: void
                    287: pckbc_attach(sc)
                    288:        struct pckbc_softc *sc;
                    289: {
                    290:        struct pckbc_internal *t;
                    291:        bus_space_tag_t iot;
                    292:        bus_space_handle_t ioh_d, ioh_c;
                    293:        int res;
                    294:        u_char cmdbits = 0;
                    295:
                    296:        t = sc->id;
                    297:        iot = t->t_iot;
                    298:        ioh_d = t->t_ioh_d;
                    299:        ioh_c = t->t_ioh_c;
                    300:
                    301:        if (pckbc_console == 0) {
                    302:                timeout_set(&t->t_cleanup, pckbc_cleanup, t);
                    303:                timeout_set(&t->t_poll, pckbc_poll, t);
                    304:        }
                    305:
                    306:        /* flush */
                    307:        (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
                    308:
                    309:        /* set initial cmd byte */
                    310:        if (!pckbc_put8042cmd(t)) {
                    311:                printf("kbc: cmd word write error\n");
                    312:                return;
                    313:        }
                    314:
                    315: /*
                    316:  * XXX Don't check the keyboard port. There are broken keyboard controllers
                    317:  * which don't pass the test but work normally otherwise.
                    318:  */
                    319: #if 0
                    320:        /*
                    321:         * check kbd port ok
                    322:         */
                    323:        if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
                    324:                return;
                    325:        res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
                    326:
                    327:        /*
                    328:         * Normally, we should get a "0" here.
                    329:         * But there are keyboard controllers behaving differently.
                    330:         */
                    331:        if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
                    332: #ifdef PCKBCDEBUG
                    333:                if (res != 0)
                    334:                        printf("kbc: returned %x on kbd slot test\n", res);
                    335: #endif
                    336:                if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
                    337:                        cmdbits |= KC8_KENABLE;
                    338:        } else {
                    339:                printf("kbc: kbd port test: %x\n", res);
                    340:                return;
                    341:        }
                    342: #else
                    343:        if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
                    344:                cmdbits |= KC8_KENABLE;
                    345: #endif /* 0 */
                    346:
                    347:        /*
                    348:         * Check aux port ok.
                    349:         * Avoid KBC_AUXTEST because it hangs some older controllers
                    350:         * (eg UMC880?).
                    351:         */
                    352:        if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
                    353:                printf("kbc: aux echo error 1\n");
                    354:                goto nomouse;
                    355:        }
                    356:        if (!pckbc_wait_output(iot, ioh_c)) {
                    357:                printf("kbc: aux echo error 2\n");
                    358:                goto nomouse;
                    359:        }
                    360:        bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
                    361:        res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
                    362:        if (res == -1) {
                    363:                /* Read of aux echo timed out, try again */
                    364:                if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
                    365:                        goto nomouse;
                    366:                if (!pckbc_wait_output(iot, ioh_c))
                    367:                        goto nomouse;
                    368:                bus_space_write_1(iot, ioh_d, 0, 0x5a);
                    369:                res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
                    370: #ifdef PCKBCDEBUG
                    371:                printf("kbc: aux echo: %x\n", res);
                    372: #endif
                    373:        }
                    374:        if (res != -1) {
                    375:                /*
                    376:                 * In most cases, the 0x5a gets echoed.
                    377:                 * Some old controllers (Gateway 2000 circa 1993)
                    378:                 * return 0xfe here.
                    379:                 * We are satisfied if there is anything in the
                    380:                 * aux output buffer.
                    381:                 */
                    382: #ifdef PCKBCDEBUG
                    383:                printf("kbc: aux echo: %x\n", res);
                    384: #endif
                    385:                t->t_haveaux = 1;
                    386:                if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
                    387:                        cmdbits |= KC8_MENABLE;
                    388:        }
                    389: #ifdef PCKBCDEBUG
                    390:        else
                    391:                printf("kbc: aux echo test failed\n");
                    392: #endif
                    393:
                    394: nomouse:
                    395:        /* enable needed interrupts */
                    396:        t->t_cmdbyte |= cmdbits;
                    397:        if (!pckbc_put8042cmd(t))
                    398:                printf("kbc: cmd word write error\n");
                    399: }
                    400:
                    401: int
                    402: pckbcprint(aux, pnp)
                    403:        void *aux;
                    404:        const char *pnp;
                    405: {
                    406:        struct pckbc_attach_args *pa = aux;
                    407:
                    408:        if (!pnp)
                    409:                printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
                    410:        return (QUIET);
                    411: }
                    412:
                    413: void
                    414: pckbc_init_slotdata(q)
                    415:        struct pckbc_slotdata *q;
                    416: {
                    417:        int i;
                    418:        TAILQ_INIT(&q->cmdqueue);
                    419:        TAILQ_INIT(&q->freequeue);
                    420:
                    421:        for (i = 0; i < NCMD; i++) {
                    422:                TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
                    423:        }
                    424:        q->polling = 0;
                    425: }
                    426:
                    427: void
                    428: pckbc_flush(self, slot)
                    429:        pckbc_tag_t self;
                    430:        pckbc_slot_t slot;
                    431: {
                    432:        struct pckbc_internal *t = self;
                    433:
                    434:        (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
                    435:            slot, t->t_haveaux);
                    436: }
                    437:
                    438: int
                    439: pckbc_poll_data(self, slot)
                    440:        pckbc_tag_t self;
                    441:        pckbc_slot_t slot;
                    442: {
                    443:        struct pckbc_internal *t = self;
                    444:        struct pckbc_slotdata *q = t->t_slotdata[slot];
                    445:        int c;
                    446:
                    447:        c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
                    448:                             slot, t->t_haveaux);
                    449:        if (c != -1 && q && CMD_IN_QUEUE(q)) {
                    450:                /* we jumped into a running command - try to
                    451:                 deliver the response */
                    452:                if (pckbc_cmdresponse(t, slot, c))
                    453:                        return (-1);
                    454:        }
                    455:        return (c);
                    456: }
                    457:
                    458: /*
                    459:  * switch scancode translation on / off
                    460:  * return nonzero on success
                    461:  */
                    462: int
                    463: pckbc_xt_translation(self, slot, on)
                    464:        pckbc_tag_t self;
                    465:        pckbc_slot_t slot;
                    466:        int on;
                    467: {
                    468:        struct pckbc_internal *t = self;
                    469:        int ison;
                    470:
                    471:        if (slot != PCKBC_KBD_SLOT) {
                    472:                /* translation only for kbd slot */
                    473:                if (on)
                    474:                        return (0);
                    475:                else
                    476:                        return (1);
                    477:        }
                    478:
                    479:        ison = t->t_cmdbyte & KC8_TRANS;
                    480:        if ((on && ison) || (!on && !ison))
                    481:                return (1);
                    482:
                    483:        t->t_cmdbyte ^= KC8_TRANS;
                    484:        if (!pckbc_put8042cmd(t))
                    485:                return (0);
                    486:
                    487:        /* read back to be sure */
                    488:        if (!pckbc_get8042cmd(t))
                    489:                return (0);
                    490:
                    491:        ison = t->t_cmdbyte & KC8_TRANS;
                    492:        if ((on && ison) || (!on && !ison))
                    493:                return (1);
                    494:        return (0);
                    495: }
                    496:
                    497: static struct pckbc_portcmd {
                    498:        u_char cmd_en, cmd_dis;
                    499: } pckbc_portcmd[2] = {
                    500:        {
                    501:                KBC_KBDENABLE, KBC_KBDDISABLE,
                    502:        }, {
                    503:                KBC_AUXENABLE, KBC_AUXDISABLE,
                    504:        }
                    505: };
                    506:
                    507: void
                    508: pckbc_slot_enable(self, slot, on)
                    509:        pckbc_tag_t self;
                    510:        pckbc_slot_t slot;
                    511:        int on;
                    512: {
                    513:        struct pckbc_internal *t = (struct pckbc_internal *)self;
                    514:        struct pckbc_portcmd *cmd;
                    515:
                    516:        cmd = &pckbc_portcmd[slot];
                    517:
                    518:        if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
                    519:                            on ? cmd->cmd_en : cmd->cmd_dis))
                    520:                printf("pckbc_slot_enable(%d) failed\n", on);
                    521:
                    522:        if (slot == PCKBC_KBD_SLOT) {
                    523:                if (on)
                    524:                        timeout_add(&t->t_poll, hz);
                    525:                else
                    526:                        timeout_del(&t->t_poll);
                    527:        }
                    528: }
                    529:
                    530: void
                    531: pckbc_set_poll(self, slot, on)
                    532:        pckbc_tag_t self;
                    533:        pckbc_slot_t slot;
                    534:        int on;
                    535: {
                    536:        struct pckbc_internal *t = (struct pckbc_internal *)self;
                    537:
                    538:        t->t_slotdata[slot]->polling = on;
                    539:
                    540:        if (!on) {
                    541:                 int s;
                    542:
                    543:                 /*
                    544:                  * If disabling polling on a device that's been configured,
                    545:                  * make sure there are no bytes left in the FIFO, holding up
                    546:                  * the interrupt line.  Otherwise we won't get any further
                    547:                  * interrupts.
                    548:                  */
                    549:                if (t->t_sc) {
                    550:                        s = spltty();
                    551:                        pckbcintr_internal(t, t->t_sc);
                    552:                        splx(s);
                    553:                }
                    554:        }
                    555: }
                    556:
                    557: /*
                    558:  * Pass command to device, poll for ACK and data.
                    559:  * to be called at spltty()
                    560:  */
                    561: static void
                    562: pckbc_poll_cmd1(t, slot, cmd)
                    563:        struct pckbc_internal *t;
                    564:        pckbc_slot_t slot;
                    565:        struct pckbc_devcmd *cmd;
                    566: {
                    567:        bus_space_tag_t iot = t->t_iot;
                    568:        bus_space_handle_t ioh_d = t->t_ioh_d;
                    569:        bus_space_handle_t ioh_c = t->t_ioh_c;
                    570:        int i, c = 0;
                    571:
                    572:        while (cmd->cmdidx < cmd->cmdlen) {
                    573:                if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
                    574:                        printf("pckbc_cmd: send error\n");
                    575:                        cmd->status = EIO;
                    576:                        return;
                    577:                }
                    578:                for (i = 10; i; i--) { /* 1s ??? */
                    579:                        c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
                    580:                                             t->t_haveaux);
                    581:                        if (c != -1)
                    582:                                break;
                    583:                }
                    584:
                    585:                if (c == KBC_DEVCMD_ACK) {
                    586:                        cmd->cmdidx++;
                    587:                        continue;
                    588:                }
                    589:                if (c == KBC_DEVCMD_RESEND) {
                    590: #ifdef PCKBCDEBUG
                    591:                        printf("pckbc_cmd: RESEND\n");
                    592: #endif
                    593:                        if (cmd->retries++ < 5)
                    594:                                continue;
                    595:                        else {
                    596: #ifdef PCKBCDEBUG
                    597:                                printf("pckbc: cmd failed\n");
                    598: #endif
                    599:                                cmd->status = EIO;
                    600:                                return;
                    601:                        }
                    602:                }
                    603:                if (c == -1) {
                    604: #ifdef PCKBCDEBUG
                    605:                        printf("pckbc_cmd: timeout\n");
                    606: #endif
                    607:                        cmd->status = EIO;
                    608:                        return;
                    609:                }
                    610: #ifdef PCKBCDEBUG
                    611:                printf("pckbc_cmd: lost 0x%x\n", c);
                    612: #endif
                    613:        }
                    614:
                    615:        while (cmd->responseidx < cmd->responselen) {
                    616:                if (cmd->flags & KBC_CMDFLAG_SLOW)
                    617:                        i = 100; /* 10s ??? */
                    618:                else
                    619:                        i = 10; /* 1s ??? */
                    620:                while (i--) {
                    621:                        c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
                    622:                                             t->t_haveaux);
                    623:                        if (c != -1)
                    624:                                break;
                    625:                }
                    626:                if (c == -1) {
                    627: #ifdef PCKBCDEBUG
                    628:                        printf("pckbc_cmd: no data\n");
                    629: #endif
                    630:                        cmd->status = ETIMEDOUT;
                    631:                        return;
                    632:                } else
                    633:                        cmd->response[cmd->responseidx++] = c;
                    634:        }
                    635: }
                    636:
                    637: /* for use in autoconfiguration */
                    638: int
                    639: pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
                    640:        pckbc_tag_t self;
                    641:        pckbc_slot_t slot;
                    642:        u_char *cmd;
                    643:        int len, responselen;
                    644:        u_char *respbuf;
                    645:        int slow;
                    646: {
                    647:        struct pckbc_devcmd nc;
                    648:
                    649:        if ((len > 4) || (responselen > 4))
                    650:                return (EINVAL);
                    651:
                    652:        bzero(&nc, sizeof(nc));
                    653:        bcopy(cmd, nc.cmd, len);
                    654:        nc.cmdlen = len;
                    655:        nc.responselen = responselen;
                    656:        nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
                    657:
                    658:        pckbc_poll_cmd1(self, slot, &nc);
                    659:
                    660:        if (nc.status == 0 && respbuf)
                    661:                bcopy(nc.response, respbuf, responselen);
                    662:
                    663:        return (nc.status);
                    664: }
                    665:
                    666: /*
                    667:  * Clean up a command queue, throw away everything.
                    668:  */
                    669: void
                    670: pckbc_cleanqueue(q)
                    671:        struct pckbc_slotdata *q;
                    672: {
                    673:        struct pckbc_devcmd *cmd;
                    674: #ifdef PCKBCDEBUG
                    675:        int i;
                    676: #endif
                    677:
                    678:        while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
                    679:                TAILQ_REMOVE(&q->cmdqueue, cmd, next);
                    680: #ifdef PCKBCDEBUG
                    681:                printf("pckbc_cleanqueue: removing");
                    682:                for (i = 0; i < cmd->cmdlen; i++)
                    683:                        printf(" %02x", cmd->cmd[i]);
                    684:                printf("\n");
                    685: #endif
                    686:                TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
                    687:        }
                    688: }
                    689:
                    690: /*
                    691:  * Timeout error handler: clean queues and data port.
                    692:  * XXX could be less invasive.
                    693:  */
                    694: void
                    695: pckbc_cleanup(self)
                    696:        void *self;
                    697: {
                    698:        struct pckbc_internal *t = self;
                    699:        int s;
                    700:
                    701:        printf("pckbc: command timeout\n");
                    702:
                    703:        s = spltty();
                    704:
                    705:        if (t->t_slotdata[PCKBC_KBD_SLOT])
                    706:                pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
                    707:        if (t->t_slotdata[PCKBC_AUX_SLOT])
                    708:                pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
                    709:
                    710:        while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
                    711:                KBD_DELAY;
                    712:                (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    713:        }
                    714:
                    715:        /* reset KBC? */
                    716:
                    717:        splx(s);
                    718: }
                    719:
                    720: /*
                    721:  * Pass command to device during normal operation.
                    722:  * to be called at spltty()
                    723:  */
                    724: void
                    725: pckbc_start(t, slot)
                    726:        struct pckbc_internal *t;
                    727:        pckbc_slot_t slot;
                    728: {
                    729:        struct pckbc_slotdata *q = t->t_slotdata[slot];
                    730:        struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
                    731:
                    732:        if (q->polling) {
                    733:                do {
                    734:                        pckbc_poll_cmd1(t, slot, cmd);
                    735:                        if (cmd->status)
                    736:                                printf("pckbc_start: command error\n");
                    737:
                    738:                        TAILQ_REMOVE(&q->cmdqueue, cmd, next);
                    739:                        if (cmd->flags & KBC_CMDFLAG_SYNC)
                    740:                                wakeup(cmd);
                    741:                        else {
                    742:                                timeout_del(&t->t_cleanup);
                    743:                                TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
                    744:                        }
                    745:                        cmd = TAILQ_FIRST(&q->cmdqueue);
                    746:                } while (cmd);
                    747:                return;
                    748:        }
                    749:
                    750:        if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
                    751:                printf("pckbc_start: send error\n");
                    752:                /* XXX what now? */
                    753:                return;
                    754:        }
                    755: }
                    756:
                    757: /*
                    758:  * Handle command responses coming in asynchronously,
                    759:  * return nonzero if valid response.
                    760:  * to be called at spltty()
                    761:  */
                    762: int
                    763: pckbc_cmdresponse(t, slot, data)
                    764:        struct pckbc_internal *t;
                    765:        pckbc_slot_t slot;
                    766:        u_char data;
                    767: {
                    768:        struct pckbc_slotdata *q = t->t_slotdata[slot];
                    769:        struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
                    770: #ifdef DIAGNOSTIC
                    771:        if (!cmd)
                    772:                panic("pckbc_cmdresponse: no active command");
                    773: #endif
                    774:        if (cmd->cmdidx < cmd->cmdlen) {
                    775:                if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
                    776:                        return (0);
                    777:
                    778:                if (data == KBC_DEVCMD_RESEND) {
                    779:                        if (cmd->retries++ < 5) {
                    780:                                /* try again last command */
                    781:                                goto restart;
                    782:                        } else {
                    783: #ifdef PCKBCDEBUG
                    784:                                printf("pckbc: cmd failed\n");
                    785: #endif
                    786:                                cmd->status = EIO;
                    787:                                /* dequeue */
                    788:                        }
                    789:                } else {
                    790:                        if (++cmd->cmdidx < cmd->cmdlen)
                    791:                                goto restart;
                    792:                        if (cmd->responselen)
                    793:                                return (1);
                    794:                        /* else dequeue */
                    795:                }
                    796:        } else if (cmd->responseidx < cmd->responselen) {
                    797:                cmd->response[cmd->responseidx++] = data;
                    798:                if (cmd->responseidx < cmd->responselen)
                    799:                        return (1);
                    800:                /* else dequeue */
                    801:        } else
                    802:                return (0);
                    803:
                    804:        /* dequeue: */
                    805:        TAILQ_REMOVE(&q->cmdqueue, cmd, next);
                    806:        if (cmd->flags & KBC_CMDFLAG_SYNC)
                    807:                wakeup(cmd);
                    808:        else {
                    809:                timeout_del(&t->t_cleanup);
                    810:                TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
                    811:        }
                    812:        if (!CMD_IN_QUEUE(q))
                    813:                return (1);
                    814: restart:
                    815:        pckbc_start(t, slot);
                    816:        return (1);
                    817: }
                    818:
                    819: /*
                    820:  * Put command into the device's command queue, return zero or errno.
                    821:  */
                    822: int
                    823: pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
                    824:        pckbc_tag_t self;
                    825:        pckbc_slot_t slot;
                    826:        u_char *cmd;
                    827:        int len, responselen, sync;
                    828:        u_char *respbuf;
                    829: {
                    830:        struct pckbc_internal *t = self;
                    831:        struct pckbc_slotdata *q = t->t_slotdata[slot];
                    832:        struct pckbc_devcmd *nc;
                    833:        int s, isactive, res = 0;
                    834:
                    835:        if ((len > 4) || (responselen > 4))
                    836:                return (EINVAL);
                    837:        s = spltty();
                    838:        nc = TAILQ_FIRST(&q->freequeue);
                    839:        if (nc) {
                    840:                TAILQ_REMOVE(&q->freequeue, nc, next);
                    841:        }
                    842:        splx(s);
                    843:        if (!nc)
                    844:                return (ENOMEM);
                    845:
                    846:        bzero(nc, sizeof(*nc));
                    847:        bcopy(cmd, nc->cmd, len);
                    848:        nc->cmdlen = len;
                    849:        nc->responselen = responselen;
                    850:        nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
                    851:
                    852:        s = spltty();
                    853:
                    854:        if (q->polling && sync) {
                    855:                /*
                    856:                 * XXX We should poll until the queue is empty.
                    857:                 * But we don't come here normally, so make
                    858:                 * it simple and throw away everything.
                    859:                 */
                    860:                pckbc_cleanqueue(q);
                    861:        }
                    862:
                    863:        isactive = CMD_IN_QUEUE(q);
                    864:        TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
                    865:        if (!isactive)
                    866:                pckbc_start(t, slot);
                    867:
                    868:        if (q->polling)
                    869:                res = (sync ? nc->status : 0);
                    870:        else if (sync) {
                    871:                if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
                    872:                        TAILQ_REMOVE(&q->cmdqueue, nc, next);
                    873:                        pckbc_cleanup(t);
                    874:                } else
                    875:                        res = nc->status;
                    876:        } else
                    877:                timeout_add(&t->t_cleanup, hz);
                    878:
                    879:        if (sync) {
                    880:                if (respbuf)
                    881:                        bcopy(nc->response, respbuf, responselen);
                    882:                TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
                    883:        }
                    884:
                    885:        splx(s);
                    886:
                    887:        return (res);
                    888: }
                    889:
                    890: void
                    891: pckbc_set_inputhandler(self, slot, func, arg, name)
                    892:        pckbc_tag_t self;
                    893:        pckbc_slot_t slot;
                    894:        pckbc_inputfcn func;
                    895:        void *arg;
                    896:        char *name;
                    897: {
                    898:        struct pckbc_internal *t = (struct pckbc_internal *)self;
                    899:        struct pckbc_softc *sc = t->t_sc;
                    900:
                    901:        if (slot >= PCKBC_NSLOTS)
                    902:                panic("pckbc_set_inputhandler: bad slot %d", slot);
                    903:
                    904:        (*sc->intr_establish)(sc, slot);
                    905:
                    906:        sc->inputhandler[slot] = func;
                    907:        sc->inputarg[slot] = arg;
                    908:        sc->subname[slot] = name;
                    909:
                    910:        if (pckbc_console && slot == PCKBC_KBD_SLOT)
                    911:                timeout_add(&t->t_poll, hz);
                    912: }
                    913:
                    914: void
                    915: pckbc_poll(v)
                    916:        void *v;
                    917: {
                    918:        struct pckbc_internal *t = v;
                    919:        int s;
                    920:
                    921:        s = spltty();
                    922:        (void)pckbcintr_internal(t, t->t_sc);
                    923:        timeout_add(&t->t_poll, hz);
                    924:        splx(s);
                    925: }
                    926:
                    927: int
                    928: pckbcintr(vsc)
                    929:        void *vsc;
                    930: {
                    931:        struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
                    932:
                    933:        return (pckbcintr_internal(sc->id, sc));
                    934: }
                    935:
                    936: int
                    937: pckbcintr_internal(t, sc)
                    938:        struct pckbc_internal *t;
                    939:        struct pckbc_softc *sc;
                    940: {
                    941:        u_char stat;
                    942:        pckbc_slot_t slot;
                    943:        struct pckbc_slotdata *q;
                    944:        int served = 0, data;
                    945:
                    946:        /* reschedule timeout further into the idle times */
                    947:        if (timeout_pending(&t->t_poll))
                    948:                timeout_add(&t->t_poll, hz);
                    949:
                    950:        for(;;) {
                    951:                stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
                    952:                if (!(stat & KBS_DIB))
                    953:                        break;
                    954:
                    955:                served = 1;
                    956:
                    957:                slot = (t->t_haveaux && (stat & 0x20)) ?
                    958:                    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
                    959:                q = t->t_slotdata[slot];
                    960:
                    961:                if (!q) {
                    962:                        /* XXX do something for live insertion? */
                    963:                        printf("pckbcintr: no dev for slot %d\n", slot);
                    964:                        KBD_DELAY;
                    965:                        (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    966:                        continue;
                    967:                }
                    968:
                    969:                if (q->polling)
                    970:                        break; /* pckbc_poll_data() will get it */
                    971:
                    972:                KBD_DELAY;
                    973:                data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
                    974:
                    975:                if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
                    976:                        continue;
                    977:
                    978:                if (sc != NULL) {
                    979:                        if (sc->inputhandler[slot])
                    980:                                (*sc->inputhandler[slot])(sc->inputarg[slot],
                    981:                                    data);
                    982: #ifdef PCKBCDEBUG
                    983:                        else
                    984:                                printf("pckbcintr: slot %d lost %d\n",
                    985:                                    slot, data);
                    986: #endif
                    987:                }
                    988:        }
                    989:
                    990:        return (served);
                    991: }
                    992:
                    993: int
                    994: pckbc_cnattach(iot, addr, cmd_offset, slot)
                    995:        bus_space_tag_t iot;
                    996:        bus_addr_t addr;
                    997:        bus_size_t cmd_offset;
                    998:        pckbc_slot_t slot;
                    999: {
                   1000:        bus_space_handle_t ioh_d, ioh_c;
                   1001:        int res = 0;
                   1002:
                   1003:        if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
                   1004:                 return (ENXIO);
                   1005:        if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
                   1006:                bus_space_unmap(iot, ioh_d, 1);
                   1007:                 return (ENXIO);
                   1008:        }
                   1009:
                   1010:        pckbc_consdata.t_iot = iot;
                   1011:        pckbc_consdata.t_ioh_d = ioh_d;
                   1012:        pckbc_consdata.t_ioh_c = ioh_c;
                   1013:        pckbc_consdata.t_addr = addr;
                   1014:        timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata);
                   1015:        timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata);
                   1016:
                   1017:        /* flush */
                   1018:        (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
                   1019:
                   1020:        /* selftest? */
                   1021:
                   1022:        /* init cmd byte, enable ports */
                   1023:        pckbc_consdata.t_cmdbyte = KC8_CPU;
                   1024:        if (!pckbc_put8042cmd(&pckbc_consdata)) {
                   1025:                printf("kbc: cmd word write error\n");
                   1026:                res = EIO;
                   1027:        }
                   1028:
                   1029:        if (!res) {
                   1030: #if (NPCKBD > 0)
                   1031:                res = pckbd_cnattach(&pckbc_consdata, slot);
                   1032: #else
                   1033:                res = ENXIO;
                   1034: #endif /* NPCKBD > 0 */
                   1035:        }
                   1036:
                   1037:        if (res) {
                   1038:                bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
                   1039:                bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
                   1040:        } else {
                   1041:                pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
                   1042:                pckbc_init_slotdata(&pckbc_cons_slotdata);
                   1043:                pckbc_console = 1;
                   1044:        }
                   1045:
                   1046:        return (res);
                   1047: }
                   1048:
                   1049: struct cfdriver pckbc_cd = {
                   1050:        NULL, "pckbc", DV_DULL
                   1051: };

CVSweb