root/dev/pcmcia/if_cnw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wait_WOC
  2. read16
  3. cnw_cmd
  4. cnw_reset
  5. cnw_init
  6. cnw_enable
  7. cnw_disable
  8. cnw_match
  9. cnw_attach
  10. cnw_start
  11. cnw_transmit
  12. cnw_read
  13. cnw_recv
  14. cnw_intr
  15. cnw_ioctl
  16. cnw_watchdog
  17. cnw_detach
  18. cnw_activate

    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 }

/* [<][>][^][v][top][bottom][index][help] */