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

Annotation of sys/dev/pcmcia/if_cnw.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: if_cnw.c,v 1.16 2006/03/25 22:41:46 djm Exp $ */
                      2: /*-
                      3:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      4:  * All rights reserved.
                      5:  *
                      6:  * This code is derived from software contributed to The NetBSD Foundation
                      7:  * by Michael Eriksson.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed by the NetBSD
                     20:  *     Foundation, Inc. and its contributors.
                     21:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     22:  *    contributors may be used to endorse or promote products derived
                     23:  *    from this software without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     26:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     27:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     28:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     29:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     30:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     31:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     32:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     33:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     34:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     35:  * POSSIBILITY OF SUCH DAMAGE.
                     36:  */
                     37:
                     38: /*
                     39:  * This is a driver for the Xircom CreditCard Netwave (also known as
                     40:  * the Netwave Airsurfer) wireless LAN PCMCIA adapter.
                     41:  *
                     42:  * When this driver was developed, the Linux Netwave driver was used
                     43:  * as a hardware manual. That driver is Copyright (c) 1997 University
                     44:  * of Tromsų, Norway. It is part of the Linux pcmcia-cs package that
                     45:  * can be found at http://pcmcia-cs.sourceforge.net/. The most
                     46:  * recent version of the pcmcia-cs package when this driver was
                     47:  * written was 3.0.6.
                     48:  *
                     49:  * Unfortunately, a lot of explicit numeric constants were used in the
                     50:  * Linux driver. I have tried to use symbolic names whenever possible,
                     51:  * but since I don't have any real hardware documentation, there's
                     52:  * still one or two "magic numbers" :-(.
                     53:  *
                     54:  * Driver limitations: This driver doesn't do multicasting or receiver
                     55:  * promiscuity, because of missing hardware documentation. I couldn't
                     56:  * get receiver promiscuity to work, and I haven't even tried
                     57:  * multicast. Volunteers are welcome, of course :-).
                     58:  */
                     59:
                     60: #include "bpfilter.h"
                     61:
                     62: #include <sys/param.h>
                     63: #include <sys/systm.h>
                     64: #include <sys/device.h>
                     65: #include <sys/socket.h>
                     66: #include <sys/mbuf.h>
                     67: #include <sys/ioctl.h>
                     68:
                     69: #include <dev/pcmcia/if_cnwreg.h>
                     70:
                     71: #include <dev/pcmcia/pcmciareg.h>
                     72: #include <dev/pcmcia/pcmciavar.h>
                     73: #include <dev/pcmcia/pcmciadevs.h>
                     74:
                     75: #include <net/if.h>
                     76: #include <net/if_dl.h>
                     77:
                     78: #ifdef INET
                     79: #include <netinet/in.h>
                     80: #include <netinet/in_systm.h>
                     81: #include <netinet/in_var.h>
                     82: #include <netinet/ip.h>
                     83: #include <netinet/if_ether.h>
                     84: #endif
                     85:
                     86: #if NBPFILTER > 0
                     87: #include <net/bpf.h>
                     88: #endif
                     89:
                     90:
                     91: /*
                     92:  * Let these be patchable variables, initialized from macros that can
                     93:  * be set in the kernel config file. Someone with lots of spare time
                     94:  * could probably write a nice Netwave configuration program to do
                     95:  * this a little bit more elegantly :-).
                     96:  */
                     97: #ifndef CNW_DOMAIN
                     98: #define CNW_DOMAIN     0x100
                     99: #endif
                    100: int cnw_domain = CNW_DOMAIN;           /* Domain */
                    101: #ifndef CNW_SCRAMBLEKEY
                    102: #define CNW_SCRAMBLEKEY 0
                    103: #endif
                    104: int cnw_skey = CNW_SCRAMBLEKEY;                /* Scramble key */
                    105:
                    106:
                    107: int    cnw_match(struct device *, void *, void *);
                    108: void   cnw_attach(struct device *, struct device *, void *);
                    109: int    cnw_detach(struct device *, int);
                    110: int    cnw_activate(struct device *, enum devact);
                    111:
                    112: struct cnw_softc {
                    113:        struct device sc_dev;               /* Device glue (must be first) */
                    114:        struct arpcom sc_arpcom;            /* Ethernet common part */
                    115:        int sc_domain;                      /* Netwave domain */
                    116:        int sc_skey;                        /* Netwave scramble key */
                    117:
                    118:        /* PCMCIA-specific stuff */
                    119:        struct pcmcia_function *sc_pf;      /* PCMCIA function */
                    120:        struct pcmcia_io_handle sc_pcioh;   /* PCMCIA I/O space handle */
                    121:        int sc_iowin;                       /*   ...window */
                    122:        bus_space_tag_t sc_iot;             /*   ...bus_space tag */
                    123:        bus_space_handle_t sc_ioh;          /*   ...bus_space handle */
                    124:        struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */
                    125:        bus_addr_t sc_memoff;               /*   ...offset */
                    126:        int sc_memwin;                      /*   ...window */
                    127:        bus_space_tag_t sc_memt;            /*   ...bus_space tag */
                    128:        bus_space_handle_t sc_memh;         /*   ...bus_space handle */
                    129:        void *sc_ih;                        /* Interrupt cookie */
                    130: };
                    131:
                    132: struct cfattach cnw_ca = {
                    133:        sizeof(struct cnw_softc), cnw_match, cnw_attach,
                    134:        cnw_detach, cnw_activate
                    135: };
                    136:
                    137: struct cfdriver cnw_cd = {
                    138:        NULL, "cnw", DV_IFNET
                    139: };
                    140:
                    141: void cnw_reset(struct cnw_softc *);
                    142: void cnw_init(struct cnw_softc *);
                    143: int cnw_enable(struct cnw_softc *sc);
                    144: void cnw_disable(struct cnw_softc *sc);
                    145: void cnw_config(struct cnw_softc *sc, u_int8_t *);
                    146: void cnw_start(struct ifnet *);
                    147: void cnw_transmit(struct cnw_softc *, struct mbuf *);
                    148: struct mbuf *cnw_read(struct cnw_softc *);
                    149: void cnw_recv(struct cnw_softc *);
                    150: int cnw_intr(void *arg);
                    151: int cnw_ioctl(struct ifnet *, u_long, caddr_t);
                    152: void cnw_watchdog(struct ifnet *);
                    153:
                    154: /* ---------------------------------------------------------------- */
                    155:
                    156: /* Help routines */
                    157: static int wait_WOC(struct cnw_softc *, int);
                    158: static int read16(struct cnw_softc *, int);
                    159: static int cnw_cmd(struct cnw_softc *, int, int, int, int);
                    160:
                    161: /*
                    162:  * Wait until the WOC (Write Operation Complete) bit in the
                    163:  * ASR (Adapter Status Register) is asserted.
                    164:  */
                    165: static int
                    166: wait_WOC(sc, line)
                    167:        struct cnw_softc *sc;
                    168:        int line;
                    169: {
                    170:        int i, asr;
                    171:
                    172:        for (i = 0; i < 5000; i++) {
                    173:                asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
                    174:                if (asr & CNW_ASR_WOC)
                    175:                        return (0);
                    176:                DELAY(100);
                    177:        }
                    178:        if (line > 0)
                    179:                printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line);
                    180:        return (1);
                    181: }
                    182: #define WAIT_WOC(sc) wait_WOC(sc, __LINE__)
                    183:
                    184:
                    185: /*
                    186:  * Read a 16 bit value from the card.
                    187:  */
                    188: static int
                    189: read16(sc, offset)
                    190:        struct cnw_softc *sc;
                    191:        int offset;
                    192: {
                    193:        int hi, lo;
                    194:
                    195:        /* This could presumably be done more efficient with
                    196:         * bus_space_read_2(), but I don't know anything about the
                    197:         * byte sex guarantees... Besides, this is pretty cheap as
                    198:         * well :-)
                    199:         */
                    200:        lo = bus_space_read_1(sc->sc_memt, sc->sc_memh,
                    201:                              sc->sc_memoff + offset);
                    202:        hi = bus_space_read_1(sc->sc_memt, sc->sc_memh,
                    203:                              sc->sc_memoff + offset + 1);
                    204:        return ((hi << 8) | lo);
                    205: }
                    206:
                    207:
                    208: /*
                    209:  * Send a command to the card by writing it to the command buffer.
                    210:  */
                    211: int
                    212: cnw_cmd(sc, cmd, count, arg1, arg2)
                    213:        struct cnw_softc *sc;
                    214:        int cmd, count, arg1, arg2;
                    215: {
                    216:        int ptr = sc->sc_memoff + CNW_EREG_CB;
                    217:
                    218:        if (wait_WOC(sc, 0)) {
                    219:                printf("%s: wedged when issuing cmd 0x%x\n",
                    220:                       sc->sc_dev.dv_xname, cmd);
                    221:                /*
                    222:                 * We'll continue anyway, as that's probably the best
                    223:                 * thing we can do; at least the user knows there's a
                    224:                 * problem, and can reset the interface with ifconfig
                    225:                 * down/up.
                    226:                 */
                    227:        }
                    228:
                    229:        bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd);
                    230:        if (count > 0) {
                    231:                bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1);
                    232:                if (count > 1)
                    233:                        bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    234:                                          ptr + 2, arg2);
                    235:        }
                    236:        bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    237:                          ptr + count + 1, CNW_CMD_EOC);
                    238:        return (0);
                    239: }
                    240: #define CNW_CMD0(sc, cmd) \
                    241:                do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0)
                    242: #define CNW_CMD1(sc, cmd, arg1)        \
                    243:                do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0)
                    244: #define CNW_CMD2(sc, cmd, arg1, arg2) \
                    245:                do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0)
                    246:
                    247: /* ---------------------------------------------------------------- */
                    248:
                    249: /*
                    250:  * Reset the hardware.
                    251:  */
                    252: void
                    253: cnw_reset(sc)
                    254:        struct cnw_softc *sc;
                    255: {
                    256: #ifdef CNW_DEBUG
                    257:        if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    258:                printf("%s: resetting\n", sc->sc_dev.dv_xname);
                    259: #endif
                    260:        wait_WOC(sc, 0);
                    261:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET);
                    262:        bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    263:                          sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC);
                    264:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0);
                    265: }
                    266:
                    267:
                    268: /*
                    269:  * Initialize the card.
                    270:  */
                    271: void
                    272: cnw_init(sc)
                    273:        struct cnw_softc *sc;
                    274: {
                    275:        /* Reset the card */
                    276:        cnw_reset(sc);
                    277:
                    278:        /* Issue a NOP to check the card */
                    279:        CNW_CMD0(sc, CNW_CMD_NOP);
                    280:
                    281:        /* Set up receive configuration */
                    282:        CNW_CMD1(sc, CNW_CMD_SRC, CNW_RXCONF_RXENA | CNW_RXCONF_BCAST);
                    283:
                    284:        /* Set up transmit configuration */
                    285:        CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA);
                    286:
                    287:        /* Set domain */
                    288:        CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8);
                    289:
                    290:        /* Set scramble key */
                    291:        CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8);
                    292:
                    293:        /* Enable interrupts */
                    294:        WAIT_WOC(sc);
                    295:        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    296:                          CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1);
                    297:
                    298:        /* Enable receiver */
                    299:        CNW_CMD0(sc, CNW_CMD_ER);
                    300:
                    301:        /* "Set the IENA bit in COR" */
                    302:        WAIT_WOC(sc);
                    303:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR,
                    304:                          CNW_COR_IENA | CNW_COR_LVLREQ);
                    305: }
                    306:
                    307:
                    308: /*
                    309:  * Enable and initialize the card.
                    310:  */
                    311: int
                    312: cnw_enable(sc)
                    313:        struct cnw_softc *sc;
                    314: {
                    315:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    316:
                    317:        sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
                    318:            cnw_intr, sc, sc->sc_dev.dv_xname);
                    319:        if (sc->sc_ih == NULL) {
                    320:                printf("%s: couldn't establish interrupt handler\n",
                    321:                    sc->sc_dev.dv_xname);
                    322:                return (EIO);
                    323:        }
                    324:        if (pcmcia_function_enable(sc->sc_pf) != 0) {
                    325:                printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
                    326:                return (EIO);
                    327:        }
                    328:        cnw_init(sc);
                    329:        ifp->if_flags |= IFF_RUNNING;
                    330:        return (0);
                    331: }
                    332:
                    333:
                    334: /*
                    335:  * Stop and disable the card.
                    336:  */
                    337: void
                    338: cnw_disable(sc)
                    339:        struct cnw_softc *sc;
                    340: {
                    341:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    342:
                    343:        pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
                    344:        pcmcia_function_disable(sc->sc_pf);
                    345:        ifp->if_flags &= ~IFF_RUNNING;
                    346:        ifp->if_timer = 0;
                    347: }
                    348:
                    349:
                    350: /*
                    351:  * Match the hardware we handle.
                    352:  */
                    353: int
                    354: cnw_match(parent, match, aux)
                    355:        struct device *parent;
                    356:        void *match, *aux;
                    357: {
                    358:        struct pcmcia_attach_args *pa = aux;
                    359:
                    360:        if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
                    361:            pa->product == PCMCIA_PRODUCT_XIRCOM_XIR_CNW_801)
                    362:                return (1);
                    363:        if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
                    364:            pa->product == PCMCIA_PRODUCT_XIRCOM_XIR_CNW_802)
                    365:                return (1);
                    366:        return (0);
                    367: }
                    368:
                    369:
                    370: /*
                    371:  * Attach the card.
                    372:  */
                    373: void
                    374: cnw_attach(parent, self, aux)
                    375:        struct device  *parent, *self;
                    376:        void           *aux;
                    377: {
                    378:        struct cnw_softc *sc = (void *) self;
                    379:        struct pcmcia_attach_args *pa = aux;
                    380:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    381:        int i;
                    382:
                    383:        /* Enable the card */
                    384:        sc->sc_pf = pa->pf;
                    385:        pcmcia_function_init(sc->sc_pf, SIMPLEQ_FIRST(&sc->sc_pf->cfe_head));
                    386:        if (pcmcia_function_enable(sc->sc_pf)) {
                    387:                printf(": function enable failed\n");
                    388:                return;
                    389:        }
                    390:
                    391:        /* Map I/O register and "memory" */
                    392:        if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE,
                    393:                            &sc->sc_pcioh) != 0) {
                    394:                printf(": can't allocate i/o space\n");
                    395:                return;
                    396:        }
                    397:        if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, 0,
                    398:                          CNW_IO_SIZE, &sc->sc_pcioh, &sc->sc_iowin) != 0) {
                    399:                printf(": can't map i/o space\n");
                    400:                return;
                    401:        }
                    402:        sc->sc_iot = sc->sc_pcioh.iot;
                    403:        sc->sc_ioh = sc->sc_pcioh.ioh;
                    404:        if (pcmcia_mem_alloc(sc->sc_pf, CNW_MEM_SIZE, &sc->sc_pcmemh) != 0) {
                    405:                printf(": can't allocate memory\n");
                    406:                return;
                    407:        }
                    408:        if (pcmcia_mem_map(sc->sc_pf, PCMCIA_MEM_COMMON, CNW_MEM_ADDR,
                    409:                           CNW_MEM_SIZE, &sc->sc_pcmemh, &sc->sc_memoff,
                    410:                           &sc->sc_memwin) != 0) {
                    411:                printf(": can't map memory\n");
                    412:                return;
                    413:        }
                    414:        sc->sc_memt = sc->sc_pcmemh.memt;
                    415:        sc->sc_memh = sc->sc_pcmemh.memh;
                    416:
                    417:        /* Finish setup of softc */
                    418:        sc->sc_domain = cnw_domain;
                    419:        sc->sc_skey = cnw_skey;
                    420:
                    421:        /* Get MAC address */
                    422:        cnw_reset(sc);
                    423:        for (i = 0; i < ETHER_ADDR_LEN; i++)
                    424:                sc->sc_arpcom.ac_enaddr[i] = bus_space_read_1(sc->sc_memt,
                    425:                    sc->sc_memh, sc->sc_memoff + CNW_EREG_PA + i);
                    426:        printf("%s: address %s\n", sc->sc_dev.dv_xname,
                    427:               ether_sprintf(sc->sc_arpcom.ac_enaddr));
                    428:
                    429:        /* Set up ifnet structure */
                    430:        bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
                    431:        ifp->if_softc = sc;
                    432:        ifp->if_start = cnw_start;
                    433:        ifp->if_ioctl = cnw_ioctl;
                    434:        ifp->if_watchdog = cnw_watchdog;
                    435:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
                    436:        IFQ_SET_READY(&ifp->if_snd);
                    437:
                    438:        /* Attach the interface */
                    439:        if_attach(ifp);
                    440:        ether_ifattach(ifp);
                    441:
                    442:        /* Disable the card now, and turn it on when the interface goes up */
                    443:        pcmcia_function_disable(sc->sc_pf);
                    444: }
                    445:
                    446: /*
                    447:  * Start outputting on the interface.
                    448:  */
                    449: void
                    450: cnw_start(ifp)
                    451:        struct ifnet *ifp;
                    452: {
                    453:        struct cnw_softc *sc = ifp->if_softc;
                    454:        struct mbuf *m0;
                    455:        int asr;
                    456:
                    457: #ifdef CNW_DEBUG
                    458:        if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    459:                printf("%s: cnw_start\n", ifp->if_xname);
                    460: #endif
                    461:
                    462:        for (;;) {
                    463:                /* Is there any buffer space available on the card? */
                    464:                WAIT_WOC(sc);
                    465:                asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
                    466:                if (!(asr & CNW_ASR_TXBA)) {
                    467: #ifdef CNW_DEBUG
                    468:                        if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    469:                                printf("%s: no buffer space\n", ifp->if_xname);
                    470: #endif
                    471:                        return;
                    472:                }
                    473:
                    474:                IFQ_DEQUEUE(&ifp->if_snd, m0);
                    475:                if (m0 == 0)
                    476:                        return;
                    477:
                    478: #if NBPFILTER > 0
                    479:                if (ifp->if_bpf)
                    480:                        bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
                    481: #endif
                    482:
                    483:                cnw_transmit(sc, m0);
                    484:                ++ifp->if_opackets;
                    485:                ifp->if_timer = 3; /* start watchdog timer */
                    486:        }
                    487: }
                    488:
                    489:
                    490: /*
                    491:  * Transmit a packet.
                    492:  */
                    493: void
                    494: cnw_transmit(sc, m0)
                    495:        struct cnw_softc *sc;
                    496:        struct mbuf *m0;
                    497: {
                    498:        int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
                    499:        struct mbuf *m;
                    500:        u_int8_t *mptr;
                    501:
                    502:        /* Get buffer info from card */
                    503:        buffer = read16(sc, CNW_EREG_TDP);
                    504:        bufsize = read16(sc, CNW_EREG_TDP + 2);
                    505:        bufoffset = read16(sc, CNW_EREG_TDP + 4);
                    506: #ifdef CNW_DEBUG
                    507:        if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    508:                printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
                    509:                       sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
                    510: #endif
                    511:
                    512:        /* Copy data from mbuf chain to card buffers */
                    513:        bufptr = sc->sc_memoff + buffer + bufoffset;
                    514:        bufspace = bufsize;
                    515:        len = 0;
                    516:        for (m = m0; m; ) {
                    517:                mptr = mtod(m, u_int8_t *);
                    518:                mbytes = m->m_len;
                    519:                len += mbytes;
                    520:                while (mbytes > 0) {
                    521:                        if (bufspace == 0) {
                    522:                                buffer = read16(sc, buffer);
                    523:                                bufptr = sc->sc_memoff + buffer + bufoffset;
                    524:                                bufspace = bufsize;
                    525: #ifdef CNW_DEBUG
                    526:                                if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    527:                                        printf("%s:   next buffer @0x%x\n",
                    528:                                               sc->sc_dev.dv_xname, buffer);
                    529: #endif
                    530:                        }
                    531:                        n = mbytes <= bufspace ? mbytes : bufspace;
                    532:                        bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
                    533:                                                 bufptr, mptr, n);
                    534:                        bufptr += n;
                    535:                        bufspace -= n;
                    536:                        mptr += n;
                    537:                        mbytes -= n;
                    538:                }
                    539:                MFREE(m, m0);
                    540:                m = m0;
                    541:        }
                    542:
                    543:        /* Issue transmit command */
                    544:        CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
                    545: }
                    546:
                    547:
                    548: /*
                    549:  * Pull a packet from the card into an mbuf chain.
                    550:  */
                    551: struct mbuf *
                    552: cnw_read(sc)
                    553:        struct cnw_softc *sc;
                    554: {
                    555:        struct mbuf *m, *top, **mp;
                    556:        int totbytes, buffer, bufbytes, bufptr, mbytes, n;
                    557:        u_int8_t *mptr;
                    558:
                    559:        WAIT_WOC(sc);
                    560:        totbytes = read16(sc, CNW_EREG_RDP);
                    561: #ifdef CNW_DEBUG
                    562:        if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    563:                printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
                    564: #endif
                    565:        buffer = CNW_EREG_RDP + 2;
                    566:        bufbytes = 0;
                    567:        bufptr = 0; /* XXX make gcc happy */
                    568:
                    569:        MGETHDR(m, M_DONTWAIT, MT_DATA);
                    570:        if (m == 0)
                    571:                return (0);
                    572:        m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if;
                    573:        m->m_pkthdr.len = totbytes;
                    574:        mbytes = MHLEN;
                    575:        top = 0;
                    576:        mp = &top;
                    577:
                    578:        while (totbytes > 0) {
                    579:                if (top) {
                    580:                        MGET(m, M_DONTWAIT, MT_DATA);
                    581:                        if (m == 0) {
                    582:                                m_freem(top);
                    583:                                return (0);
                    584:                        }
                    585:                        mbytes = MLEN;
                    586:                }
                    587:                if (totbytes >= MINCLSIZE) {
                    588:                        MCLGET(m, M_DONTWAIT);
                    589:                        if ((m->m_flags & M_EXT) == 0) {
                    590:                                m_free(m);
                    591:                                m_freem(top);
                    592:                                return (0);
                    593:                        }
                    594:                        mbytes = MCLBYTES;
                    595:                }
                    596:                if (!top) {
                    597:                        int pad =
                    598:                            ALIGN(sizeof(struct ether_header)) -
                    599:                                sizeof(struct ether_header);
                    600:                        m->m_data += pad;
                    601:                        mbytes -= pad;
                    602:                }
                    603:                mptr = mtod(m, u_int8_t *);
                    604:                mbytes = m->m_len = min(totbytes, mbytes);
                    605:                totbytes -= mbytes;
                    606:                while (mbytes > 0) {
                    607:                        if (bufbytes == 0) {
                    608:                                buffer = read16(sc, buffer);
                    609:                                bufbytes = read16(sc, buffer + 2);
                    610:                                bufptr = sc->sc_memoff + buffer +
                    611:                                        read16(sc, buffer + 4);
                    612: #ifdef CNW_DEBUG
                    613:                                if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
                    614:                                        printf("%s:   %d bytes @0x%x+0x%x\n",
                    615:                                               sc->sc_dev.dv_xname, bufbytes,
                    616:                                               buffer, bufptr - buffer -
                    617:                                               sc->sc_memoff);
                    618: #endif
                    619:                        }
                    620:                        n = mbytes <= bufbytes ? mbytes : bufbytes;
                    621:                        bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
                    622:                                                bufptr, mptr, n);
                    623:                        bufbytes -= n;
                    624:                        bufptr += n;
                    625:                        mbytes -= n;
                    626:                        mptr += n;
                    627:                }
                    628:                *mp = m;
                    629:                mp = &m->m_next;
                    630:        }
                    631:
                    632:        return (top);
                    633: }
                    634:
                    635:
                    636: /*
                    637:  * Handle received packets.
                    638:  */
                    639: void
                    640: cnw_recv(sc)
                    641:        struct cnw_softc *sc;
                    642: {
                    643:        int rser;
                    644:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    645:        struct mbuf *m;
                    646:        struct ether_header *eh;
                    647:
                    648:        for (;;) {
                    649:                WAIT_WOC(sc);
                    650:                rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
                    651:                                        sc->sc_memoff + CNW_EREG_RSER);
                    652:                if (!(rser & CNW_RSER_RXAVAIL))
                    653:                        return;
                    654:
                    655:                /* Pull packet off card */
                    656:                m = cnw_read(sc);
                    657:
                    658:                /* Acknowledge packet */
                    659:                CNW_CMD0(sc, CNW_CMD_SRP);
                    660:
                    661:                /* Did we manage to get the packet from the interface? */
                    662:                if (m == 0) {
                    663:                        ++ifp->if_ierrors;
                    664:                        return;
                    665:                }
                    666:                ++ifp->if_ipackets;
                    667:
                    668: #if NBPFILTER > 0
                    669:                if (ifp->if_bpf)
                    670:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
                    671: #endif
                    672:
                    673:                /*
                    674:                 * Check that the packet is for us or {multi,broad}cast. Maybe
                    675:                 * there's a fool-poof hardware check for this, but I don't
                    676:                 * really know...
                    677:                 */
                    678:                eh = mtod(m, struct ether_header *);
                    679:                if ((eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
                    680:                    bcmp(sc->sc_arpcom.ac_enaddr, eh->ether_dhost,
                    681:                        sizeof(eh->ether_dhost)) != 0) {
                    682:                        m_freem(m);
                    683:                        continue;
                    684:                }
                    685:
                    686:                ether_input_mbuf(ifp, m);
                    687:        }
                    688: }
                    689:
                    690:
                    691: /*
                    692:  * Interrupt handler.
                    693:  */
                    694: int
                    695: cnw_intr(arg)
                    696:        void *arg;
                    697: {
                    698:        struct cnw_softc *sc = arg;
                    699:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    700:        int ret, status, rser, tser;
                    701:
                    702:        if (!(sc->sc_arpcom.ac_if.if_flags & IFF_RUNNING))
                    703:                return (0);
                    704:        ifp->if_timer = 0;      /* stop watchdog timer */
                    705:
                    706:        ret = 0;
                    707:        for (;;) {
                    708:                WAIT_WOC(sc);
                    709:                if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh,
                    710:                                       CNW_REG_CCSR) & 0x02)) {
                    711:                        if (ret == 0)
                    712:                                printf("%s: spurious interrupt\n",
                    713:                                       sc->sc_dev.dv_xname);
                    714:                        return (ret);
                    715:                }
                    716:                ret = 1;
                    717:                status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
                    718:
                    719:                /* Anything to receive? */
                    720:                if (status & CNW_ASR_RXRDY)
                    721:                        cnw_recv(sc);
                    722:
                    723:                /* Receive error */
                    724:                if (status & CNW_ASR_RXERR) {
                    725:                        /*
                    726:                         * I get a *lot* of spurious receive errors
                    727:                         * (many per second), even when the interface
                    728:                         * is quiescent, so we don't increment
                    729:                         * if_ierrors here.
                    730:                         */
                    731:                        rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
                    732:                                                sc->sc_memoff + CNW_EREG_RSER);
                    733:                        /* Clear error bits in RSER */
                    734:                        WAIT_WOC(sc);
                    735:                        bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    736:                                sc->sc_memoff + CNW_EREG_RSERW,
                    737:                                CNW_RSER_RXERR |
                    738:                                (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
                    739:                        /* Clear RXERR in ASR */
                    740:                        WAIT_WOC(sc);
                    741:                        bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    742:                                sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
                    743:                }
                    744:
                    745:                /* Transmit done */
                    746:                if (status & CNW_ASR_TXDN) {
                    747:                        tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
                    748:                                                CNW_EREG_TSER);
                    749:                        if (tser & CNW_TSER_TXOK) {
                    750:                                WAIT_WOC(sc);
                    751:                                bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    752:                                        sc->sc_memoff + CNW_EREG_TSERW,
                    753:                                        CNW_TSER_TXOK | CNW_TSER_RTRY);
                    754:                        }
                    755:                        if (tser & CNW_TSER_ERROR) {
                    756:                                ++ifp->if_oerrors;
                    757:                                WAIT_WOC(sc);
                    758:                                bus_space_write_1(sc->sc_memt, sc->sc_memh,
                    759:                                        sc->sc_memoff + CNW_EREG_TSERW,
                    760:                                        (tser & CNW_TSER_ERROR) |
                    761:                                        CNW_TSER_RTRY);
                    762:                        }
                    763:                        /* Continue to send packets from the queue */
                    764:                        cnw_start(&sc->sc_arpcom.ac_if);
                    765:                }
                    766:
                    767:        }
                    768: }
                    769:
                    770:
                    771: /*
                    772:  * Handle device ioctls.
                    773:  */
                    774: int
                    775: cnw_ioctl(ifp, cmd, data)
                    776:        register struct ifnet *ifp;
                    777:        u_long cmd;
                    778:        caddr_t data;
                    779: {
                    780:        struct cnw_softc *sc = ifp->if_softc;
                    781:        struct ifaddr *ifa = (struct ifaddr *)data;
                    782:        int s, error = 0;
                    783:
                    784:        s = splnet();
                    785:
                    786:        switch (cmd) {
                    787:
                    788:        case SIOCSIFADDR:
                    789:                if (!(ifp->if_flags & IFF_RUNNING) &&
                    790:                    (error = cnw_enable(sc)) != 0)
                    791:                        break;
                    792:                ifp->if_flags |= IFF_UP;
                    793:                switch (ifa->ifa_addr->sa_family) {
                    794: #ifdef INET
                    795:                case AF_INET:
                    796:                        arp_ifinit(&sc->sc_arpcom, ifa);
                    797:                        break;
                    798: #endif
                    799:                }
                    800:                break;
                    801:
                    802:        case SIOCSIFFLAGS:
                    803:                if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
                    804:                        /*
                    805:                         * The interface is marked down and it is running, so
                    806:                         * stop it.
                    807:                         */
                    808:                        cnw_disable(sc);
                    809:                } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
                    810:                        /*
                    811:                         * The interface is marked up and it is stopped, so
                    812:                         * start it.
                    813:                         */
                    814:                        error = cnw_enable(sc);
                    815:                }
                    816:                break;
                    817:
                    818:        default:
                    819:                error = EINVAL;
                    820:                break;
                    821:        }
                    822:
                    823:        splx(s);
                    824:        return (error);
                    825: }
                    826:
                    827:
                    828: /*
                    829:  * Device timeout/watchdog routine. Entered if the device neglects to
                    830:  * generate an interrupt after a transmit has been started on it.
                    831:  */
                    832: void
                    833: cnw_watchdog(ifp)
                    834:        struct ifnet *ifp;
                    835: {
                    836:        struct cnw_softc *sc = ifp->if_softc;
                    837:
                    838:        printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
                    839:        ++ifp->if_oerrors;
                    840:        cnw_init(sc);
                    841: }
                    842:
                    843:
                    844: int
                    845: cnw_detach(dev, flags)
                    846:        struct device *dev;
                    847:        int flags;
                    848: {
                    849:        struct cnw_softc *sc = (struct cnw_softc *)dev;
                    850:        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    851:        int rv = 0;
                    852:
                    853:        pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
                    854:        pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
                    855:        pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
                    856:        pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
                    857:
                    858:        ether_ifdetach(ifp);
                    859:        if_detach(ifp);
                    860:
                    861:        return (rv);
                    862: }
                    863:
                    864: int
                    865: cnw_activate(dev, act)
                    866:        struct device *dev;
                    867:        enum devact act;
                    868: {
                    869:        struct cnw_softc *sc = (struct cnw_softc *)dev;
                    870:         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
                    871:        int s;
                    872:
                    873:        s = splnet();
                    874:        switch (act) {
                    875:        case DVACT_ACTIVATE:
                    876:                pcmcia_function_enable(sc->sc_pf);
                    877:                sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
                    878:                    cnw_intr, sc, sc->sc_dev.dv_xname);
                    879:                cnw_init(sc);
                    880:                break;
                    881:
                    882:        case DVACT_DEACTIVATE:
                    883:                ifp->if_timer = 0;
                    884:                ifp->if_flags &= ~IFF_RUNNING; /* XXX no cnw_stop() ? */
                    885:                pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
                    886:                pcmcia_function_disable(sc->sc_pf);
                    887:                break;
                    888:        }
                    889:        splx(s);
                    890:        return (0);
                    891: }

CVSweb