[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     ! 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