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

Annotation of sys/dev/ic/rlnsubr.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: rlnsubr.c,v 1.5 2002/03/14 01:26:55 millert Exp $     */
        !             2: /*
        !             3:  * David Leonard <d@openbsd.org>, 1999. Public Domain.
        !             4:  *
        !             5:  * Low level card protocol access to the Proxim RangeLAN2 wireless
        !             6:  * network adaptor.
        !             7:  *
        !             8:  * Information and ideas gleaned from
        !             9:  *   - disassembly of Dave Koberstein's <davek@komacke.com> Linux driver
        !            10:  *     (which is built with Proxim source),
        !            11:  *   - Yoichi Shinoda's <shinoda@cs.washington.edu> BSDI driver, and
        !            12:  *   - Geoff Voelker's <voelker@cs.washington.edu> Linux port of the same.
        !            13:  */
        !            14:
        !            15: #include <sys/param.h>
        !            16: #include <sys/systm.h>
        !            17: #include <sys/mbuf.h>
        !            18: #include <sys/socket.h>
        !            19: #include <sys/ioctl.h>
        !            20: #include <sys/syslog.h>
        !            21: #include <sys/device.h>
        !            22: #include <sys/queue.h>
        !            23: #include <sys/proc.h>
        !            24: #include <sys/kernel.h>
        !            25:
        !            26: #include <net/if.h>
        !            27:
        !            28: #ifdef INET
        !            29: #include <netinet/in.h>
        !            30: #include <netinet/if_ether.h>
        !            31: #endif
        !            32:
        !            33: #include <machine/bus.h>
        !            34: #include <machine/intr.h>
        !            35:
        !            36: #include <dev/ic/rln.h>
        !            37: #include <dev/ic/rlnvar.h>
        !            38: #include <dev/ic/rlnreg.h>
        !            39: #include <dev/ic/rlncmd.h>
        !            40:
        !            41: static int     rln_tx_request(struct rln_softc *, u_int16_t);
        !            42: static int     rln_tx_end(struct rln_softc *);
        !            43:
        !            44: /*
        !            45:  * Disables or enables interrupts from the card. Returns the old
        !            46:  * interrupt-enable state.
        !            47:  */
        !            48: int
        !            49: rln_enable(sc, enable)
        !            50:        struct rln_softc * sc;
        !            51:        int             enable;
        !            52: {
        !            53:        int             s;
        !            54:        int             was_enabled;
        !            55:
        !            56:        s = splhigh();
        !            57:        was_enabled = (sc->sc_intsel & RLN_INTSEL_ENABLE) ? 1 : 0;
        !            58:        if (enable != was_enabled) {
        !            59:                if (enable)
        !            60:                        sc->sc_intsel |= RLN_INTSEL_ENABLE;
        !            61:                else
        !            62:                        sc->sc_intsel &=~RLN_INTSEL_ENABLE;
        !            63:                _rln_register_write_1(sc, RLN_REG_INTSEL, sc->sc_intsel);
        !            64:        }
        !            65:        splx(s);
        !            66:        return (was_enabled);
        !            67: }
        !            68:
        !            69: /*
        !            70:  * Perform a hard reset of the card.  Determines bus width (8 or
        !            71:  * 16 bit), if sc->sc_width is unset.  Returns 0 on success.
        !            72:  * Note: takes about 200ms at splhigh, meaning this is an expensive call,
        !            73:  * but normal (error-free) operation of the card will not need more than
        !            74:  * two resets - one at probe time, and the other when the interface is
        !            75:  * brought up.
        !            76:  */
        !            77: int
        !            78: rln_reset(sc)
        !            79:        struct rln_softc * sc;
        !            80: {
        !            81:        int             s;
        !            82:        int             i;
        !            83:        int             status;
        !            84:        u_int8_t        op = 0x00;
        !            85:
        !            86:        s = splhigh();
        !            87:        dprintf(" R[");
        !            88:        if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
        !            89:                op = 0x04;
        !            90:        if (rln_status_read(sc) & RLN_STATUS_WAKEUP) {
        !            91:                rln_control_write(sc, op);
        !            92:                rln_control_write(sc, op | RLN_CONTROL_RESET);
        !            93:                dprintf(" 7ms");
        !            94:                DELAY(7000);
        !            95:                rln_control_write(sc, op);
        !            96:                dprintf(" 7ms");
        !            97:                DELAY(7000);
        !            98:        }
        !            99:        rln_control_write(sc, op);
        !           100:        rln_control_write(sc, op);
        !           101:        rln_control_write(sc, op | RLN_CONTROL_BIT3);
        !           102:        dprintf(" 67ms");
        !           103:        DELAY(67000);
        !           104:        rln_status_write(sc, 0x00);
        !           105:        if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
        !           106:                rln_control_write(sc, 0x38);
        !           107:                /* RLN_CONTROL_BIT3 | RLN_CONTROL_RESET | RLN_CONTROL_16BIT */
        !           108:        else
        !           109:                rln_control_write(sc, 0x2c);
        !           110:                /* RLN_CONTROL_BIT3 | RLN_CONTROL_BIT2  | RLN_CONTROL_16BIT */
        !           111:        dprintf(" 67ms");
        !           112:        DELAY(67000);
        !           113:        rln_data_write_2(sc, 0xaa55);
        !           114:        rln_status_write(sc, 0x5a);
        !           115:        splx(s);
        !           116:        for (i = 0; i < 200 * 10; i++) {        /* Proxim says 200. */
        !           117:                if ((status = rln_status_read(sc)) == 0x5a)
        !           118:                        break;
        !           119:                DELAY(1000);
        !           120:        }
        !           121:        dprintf(" (%dms)", i);
        !           122:        s = splhigh();
        !           123:        if (status != 0x5a) {
        !           124:                splx(s);
        !           125:                /* Only winge if bus width not yet probed */
        !           126:                if (sc->sc_width != 0)
        !           127:                        printf("%s: reset timeout\n", sc->sc_dev.dv_xname);
        !           128:                dprintf("]=-1");
        !           129:                return (-1);
        !           130:        }
        !           131:        if (sc->sc_width == 8) {
        !           132:                if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
        !           133:                        rln_control_write(sc, RLN_CONTROL_BIT3);
        !           134:                else
        !           135:                        rln_control_write(sc, RLN_CONTROL_BIT3 |
        !           136:                            RLN_CONTROL_BIT2);
        !           137:                rln_data_write_1(sc, 0x20);
        !           138:        } else if (sc->sc_width == 16) {
        !           139:                rln_data_write_2(sc, 0x0000);
        !           140:        } else {
        !           141:                if (rln_data_read_2(sc) == 0x55aa) {
        !           142:                        rln_data_write_2(sc, 0x0000);
        !           143:                        sc->sc_width = 16;
        !           144:                } else {
        !           145:                        if (sc->sc_cardtype & (RLN_CTYPE_UISA |
        !           146:                            RLN_CTYPE_ONE_PIECE))
        !           147:                                rln_control_write(sc, RLN_CONTROL_BIT3);
        !           148:                        else
        !           149:                                rln_control_write(sc, RLN_CONTROL_BIT3 |
        !           150:                                    RLN_CONTROL_BIT2);
        !           151:                        rln_data_write_1(sc, 0x20);
        !           152:                        sc->sc_width = 8;
        !           153:                }
        !           154:                /* printf("%s: %d bit bus\n", sc->sc_dev.dv_xname,
        !           155:                   sc->sc_width); */
        !           156:        }
        !           157:        rln_status_write(sc, 0x00);
        !           158:        sc->sc_intsel = 0;
        !           159:        rln_intsel_write(sc, sc->sc_irq);
        !           160:        splx(s);
        !           161:        dprintf("]");
        !           162:        return (0);
        !           163: }
        !           164:
        !           165: /*
        !           166:  * Sets the new 'wakeup' state. Returns the old wakeup state.
        !           167:  * The special state value RLN_WAKEUP_SET should be used to wake the
        !           168:  * card up. The card can be partially put to sleep (presumably to save
        !           169:  * power) by sending it the 'Standby' command.
        !           170:  */
        !           171: u_int8_t
        !           172: rln_wakeup(sc, wnew)
        !           173:        struct rln_softc *      sc;
        !           174:        u_int8_t                wnew;
        !           175: {
        !           176:        u_int8_t                wold, s;
        !           177:        int                     i;
        !           178:
        !           179:        /* Save what the last-written values were. */
        !           180:        wold = (sc->sc_status & RLN_STATUS_WAKEUP) |
        !           181:            (sc->sc_control & RLN_CONTROL_RESET);
        !           182:
        !           183:        if (wnew == RLN_WAKEUP_SET) {
        !           184:                /* SetWakeupBit() */
        !           185:                dprintf(" Ws[");
        !           186:                rln_status_set(sc, RLN_STATUS_WAKEUP);
        !           187:                if (0/*LLDInactivityTimeOut &&
        !           188:                    (sc->sc_cardtype & RLN_CTYPE_OEM)*/) {
        !           189:                        dprintf (" 167ms");
        !           190:                        DELAY(167000);
        !           191:                } else {
        !           192:                        dprintf (" .1ms");
        !           193:                        DELAY(100);
        !           194:                }
        !           195:                s = rln_status_read(sc);
        !           196:                rln_control_set(sc, RLN_CONTROL_RESET);
        !           197:                if ((s & RLN_STATUS_WAKEUP) != 0)
        !           198:                        for (i = 0; i < 9; i++) {
        !           199:                                dprintf(" 2ms");
        !           200:                                DELAY(2000);
        !           201:                                rln_status_set(sc, RLN_STATUS_WAKEUP);
        !           202:                        }
        !           203:                dprintf("]");
        !           204:        } else {
        !           205:                /* ClearWakeupBit() */
        !           206:                dprintf(" Wc[");
        !           207:                if ((wnew & RLN_STATUS_WAKEUP) == 0)
        !           208:                        rln_status_clear(sc, RLN_STATUS_WAKEUP);
        !           209:                if ((wnew & RLN_CONTROL_RESET) == 0)
        !           210:                        rln_control_clear(sc, RLN_CONTROL_RESET);
        !           211:                dprintf("]");
        !           212:        }
        !           213:        return (wold);
        !           214: }
        !           215:
        !           216: /*
        !           217:  * Performs the first (request) stage of transmitting a command message
        !           218:  * to the card. 'len' is the expected length of the message is needed.
        !           219:  * Returns: 0 on success
        !           220:  *          1 on timeout
        !           221:  *          2 on NAK (card busy, and will need a rln_clear_nak() after 100ms)
        !           222:  */
        !           223: static int
        !           224: rln_tx_request(sc, len)
        !           225:        struct rln_softc *      sc;
        !           226:        u_int16_t               len;
        !           227: {
        !           228:        /* TxRequest() */
        !           229:        int                     s;
        !           230:        int                     i;
        !           231:        u_int8_t                status;
        !           232:
        !           233:        /* u_int8_t w; */
        !           234:        /* w = rln_wakeup(sc, RLN_WAKEUP_SET); */
        !           235:
        !           236:        dprintf(" Tr[");
        !           237:        if (sc->sc_width == 16) {
        !           238:                rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL);
        !           239:                rln_data_write_2(sc, len);
        !           240:                rln_status_tx_int(sc);
        !           241:
        !           242:                s = spl0();
        !           243:                for (i = 0; i < 600; i++) {
        !           244:                        status = rln_status_tx_read(sc);
        !           245:                        if (status == RLN_STATUS_TX_HILEN_ACCEPT ||
        !           246:                            status == RLN_STATUS_TX_ERROR)
        !           247:                                break;
        !           248:                        DELAY(1000);
        !           249:                }
        !           250:                splx(s);
        !           251:                dprintf(" %dms", i);
        !           252:                if (status == RLN_STATUS_TX_HILEN_ACCEPT)
        !           253:                        goto success;
        !           254:                if (status == RLN_STATUS_TX_ERROR)
        !           255:                        goto error;
        !           256:        } else if (sc->sc_width == 8) {
        !           257:                rln_status_tx_write(sc, RLN_STATUS_TX_LOLEN_AVAIL);
        !           258:                rln_data_write_1(sc, len & 0xff);
        !           259:                rln_status_tx_int(sc);
        !           260:                s = spl0();
        !           261:                for (i = 0; i < 6800; i++) {
        !           262:                        status = rln_status_tx_read(sc);
        !           263:                        if (status == RLN_STATUS_TX_LOLEN_ACCEPT)
        !           264:                                break;
        !           265:                        DELAY(1000);
        !           266:                }
        !           267:                splx(s);
        !           268:                dprintf(" %dms", i);
        !           269:                if (status == RLN_STATUS_TX_LOLEN_ACCEPT) {
        !           270:                        rln_data_write_1(sc, (len >> 8) & 0xff);
        !           271:                        rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL);
        !           272:                        s = spl0();
        !           273:                        for (i = 0; i < 600; i++) {
        !           274:                                status = rln_status_tx_read(sc);
        !           275:                                if (status == RLN_STATUS_TX_HILEN_ACCEPT ||
        !           276:                                    status == RLN_STATUS_TX_ERROR)
        !           277:                                        break;
        !           278:                                DELAY(1000);
        !           279:                        }
        !           280:                        splx(s);
        !           281:                        dprintf(" %dms", i);
        !           282:                        if (status == RLN_STATUS_TX_HILEN_ACCEPT)
        !           283:                                goto success;
        !           284:                        if (status == RLN_STATUS_TX_ERROR)
        !           285:                                goto error;
        !           286:                }
        !           287:        }
        !           288: #ifdef DIAGNOSTIC
        !           289:        else
        !           290:                panic("rln: bus width");
        !           291: #endif
        !           292:
        !           293:        printf("%s: tx_request timed out, status 0x%02x",
        !           294:            sc->sc_dev.dv_xname, status);
        !           295:        dprintf("]=(1)");
        !           296:        return (1);
        !           297:
        !           298: error:
        !           299:        /* Will need to clear nak within 100 ms. */
        !           300:        dprintf("]=2");
        !           301: #ifdef DIAGNOSTIC
        !           302:        printf("%s: tx protocol fault (nak)\n", sc->sc_dev.dv_xname);
        !           303: #endif
        !           304:        return (2);
        !           305:
        !           306: success:
        !           307:        /* rln_wakeup(sc, w); */
        !           308:        dprintf("]=0");
        !           309:        return (0);
        !           310: }
        !           311:
        !           312: /*
        !           313:  * Performs the third (and final) stage of transmitting a command
        !           314:  * message to the card.
        !           315:  * Returns: 0 on command success.
        !           316:  *          non-zero on failure (card will need reset)
        !           317:  */
        !           318: static int
        !           319: rln_tx_end(sc)
        !           320:        struct rln_softc * sc;
        !           321: {
        !           322:        /* EndOfTx() */
        !           323:        int             i;
        !           324:        int             s;
        !           325:        u_int8_t        status;
        !           326:
        !           327:        dprintf(" Te[");
        !           328:        s = spl0();
        !           329:        for (i = 0; i < 600; i++) {
        !           330:                status = rln_status_tx_read(sc);
        !           331:                if (status == RLN_STATUS_TX_XFR_COMPLETE)
        !           332:                        break;
        !           333:                DELAY(1000);
        !           334:        }
        !           335:        splx(s);
        !           336:        if (status == RLN_STATUS_TX_XFR_COMPLETE) {
        !           337:                rln_status_tx_write(sc, RLN_STATUS_TX_IDLE);
        !           338:                dprintf("]=0");
        !           339:                return (0);
        !           340:        } else {
        !           341:                printf("%s: tx cmd failed (%02x)\n", sc->sc_dev.dv_xname,
        !           342:                    status);
        !           343:                rln_need_reset(sc);
        !           344:                dprintf("]=-1");
        !           345:                return (-1);
        !           346:        }
        !           347: }
        !           348:
        !           349: /*
        !           350:  * Performs first (request) stage of receiving a message from the card.
        !           351:  * Returns: 0 on failure,
        !           352:  *          n>0 on success, where 'n' is the length of the message
        !           353:  */
        !           354:
        !           355: int
        !           356: rln_rx_request(sc, timeo)
        !           357:        struct rln_softc *      sc;
        !           358:        int                     timeo;  /* milliseconds */
        !           359: {
        !           360:        /* RxRequest */
        !           361:        int                     s;
        !           362:        int                     len = 0;
        !           363:        int                     i;
        !           364:        u_int8_t                status;
        !           365:        u_int8_t                hi, lo;
        !           366:
        !           367:        dprintf(" Rr[");
        !           368:        status = rln_status_rx_read(sc);
        !           369:
        !           370:        /* Short wait for states 1|5|6. */
        !           371:        s = spl0();
        !           372:        for (i = 0; i < timeo; i++) {
        !           373:                if (status == RLN_STATUS_RX_LOLEN_AVAIL ||
        !           374:                    status == RLN_STATUS_RX_HILEN_AVAIL ||
        !           375:                    status == RLN_STATUS_RX_ERROR)
        !           376:                        break;
        !           377:                DELAY(1000);
        !           378:                status = rln_status_rx_read(sc);
        !           379:        }
        !           380:        splx(s);
        !           381:        dprintf(" (%dms)",i);
        !           382:
        !           383:        if (sc->sc_width == 16) {
        !           384:                if (status != RLN_STATUS_RX_HILEN_AVAIL)
        !           385:                        goto badstatus_quiet;
        !           386:                /* Read 2 octets. */
        !           387:                len = rln_data_read_2(sc);
        !           388:        } else if (sc->sc_width == 8) {
        !           389:                if (status != RLN_STATUS_RX_LOLEN_AVAIL)
        !           390:                        goto badstatus_quiet;
        !           391:                /* Read low octet. */
        !           392:                lo = rln_data_read_1(sc);
        !           393:                rln_status_rx_write(sc, RLN_STATUS_RX_LOLEN_ACCEPT);
        !           394:                rln_status_rx_int(sc);
        !           395:                s = spl0();
        !           396:                for (i = 0; i < 600; i++) {
        !           397:                        status = rln_status_rx_read(sc);
        !           398:                        if (status == RLN_STATUS_RX_HILEN_AVAIL)
        !           399:                                break;
        !           400:                        DELAY(1000);
        !           401:                }
        !           402:                splx(s);
        !           403:                if (status != RLN_STATUS_RX_HILEN_AVAIL)
        !           404:                        goto badstatus;
        !           405:                /* Read high octet. */
        !           406:                hi = rln_data_read_1(sc);
        !           407:                len = lo | (hi << 8);
        !           408:        }
        !           409: #ifdef DIAGNOSTIC
        !           410:        else
        !           411:                panic("rln: bus width %d", sc->sc_width);
        !           412: #endif
        !           413:
        !           414:        dprintf(" len=%d]", len);
        !           415:        return (len);
        !           416:
        !           417: badstatus:
        !           418:        printf("%s: rx_request timed out, status %02x\n",
        !           419:            sc->sc_dev.dv_xname, status);
        !           420: badstatus_quiet:
        !           421:        if (status == RLN_STATUS_RX_ERROR)
        !           422:                printf("%s: rx protocol error (nak)\n", sc->sc_dev.dv_xname);
        !           423:        dprintf("]");
        !           424:        return (-1);
        !           425: }
        !           426:
        !           427: /* Performs part of the second (transfer) stage of receiving a data message. */
        !           428: void
        !           429: rln_rx_pdata(sc, buf, len, pd)
        !           430:        struct rln_softc *      sc;
        !           431:        void *                  buf;
        !           432:        int                     len;
        !           433:        struct rln_pdata *      pd;
        !           434: {
        !           435:        char *                  data = (char *)buf;
        !           436:
        !           437:        if (pd->p_nremain) {
        !           438:                *data++ = pd->p_data;
        !           439:                if (--len == 0)
        !           440:                        return;
        !           441:        }
        !           442:
        !           443:        pd->p_nremain = 0;
        !           444:
        !           445:        if (sc->sc_width == 16) {
        !           446:                /* Round down to the closest even multiple. */
        !           447:                rln_data_read_multi_2(sc, data, len / 2);
        !           448: #ifdef RLNDEBUG_REG
        !           449:                dprintf(" D>");
        !           450:                dprinthex(data, len);
        !           451: #endif
        !           452:                if (len & 1) {
        !           453:                        /* Read the last octet plus a bit extra. */
        !           454:                        union {
        !           455:                                u_int16_t w;
        !           456:                                u_int8_t  b[2];
        !           457:                        } u;
        !           458:
        !           459:                        u.w = rln_data_read_2(sc);
        !           460:                        data[len - 1] = u.b[0];
        !           461:                        pd->p_data = u.b[1];
        !           462:                        pd->p_nremain = 1;
        !           463: #ifdef RLNDEBUG_REG
        !           464:                        dprintf(" D>{%02x%02x}", u.b[0], u.b[1]);
        !           465: #endif
        !           466:                }
        !           467:        } else if (sc->sc_width == 8) {
        !           468:                rln_data_read_multi_1(sc, data, len);
        !           469: #ifdef RLNDEBUG_REG
        !           470:                dprintf(" D>");
        !           471:                dprinthex(data, len);
        !           472: #endif
        !           473:                if (len & 1) {
        !           474:                        /* Must read multiples of two. */
        !           475:                        pd->p_data = rln_data_read_1(sc);
        !           476:                        pd->p_nremain = 1;
        !           477: #ifdef RLNDEBUG_REG
        !           478:                        dprintf(" D>{%02x}", pd->p_data);
        !           479: #endif
        !           480:                }
        !           481:        }
        !           482:
        !           483: }
        !           484:
        !           485: int
        !           486: rln_rx_data(sc, buf, len)
        !           487:        struct rln_softc *      sc;
        !           488:        void *                  buf;
        !           489:        int                     len;
        !           490: {
        !           491:        /* RxData() */
        !           492:        struct rln_pdata        pd = { 0, 0 };
        !           493:        int                     s;
        !           494:        int                     i;
        !           495:        u_int8_t                status;
        !           496:
        !           497:        dprintf(" Rd[");
        !           498:        rln_status_rx_write(sc, RLN_STATUS_RX_HILEN_ACCEPT);
        !           499:        rln_status_rx_int(sc);
        !           500:        s = spl0();
        !           501:        for (i = 0; i < 600; i++) {
        !           502:                status = rln_status_rx_read(sc);
        !           503:                if (status == RLN_STATUS_RX_XFR)
        !           504:                        break;
        !           505:                DELAY(1000);
        !           506:        }
        !           507:        splx(s);
        !           508:        if (status != RLN_STATUS_RX_XFR) {
        !           509:                dprintf("]=-1");
        !           510:                return (-1);
        !           511:        }
        !           512:
        !           513:        rln_rx_pdata(sc, buf, len, &pd);
        !           514: #ifdef DIAGNOSTIC
        !           515:        /* We should have nothing left over. */
        !           516:        if (pd.p_nremain || len & 1)
        !           517:                panic("rln_rx_data: leftover");
        !           518: #endif
        !           519:
        !           520:        dprintf("]=0");
        !           521:        return (0);
        !           522: }
        !           523:
        !           524: void
        !           525: rln_rx_end(sc)
        !           526:        struct rln_softc * sc;
        !           527: {
        !           528:        /* EndOfRx() */
        !           529:
        !           530:        dprintf(" Re[");
        !           531:        rln_status_rx_write(sc, RLN_STATUS_RX_XFR_COMPLETE);
        !           532:        rln_status_rx_int(sc);
        !           533:        /* rln_wakeup(sc, 0); */
        !           534:        dprintf("]");
        !           535: }
        !           536:
        !           537: /* Clear a transmission NAK from the card. */
        !           538: void
        !           539: rln_clear_nak(sc)
        !           540:        struct rln_softc * sc;
        !           541: {
        !           542:        /* ClearNAK() */
        !           543:
        !           544:        rln_status_tx_write(sc, RLN_STATUS_CLRNAK);
        !           545:        rln_status_tx_int(sc);
        !           546: }
        !           547:
        !           548: /*
        !           549:  * Send a command message to the card. Returns;
        !           550:  *     2: NAK
        !           551:  *     -1: failure
        !           552:  *     0: success
        !           553:  */
        !           554: int
        !           555: rln_msg_tx_start(sc, buf, pktlen, state)
        !           556:        struct rln_softc *      sc;
        !           557:        void *                  buf;
        !           558:        int                     pktlen;
        !           559:        struct rln_msg_tx_state * state;
        !           560: {
        !           561:        struct rln_mm_cmd *     cmd = (struct rln_mm_cmd *)buf;
        !           562:        int                     ret;
        !           563:
        !           564:        state->ien = rln_enable(sc, 0);
        !           565:        state->pd.p_nremain = 0;
        !           566:
        !           567:        if (!(cmd->cmd_letter == 'A' && cmd->cmd_fn == 6))      /* Standby. */
        !           568:                state->w = rln_wakeup(sc, RLN_WAKEUP_SET);
        !           569:        else
        !           570:                state->w = RLN_WAKEUP_NOCHANGE;
        !           571:
        !           572:        ret = rln_tx_request(sc, pktlen);
        !           573:        if (ret == 2) {
        !           574:                rln_clear_nak(sc);
        !           575:                if (sc->sc_cardtype & RLN_CTYPE_OEM)
        !           576:                        rln_need_reset(sc);
        !           577:                ret = 2;
        !           578:        }
        !           579:        else if (ret == 1) {
        !           580:                /* Timeout. */
        !           581:                rln_status_tx_write(sc, RLN_STATUS_TX_XFR);
        !           582:                ret = -1;
        !           583:        }
        !           584:        return (ret);
        !           585: }
        !           586:
        !           587: void
        !           588: rln_msg_tx_data(sc, buf, len, state)
        !           589:        struct rln_softc *      sc;
        !           590:        void *                  buf;
        !           591:        u_int16_t               len;
        !           592:        struct rln_msg_tx_state * state;
        !           593: {
        !           594:        char *                  data = (char *)buf;
        !           595:
        !           596:        if (sc->sc_width == 16 && state->pd.p_nremain) {
        !           597:                /* XXX htons() needed? */
        !           598:                union {
        !           599:                        u_int8_t  b[2];
        !           600:                        u_int16_t w;
        !           601:                } u;
        !           602:
        !           603:                u.b[0] = state->pd.p_data;
        !           604:                if (len) {
        !           605:                        u.b[1] = *data++;
        !           606:                        len--;
        !           607:                } else
        !           608:                        u.b[1] = '\0';
        !           609: #ifdef RLNDEBUG_REG
        !           610:                dprintf(" D<%02x%02x", u.b[0], u.b[1]);
        !           611: #endif
        !           612:                rln_data_write_2(sc, u.w);
        !           613:                state->pd.p_nremain = 0;
        !           614:        }
        !           615:
        !           616:        if (len) {
        !           617:                if (sc->sc_width == 16) {
        !           618:                        if (len >= 2)
        !           619:                                rln_data_write_multi_2(sc, buf, len / 2);
        !           620:                        if (len & 1) {
        !           621:                                state->pd.p_nremain = 1;
        !           622:                                state->pd.p_data = data[len - 1];
        !           623:                        }
        !           624:                } else if (sc->sc_width == 8)
        !           625:                        rln_data_write_multi_1(sc, buf, len);
        !           626: #ifdef DIAGNOSTIC
        !           627:                else
        !           628:                        panic("rln_msg_tx_data width %d", sc->sc_width);
        !           629: #endif
        !           630: #ifdef RLNDEBUG_REG
        !           631:                dprintf(" D<");
        !           632:                dprinthex(data, len);
        !           633: #endif
        !           634:        }
        !           635: }
        !           636:
        !           637:
        !           638: int
        !           639: rln_msg_tx_end(sc, state)
        !           640:        struct rln_softc *      sc;
        !           641:        struct rln_msg_tx_state * state;
        !           642: {
        !           643:        int                     ret;
        !           644:
        !           645:        /* Flush the tx buffer. */
        !           646:        if (state->pd.p_nremain)
        !           647:                rln_msg_tx_data(sc, NULL, 0, state);
        !           648:
        !           649: #ifdef DIAGNOSTIC
        !           650:        if (state->pd.p_nremain)
        !           651:                panic("rln_msg_tx_end remain %d", state->pd.p_nremain);
        !           652: #endif
        !           653:        ret = rln_tx_end(sc);
        !           654:        if (sc->sc_arpcom.ac_if.if_flags & IFF_OACTIVE)
        !           655:                state->w = RLN_WAKEUP_NOCHANGE;
        !           656:        rln_wakeup(sc, state->w);
        !           657:        rln_enable(sc, state->ien);
        !           658:        return (ret);
        !           659: }
        !           660:
        !           661: /* Return the next unique sequence number to use for a transmitted command */
        !           662: u_int8_t
        !           663: rln_newseq(sc)
        !           664:        struct rln_softc * sc;
        !           665: {
        !           666:        int s;
        !           667:        u_int8_t seq;
        !           668:
        !           669:        s = splhigh();
        !           670:        seq = sc->sc_pktseq++;
        !           671:        if (sc->sc_pktseq > RLN_MAXSEQ)
        !           672:                sc->sc_pktseq = 0;
        !           673:        splx(s);
        !           674:        return (seq);
        !           675: }
        !           676:
        !           677: /*
        !           678:  * Transmit a command message to, and (optionally) receive a response
        !           679:  * message from the card.  Each transmitted message has a sequence
        !           680:  * number, and corresponding reply messages have the same sequence
        !           681:  * number.  We use the sequence numbers to index the mailboxes so
        !           682:  * that rlnsoftintr() can signal this routine when it has serviced
        !           683:  * and correctly received a response.
        !           684:  */
        !           685:
        !           686: int
        !           687: rln_msg_txrx(sc, tx, txlen, rx, rxlen)
        !           688:        struct rln_softc *      sc;
        !           689:        void *                  tx;
        !           690:        int                     txlen;
        !           691:        void *                  rx;
        !           692:        int                     rxlen;
        !           693: {
        !           694:        struct rln_mm_cmd *     txc = (struct rln_mm_cmd *)tx;
        !           695:        struct rln_mm_cmd *     rxc = (struct rln_mm_cmd *)rx;
        !           696:        struct rln_msg_tx_state state;
        !           697:        int                     ien;
        !           698:        int                     ret;
        !           699:
        !           700: #ifdef DIAGNOSTIC
        !           701:        if (rx != NULL && rxlen < sizeof *rxc)
        !           702:                panic("rln_msg_txrx");
        !           703: #endif
        !           704:
        !           705:        txc->cmd_seq = rln_newseq(sc);
        !           706:
        !           707: #ifdef RLNDUMP
        !           708:        printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname,
        !           709:            txc->cmd_letter, txc->cmd_fn, txc->cmd_seq);
        !           710:        RLNDUMPHEX(txc, sizeof *txc);
        !           711:        printf(":");
        !           712:        RLNDUMPHEX((char *)tx + sizeof *txc, txlen - sizeof *txc);
        !           713:        printf("\n");
        !           714: #endif
        !           715:
        !           716:        if (rx != NULL)
        !           717:                if (rln_mbox_create(sc, txc->cmd_seq, rx, rxlen) < 0)
        !           718:                        /* Mailbox collision. */
        !           719:                        return (-1);
        !           720:
        !           721:        /* Start the transfer. */
        !           722:        if ((ret = rln_msg_tx_start(sc, tx, txlen, &state))) {
        !           723:                if (rx != NULL)
        !           724:                        rln_mbox_wait(sc, txc->cmd_seq, -1);
        !           725:                return (ret);
        !           726:        }
        !           727:
        !           728:        /* Always send an even number of octets. */
        !           729:        rln_msg_tx_data(sc, tx, (txlen + 1) & ~1, &state);
        !           730:
        !           731:        /* End the transmission. */
        !           732:        if ((ret = rln_msg_tx_end(sc, &state))) {
        !           733:                /* Destroy mailbox. */
        !           734:                if (rx != NULL)
        !           735:                        rln_mbox_wait(sc, txc->cmd_seq, -1);
        !           736:                return (ret);
        !           737:        }
        !           738:
        !           739:        /* Don't wait for reply if there is nowhere to put it. */
        !           740:        if (rx == NULL)
        !           741:                return (0);
        !           742:
        !           743:        /* Enable interrupts if not already. */
        !           744:        ien = rln_enable(sc, 1);
        !           745:
        !           746:        /* Wait for the reply message. */
        !           747:        if (rln_mbox_wait(sc, txc->cmd_seq, 4000) <= 0) {
        !           748:                printf("%s: lost message %c%d seq %d\n", sc->sc_dev.dv_xname,
        !           749:                        txc->cmd_letter, txc->cmd_fn, txc->cmd_seq);
        !           750:                rln_enable(sc, ien);
        !           751:                return (-1);
        !           752:        }
        !           753:        rln_enable(sc, ien);
        !           754:
        !           755: #ifdef RLNDUMP
        !           756:        printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
        !           757:            rxc->cmd_letter, rxc->cmd_fn, rxc->cmd_seq);
        !           758:        RLNDUMPHEX(rxc, sizeof *rxc);
        !           759:        printf(":");
        !           760:        RLNDUMPHEX(((char *)rx) + sizeof *rxc, rxlen - sizeof *rxc);
        !           761:        printf("\n");
        !           762: #endif
        !           763:
        !           764:        /* Check for errors in the received message. */
        !           765:        if (rxc->cmd_error & 0x80) {
        !           766:                printf("%s: command error 0x%02x command %c%d\n",
        !           767:                        sc->sc_dev.dv_xname,
        !           768:                        rxc->cmd_error & ~0x80,
        !           769:                        rxc->cmd_letter, rxc->cmd_fn);
        !           770:                return (-1);
        !           771:        }
        !           772:
        !           773:        return (0);
        !           774: }
        !           775:
        !           776: /*
        !           777:  * Mailboxes provide a simple way to tell the interrupt
        !           778:  * service routine that someone is expecting a reply message.
        !           779:  * Mailboxes are identified by the message sequence number
        !           780:  * and also hold a pointer to storage supplied by the waiter.
        !           781:  * The interrupt service routine signals the mailbox when it
        !           782:  * gets the reply message.
        !           783:  */
        !           784:
        !           785: /* Create a mailbox for filling. */
        !           786: int
        !           787: rln_mbox_create(sc, seq, buf, len)
        !           788:        struct rln_softc *      sc;
        !           789:        u_int8_t                seq;
        !           790:        void *                  buf;
        !           791:        size_t                  len;
        !           792: {
        !           793:        int                     s;
        !           794:        struct rln_mbox *       mb = &sc->sc_mbox[seq];
        !           795:
        !           796:        dprintf(" <create %d", seq);
        !           797:
        !           798: #ifdef DIAGNOSTIC
        !           799:        if (seq > RLN_NMBOX)
        !           800:                panic("mbox create");
        !           801: #endif
        !           802:
        !           803:        s = splhigh();
        !           804:        if (mb->mb_state != RLNMBOX_VOID) {
        !           805: #ifdef DIAGNOSTIC
        !           806:                printf("mbox collision");
        !           807: #endif
        !           808:                splx(s);
        !           809:                return (-1);
        !           810:        }
        !           811:        mb->mb_buf = buf;
        !           812:        mb->mb_len = len;
        !           813:        mb->mb_actlen = 0;
        !           814:        mb->mb_state = RLNMBOX_EMPTY;
        !           815:        dprintf(" empty>");
        !           816:        splx(s);
        !           817:        return (0);
        !           818: }
        !           819:
        !           820:
        !           821: /* Wait for a mailbox to be filled. */
        !           822: int
        !           823: rln_mbox_wait(sc, seq, timeo)
        !           824:        struct rln_softc *      sc;
        !           825:        u_int8_t                seq;
        !           826:        int                     timeo;
        !           827: {
        !           828:        int                     i;
        !           829:        int                     s;
        !           830:        int                     ret;
        !           831:        volatile struct rln_mbox * mb = &sc->sc_mbox[seq];
        !           832:
        !           833:        dprintf(" <wait %d", seq);
        !           834:
        !           835: #ifdef DIAGNOSTIC
        !           836:        if (seq > RLN_NMBOX)
        !           837:                panic("mbox wait");
        !           838: #endif
        !           839:
        !           840: #if defined(RLN_TSLEEP)
        !           841:        if (!cold) {
        !           842:                tsleep((void *)mb, PRIBIO, "rlnmbox", hz * timeo / 1000);
        !           843:                if (mb->mb_state == RLNMBOX_FILLING) {
        !           844:                        /* Must wait until filled. */
        !           845:                        s = spl0();
        !           846:                        while (mb->mb_state == RLNMBOX_FILLING)
        !           847:                                ;
        !           848:                        splx(s);
        !           849:                }
        !           850:        } else {
        !           851:                /* Autoconfiguration - spin at spl0. */
        !           852: #endif
        !           853:                s = spl0();
        !           854:                i = 0;
        !           855:                while (mb->mb_state == RLNMBOX_EMPTY && i < timeo) {
        !           856:                        DELAY(1000);
        !           857:                        i++;
        !           858:                }
        !           859:                if (i)
        !           860:                        dprintf(" %dms", i);
        !           861:                while (mb->mb_state == RLNMBOX_FILLING)
        !           862:                        ;
        !           863:                splx(s);
        !           864: #if defined(RLN_TSLEEP)
        !           865:        }
        !           866: #endif
        !           867:
        !           868:        s = splhigh();
        !           869:
        !           870: #ifdef DIAGNOSTIC
        !           871:        if (mb->mb_state != RLNMBOX_EMPTY && mb->mb_state != RLNMBOX_FILLED)
        !           872:                panic("mbox wait %d", mb->mb_state);
        !           873: #endif
        !           874:        ret = mb->mb_actlen;
        !           875:        mb->mb_state = RLNMBOX_VOID;
        !           876:        dprintf(" void>=%d", ret);
        !           877:        splx(s);
        !           878:        return (ret);
        !           879: }
        !           880:
        !           881: /* Lock a mailbox for filling. */
        !           882: int
        !           883: rln_mbox_lock(sc, seq, bufp, lenp)
        !           884:        struct rln_softc *      sc;
        !           885:        u_int8_t                seq;
        !           886:        void **                 bufp;
        !           887:        size_t *                lenp;
        !           888: {
        !           889:        int                     s;
        !           890:        struct rln_mbox *       mb = &sc->sc_mbox[seq];
        !           891:
        !           892:        dprintf(" <lock %d", seq);
        !           893:
        !           894:        s = splhigh();
        !           895: #ifdef DIAGNOSTIC
        !           896:        if (seq > RLN_NMBOX)
        !           897:                panic("mbox lock");
        !           898: #endif
        !           899:        if (mb->mb_state != RLNMBOX_EMPTY) {
        !           900:                splx(s);
        !           901:                dprintf(" ?>");
        !           902:                return (-1);
        !           903:        }
        !           904:
        !           905:        mb->mb_state = RLNMBOX_FILLING;
        !           906:        dprintf(" filling>");
        !           907:        *bufp = mb->mb_buf;
        !           908:        *lenp = mb->mb_len;
        !           909:
        !           910:        splx(s);
        !           911:        return (0);
        !           912: }
        !           913:
        !           914: /* Unlock a mailbox and inform the waiter of the actual number of octets. */
        !           915: void
        !           916: rln_mbox_unlock(sc, seq, actlen)
        !           917:        struct rln_softc *      sc;
        !           918:        u_int8_t                seq;
        !           919:        size_t                  actlen;
        !           920: {
        !           921:        int                     s;
        !           922:        struct rln_mbox *       mb = &sc->sc_mbox[seq];
        !           923:
        !           924:        dprintf(" <unlock %d", seq);
        !           925:
        !           926:        s = splhigh();
        !           927: #ifdef DIAGNOSTIC
        !           928:        if (seq > RLN_NMBOX)
        !           929:                panic("mbox unlock seq");
        !           930:        if (mb->mb_state != RLNMBOX_FILLING)
        !           931:                panic("mbox unlock");
        !           932: #endif
        !           933:        mb->mb_state = RLNMBOX_FILLED;
        !           934:        dprintf(" filled>");
        !           935:        mb->mb_actlen = actlen;
        !           936: #if defined(RLN_TSLEEP)
        !           937:        wakeup(mb);
        !           938: #endif
        !           939:        splx(s);
        !           940: }
        !           941:

CVSweb