The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pcmcia/if_cnw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_cnw.c,v 1.25 2003/11/10 08:55:41 wiz Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Michael Eriksson.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Copyright (c) 1996, 1997 Berkeley Software Design, Inc.
   41  * All rights reserved.
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that this notice is retained,
   45  * the conditions in the following notices are met, and terms applying
   46  * to contributors in the following notices also apply to Berkeley
   47  * Software Design, Inc.
   48  *
   49  * 1. Redistributions of source code must retain the above copyright
   50  *    notice, this list of conditions and the following disclaimer.
   51  * 2. Redistributions in binary form must reproduce the above copyright
   52  *    notice, this list of conditions and the following disclaimer in the
   53  *    documentation and/or other materials provided with the distribution.
   54  * 3. All advertising materials mentioning features or use of this software
   55  *    must display the following acknowledgement:
   56  *      This product includes software developed by
   57  *      Berkeley Software Design, Inc.
   58  * 4. Neither the name of the Berkeley Software Design, Inc. nor the names
   59  *    of its contributors may be used to endorse or promote products derived
   60  *    from this software without specific prior written permission.
   61  *
   62  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
   63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   65  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
   66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   72  * SUCH DAMAGE.
   73  *
   74  * Paul Borman, December 1996
   75  *
   76  * This driver is derived from a generic frame work which is
   77  * Copyright(c) 1994,1995,1996
   78  * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project
   79  * and Foretune.  All rights reserved.
   80  *
   81  * A linux driver was used as the "hardware reference manual" (i.e.,
   82  * to determine registers and a general outline of how the card works)
   83  * That driver is publically available and copyright
   84  *
   85  * John Markus Bjørndalen
   86  * Department of Computer Science
   87  * University of Tromsø
   88  * Norway             
   89  * johnm@staff.cs.uit.no, http://www.cs.uit.no/~johnm/
   90  */
   91 
   92 /*
   93  * This is a driver for the Xircom CreditCard Netwave (also known as
   94  * the Netwave Airsurfer) wireless LAN PCMCIA adapter.
   95  *
   96  * When this driver was developed, the Linux Netwave driver was used
   97  * as a hardware manual. That driver is Copyright (c) 1997 University
   98  * of Tromsø, Norway. It is part of the Linux pcmcia-cs package that
   99  * can be found at http://pcmcia-cs.sourceforge.net/. The most recent
  100  * version of the pcmcia-cs package when this driver was written was
  101  * 3.0.6.
  102  *
  103  * Unfortunately, a lot of explicit numeric constants were used in the
  104  * Linux driver. I have tried to use symbolic names whenever possible,
  105  * but since I don't have any real hardware documentation, there's
  106  * still one or two "magic numbers" :-(.
  107  *
  108  * Driver limitations: This driver doesn't do multicasting or receiver
  109  * promiscuity, because of missing hardware documentation. I couldn't
  110  * get receiver promiscuity to work, and I haven't even tried
  111  * multicast. Volunteers are welcome, of course :-).
  112  */
  113 
  114 #include <sys/cdefs.h>
  115 __KERNEL_RCSID(0, "$NetBSD: if_cnw.c,v 1.25 2003/11/10 08:55:41 wiz Exp $");
  116 
  117 #include "opt_inet.h"
  118 #include "bpfilter.h"
  119 
  120 #include <sys/param.h>
  121 #include <sys/systm.h>
  122 #include <sys/device.h>
  123 #include <sys/socket.h>
  124 #include <sys/mbuf.h>
  125 #include <sys/ioctl.h>
  126 #include <sys/proc.h>
  127 
  128 #include <net/if.h>
  129 
  130 #include <dev/pcmcia/if_cnwreg.h>
  131 #include <dev/pcmcia/if_cnwioctl.h>
  132 
  133 #include <dev/pcmcia/pcmciareg.h>
  134 #include <dev/pcmcia/pcmciavar.h>
  135 #include <dev/pcmcia/pcmciadevs.h>
  136 
  137 #include <net/if_dl.h>
  138 #include <net/if_ether.h>
  139 
  140 #ifdef INET
  141 #include <netinet/in.h>
  142 #include <netinet/in_systm.h>
  143 #include <netinet/in_var.h>
  144 #include <netinet/ip.h>
  145 #include <netinet/if_inarp.h>
  146 #endif
  147 
  148 #if NBPFILTER > 0
  149 #include <net/bpf.h>
  150 #include <net/bpfdesc.h>
  151 #endif
  152 
  153 /*
  154  * Let these be patchable variables, initialized from macros that can
  155  * be set in the kernel config file. Someone with lots of spare time
  156  * could probably write a nice Netwave configuration program to do
  157  * this a little bit more elegantly :-).
  158  */
  159 #ifndef CNW_DOMAIN
  160 #define CNW_DOMAIN      0x100
  161 #endif
  162 int cnw_domain = CNW_DOMAIN;            /* Domain */
  163 #ifndef CNW_SCRAMBLEKEY
  164 #define CNW_SCRAMBLEKEY 0
  165 #endif
  166 int cnw_skey = CNW_SCRAMBLEKEY;         /* Scramble key */
  167 
  168 /*
  169  * The card appears to work much better when we only allow one packet
  170  * "in the air" at a time.  This is done by not allowing another packet
  171  * on the card, even if there is room.  Turning this off will allow the
  172  * driver to stuff packets on the card as soon as a transmit buffer is
  173  * available.  This does increase the number of collisions, though.
  174  * We can que a second packet if there are transmit buffers available,
  175  * but we do not actually send the packet until the last packet has
  176  * been written.
  177  */
  178 #define ONE_AT_A_TIME
  179 
  180 /*
  181  * Netwave cards choke if we try to use io memory address >= 0x400.
  182  * Even though, CIS tuple does not talk about this.
  183  * Use memory mapped access.
  184  */
  185 #define MEMORY_MAPPED
  186 
  187 int     cnw_match __P((struct device *, struct cfdata *, void *));
  188 void    cnw_attach __P((struct device *, struct device *, void *));
  189 int     cnw_detach __P((struct device *, int));
  190 
  191 int     cnw_activate __P((struct device *, enum devact));
  192 
  193 struct cnw_softc {
  194         struct device sc_dev;               /* Device glue (must be first) */
  195         struct ethercom sc_ethercom;        /* Ethernet common part */
  196         int sc_domain;                      /* Netwave domain */
  197         int sc_skey;                        /* Netwave scramble key */
  198         struct cnwstats sc_stats;
  199 
  200         /* PCMCIA-specific stuff */
  201         struct pcmcia_function *sc_pf;      /* PCMCIA function */
  202 #ifndef MEMORY_MAPPED
  203         struct pcmcia_io_handle sc_pcioh;   /* PCMCIA I/O space handle */
  204         int sc_iowin;                       /*   ...window */
  205         bus_space_tag_t sc_iot;             /*   ...bus_space tag */
  206         bus_space_handle_t sc_ioh;          /*   ...bus_space handle */
  207 #endif
  208         struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */
  209         bus_size_t sc_memoff;               /*   ...offset */
  210         int sc_memwin;                      /*   ...window */
  211         bus_space_tag_t sc_memt;            /*   ...bus_space tag */
  212         bus_space_handle_t sc_memh;         /*   ...bus_space handle */
  213         void *sc_ih;                        /* Interrupt cookie */
  214         struct timeval sc_txlast;           /* When the last xmit was made */
  215         int sc_active;                      /* Currently xmitting a packet */
  216 
  217         int sc_resource;                    /* Resources alloc'ed on attach */
  218 #define CNW_RES_PCIC    1
  219 #define CNW_RES_IO      2
  220 #define CNW_RES_MEM     4
  221 #define CNW_RES_NET     8
  222 };
  223 
  224 CFATTACH_DECL(cnw, sizeof(struct cnw_softc),
  225     cnw_match, cnw_attach, cnw_detach, cnw_activate);
  226 
  227 void cnw_reset __P((struct cnw_softc *));
  228 void cnw_init __P((struct cnw_softc *));
  229 int cnw_enable __P((struct cnw_softc *sc));
  230 void cnw_disable __P((struct cnw_softc *sc));
  231 void cnw_config __P((struct cnw_softc *sc, u_int8_t *));
  232 void cnw_start __P((struct ifnet *));
  233 void cnw_transmit __P((struct cnw_softc *, struct mbuf *));
  234 struct mbuf *cnw_read __P((struct cnw_softc *));
  235 void cnw_recv __P((struct cnw_softc *));
  236 int cnw_intr __P((void *arg));
  237 int cnw_ioctl __P((struct ifnet *, u_long, caddr_t));
  238 void cnw_watchdog __P((struct ifnet *));
  239 static int cnw_setdomain __P((struct cnw_softc *, int));
  240 static int cnw_setkey __P((struct cnw_softc *, int));
  241 
  242 /* ---------------------------------------------------------------- */
  243 
  244 /* Help routines */
  245 static int wait_WOC __P((struct cnw_softc *, int));
  246 static int read16 __P((struct cnw_softc *, int));
  247 static int cnw_cmd __P((struct cnw_softc *, int, int, int, int));
  248 
  249 /* 
  250  * Wait until the WOC (Write Operation Complete) bit in the 
  251  * ASR (Adapter Status Register) is asserted. 
  252  */
  253 static int
  254 wait_WOC(sc, line)
  255         struct cnw_softc *sc;
  256         int line;
  257 {
  258         int i, asr;
  259 
  260         for (i = 0; i < 5000; i++) {
  261 #ifndef MEMORY_MAPPED
  262                 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  263 #else
  264                 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  265                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
  266 #endif
  267                 if (asr & CNW_ASR_WOC)
  268                         return (0);
  269                 DELAY(100);
  270         }
  271         if (line > 0)
  272                 printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line);
  273         return (1);
  274 }
  275 #define WAIT_WOC(sc) wait_WOC(sc, __LINE__)
  276 
  277 
  278 /*
  279  * Read a 16 bit value from the card. 
  280  */
  281 static int
  282 read16(sc, offset)
  283         struct cnw_softc *sc;
  284         int offset;
  285 {
  286         int hi, lo;
  287         int offs = sc->sc_memoff + offset;
  288 
  289         /* This could presumably be done more efficient with
  290          * bus_space_read_2(), but I don't know anything about the
  291          * byte sex guarantees... Besides, this is pretty cheap as
  292          * well :-)
  293          */
  294         lo = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs);
  295         hi = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs + 1);
  296         return ((hi << 8) | lo);
  297 }
  298 
  299 
  300 /*
  301  * Send a command to the card by writing it to the command buffer.
  302  */
  303 int
  304 cnw_cmd(sc, cmd, count, arg1, arg2)
  305         struct cnw_softc *sc;
  306         int cmd, count, arg1, arg2;
  307 {
  308         int ptr = sc->sc_memoff + CNW_EREG_CB;
  309 
  310         if (wait_WOC(sc, 0)) {
  311                 printf("%s: wedged when issuing cmd 0x%x\n",
  312                     sc->sc_dev.dv_xname, cmd);
  313                 /*
  314                  * We'll continue anyway, as that's probably the best
  315                  * thing we can do; at least the user knows there's a
  316                  * problem, and can reset the interface with ifconfig
  317                  * down/up.
  318                  */
  319         }
  320 
  321         bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd);
  322         if (count > 0) {
  323                 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1);
  324                 if (count > 1)
  325                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  326                             ptr + 2, arg2);
  327         }
  328         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  329             ptr + count + 1, CNW_CMD_EOC);
  330         return (0);
  331 }
  332 #define CNW_CMD0(sc, cmd) \
  333     do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0)
  334 #define CNW_CMD1(sc, cmd, arg1) \
  335     do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0)
  336 #define CNW_CMD2(sc, cmd, arg1, arg2) \
  337     do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0)
  338 
  339 /* ---------------------------------------------------------------- */
  340 
  341 /*
  342  * Reset the hardware.
  343  */
  344 void
  345 cnw_reset(sc)
  346         struct cnw_softc *sc;
  347 {
  348 #ifdef CNW_DEBUG
  349         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  350                 printf("%s: resetting\n", sc->sc_dev.dv_xname);
  351 #endif
  352         wait_WOC(sc, 0);
  353 #ifndef MEMORY_MAPPED
  354         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET);
  355 #else
  356         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  357             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, CNW_PMR_RESET);
  358 #endif
  359         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  360             sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC);
  361 #ifndef MEMORY_MAPPED
  362         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0);
  363 #else
  364         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  365             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, 0);
  366 #endif
  367 }
  368 
  369 
  370 /*
  371  * Initialize the card.
  372  */
  373 void
  374 cnw_init(sc)
  375         struct cnw_softc *sc;
  376 {
  377         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  378         const u_int8_t rxmode =
  379             CNW_RXCONF_RXENA | CNW_RXCONF_BCAST | CNW_RXCONF_AMP;
  380 
  381         /* Reset the card */
  382         cnw_reset(sc);
  383 
  384         /* Issue a NOP to check the card */
  385         CNW_CMD0(sc, CNW_CMD_NOP);
  386 
  387         /* Set up receive configuration */
  388         CNW_CMD1(sc, CNW_CMD_SRC,
  389             rxmode | ((ifp->if_flags & IFF_PROMISC) ? CNW_RXCONF_PRO : 0));
  390 
  391         /* Set up transmit configuration */
  392         CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA);
  393 
  394         /* Set domain */
  395         CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8);
  396 
  397         /* Set scramble key */
  398         CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8);
  399 
  400         /* Enable interrupts */
  401         WAIT_WOC(sc);
  402 #ifndef MEMORY_MAPPED
  403         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  404             CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1);
  405 #else
  406         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  407             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_IMR,
  408             CNW_IMR_IENA | CNW_IMR_RFU1);
  409 #endif
  410 
  411         /* Enable receiver */
  412         CNW_CMD0(sc, CNW_CMD_ER);
  413 
  414         /* "Set the IENA bit in COR" */
  415         WAIT_WOC(sc);
  416 #ifndef MEMORY_MAPPED
  417         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR,
  418             CNW_COR_IENA | CNW_COR_LVLREQ);
  419 #else
  420         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  421             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_COR,
  422             CNW_COR_IENA | CNW_COR_LVLREQ);
  423 #endif
  424 }
  425 
  426 
  427 /*
  428  * Enable and initialize the card.
  429  */
  430 int
  431 cnw_enable(sc)
  432         struct cnw_softc *sc;
  433 {
  434         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  435 
  436         if ((ifp->if_flags & IFF_RUNNING) != 0)
  437                 return (0);
  438 
  439         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, cnw_intr, sc);
  440         if (sc->sc_ih == NULL) {
  441                 printf("%s: couldn't establish interrupt handler\n",
  442                     sc->sc_dev.dv_xname);
  443                 return (EIO);
  444         }
  445         if (pcmcia_function_enable(sc->sc_pf) != 0) {
  446                 printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
  447                 return (EIO);
  448         }
  449         sc->sc_resource |= CNW_RES_PCIC;
  450         cnw_init(sc);
  451         ifp->if_flags &= ~IFF_OACTIVE;
  452         ifp->if_flags |= IFF_RUNNING;
  453         return (0);
  454 }
  455 
  456 
  457 /*
  458  * Stop and disable the card.
  459  */
  460 void
  461 cnw_disable(sc)
  462         struct cnw_softc *sc;
  463 {
  464         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  465 
  466         if ((ifp->if_flags & IFF_RUNNING) == 0)
  467                 return;
  468 
  469         pcmcia_function_disable(sc->sc_pf);
  470         sc->sc_resource &= ~CNW_RES_PCIC;
  471         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  472         ifp->if_flags &= ~IFF_RUNNING;
  473         ifp->if_timer = 0;
  474 }
  475 
  476 
  477 /*
  478  * Match the hardware we handle.
  479  */
  480 int
  481 cnw_match(parent, match, aux)
  482         struct device *parent;
  483         struct cfdata *match;
  484         void *aux;
  485 {
  486         struct pcmcia_attach_args *pa = aux;
  487 
  488         if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
  489             pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_801)
  490                 return 1;
  491         if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
  492             pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_802)
  493                 return 1;
  494         return 0;
  495 }
  496 
  497 
  498 /*
  499  * Attach the card.
  500  */
  501 void
  502 cnw_attach(parent, self, aux)
  503         struct device  *parent, *self;
  504         void           *aux;
  505 {
  506         struct cnw_softc *sc = (void *) self;
  507         struct pcmcia_attach_args *pa = aux;
  508         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  509         u_int8_t macaddr[ETHER_ADDR_LEN];
  510         int i;
  511         bus_size_t memsize;
  512 
  513         sc->sc_resource = 0;
  514 
  515         /* Enable the card */
  516         sc->sc_pf = pa->pf;
  517         pcmcia_function_init(sc->sc_pf, SIMPLEQ_FIRST(&sc->sc_pf->cfe_head));
  518         if (pcmcia_function_enable(sc->sc_pf)) {
  519                 printf(": function enable failed\n");
  520                 return;
  521         }
  522         sc->sc_resource |= CNW_RES_PCIC;
  523 
  524         /* Map I/O register and "memory" */
  525 #ifndef MEMORY_MAPPED
  526         if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE,
  527             &sc->sc_pcioh) != 0) {
  528                 printf(": can't allocate i/o space\n");
  529                 goto fail;
  530         }
  531         if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, 0,
  532             CNW_IO_SIZE, &sc->sc_pcioh, &sc->sc_iowin) != 0) {
  533                 printf(": can't map i/o space\n");
  534                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
  535                 goto fail;
  536         }
  537         sc->sc_iot = sc->sc_pcioh.iot;
  538         sc->sc_ioh = sc->sc_pcioh.ioh;
  539         sc->sc_resource |= CNW_RES_IO;
  540 #endif
  541 #ifndef MEMORY_MAPPED
  542         memsize = CNW_MEM_SIZE;
  543 #else
  544         memsize = CNW_MEM_SIZE + CNW_IOM_SIZE;
  545 #endif
  546         if (pcmcia_mem_alloc(sc->sc_pf, memsize, &sc->sc_pcmemh) != 0) {
  547                 printf(": can't allocate memory\n");
  548                 goto fail;
  549         }
  550         if (pcmcia_mem_map(sc->sc_pf, PCMCIA_WIDTH_MEM8|PCMCIA_MEM_COMMON,
  551             CNW_MEM_ADDR, memsize, &sc->sc_pcmemh, &sc->sc_memoff,
  552             &sc->sc_memwin) != 0) {
  553                 printf(": can't map memory\n");
  554                 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
  555                 goto fail;
  556         }
  557         sc->sc_memt = sc->sc_pcmemh.memt;
  558         sc->sc_memh = sc->sc_pcmemh.memh;
  559         sc->sc_resource |= CNW_RES_MEM;
  560         switch (pa->product) {
  561         case PCMCIA_PRODUCT_XIRCOM_CNW_801:
  562                 printf(": %s\n", PCMCIA_STR_XIRCOM_CNW_801);
  563                 break;
  564         case PCMCIA_PRODUCT_XIRCOM_CNW_802:
  565                 printf(": %s\n", PCMCIA_STR_XIRCOM_CNW_802);
  566                 break;
  567         }
  568 
  569         /* Finish setup of softc */
  570         sc->sc_domain = cnw_domain;
  571         sc->sc_skey = cnw_skey;
  572 
  573         /* Get MAC address */
  574         cnw_reset(sc);
  575         for (i = 0; i < ETHER_ADDR_LEN; i++)
  576                 macaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  577                     sc->sc_memoff + CNW_EREG_PA + i);
  578         printf("%s: address %s\n", sc->sc_dev.dv_xname,
  579             ether_sprintf(macaddr));
  580 
  581         /* Set up ifnet structure */
  582         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  583         ifp->if_softc = sc;
  584         ifp->if_start = cnw_start;
  585         ifp->if_ioctl = cnw_ioctl;
  586         ifp->if_watchdog = cnw_watchdog;
  587         ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX |
  588             IFF_NOTRAILERS;
  589         IFQ_SET_READY(&ifp->if_snd);
  590 
  591         /* Attach the interface */
  592         if_attach(ifp);
  593         ether_ifattach(ifp, macaddr);
  594 
  595         sc->sc_resource |= CNW_RES_NET;
  596 
  597         ifp->if_baudrate = IF_Mbps(1);
  598 
  599         /* Disable the card now, and turn it on when the interface goes up */
  600         pcmcia_function_disable(sc->sc_pf);
  601         sc->sc_resource &= ~CNW_RES_PCIC;
  602         return;
  603 
  604 fail:
  605 #ifndef MEMORY_MAPPED
  606         if ((sc->sc_resource & CNW_RES_IO) != 0) {
  607                 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
  608                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
  609                 sc->sc_resource &= ~CNW_RES_IO;
  610         }
  611 #endif
  612         if ((sc->sc_resource & CNW_RES_PCIC) != 0) {
  613                 pcmcia_function_disable(sc->sc_pf);
  614                 sc->sc_resource &= ~CNW_RES_PCIC;
  615         }
  616 }
  617 
  618 /*
  619  * Start outputting on the interface.
  620  */
  621 void
  622 cnw_start(ifp)
  623         struct ifnet *ifp;
  624 {
  625         struct cnw_softc *sc = ifp->if_softc;
  626         struct mbuf *m0;
  627         int lif;
  628         int asr;
  629 #ifdef ONE_AT_A_TIME
  630         struct timeval now;
  631 #endif
  632 
  633 #ifdef CNW_DEBUG
  634         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  635                 printf("%s: cnw_start\n", ifp->if_xname);
  636         if (ifp->if_flags & IFF_OACTIVE)
  637                 printf("%s: cnw_start reentered\n", ifp->if_xname);
  638 #endif
  639 
  640         ifp->if_flags |= IFF_OACTIVE;
  641 
  642         for (;;) {
  643 #ifdef ONE_AT_A_TIME
  644                 microtime(&now);
  645                 now.tv_sec -= sc->sc_txlast.tv_sec;
  646                 now.tv_usec -= sc->sc_txlast.tv_usec;
  647                 if (now.tv_usec < 0) {
  648                         now.tv_usec += 1000000;
  649                         now.tv_sec--;
  650                 }
  651 
  652                 /*
  653                  * Don't ship this packet out until the last
  654                  * packet has left the building.
  655                  * If we have not tried to send a packet for 1/5
  656                  * a second then we assume we lost an interrupt,
  657                  * lets go on and send the next packet anyhow.
  658                  *
  659                  * I suppose we could check to see if it is okay
  660                  * to put additional packets on the card (beyond
  661                  * the one already waiting to be sent) but I don't
  662                  * think we would get any improvement in speed as
  663                  * we should have ample time to put the next packet
  664                  * on while this one is going out.
  665                  */
  666                 if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000)
  667                         break;
  668 #endif
  669 
  670                 /* Make sure the link integrity field is on */
  671                 WAIT_WOC(sc);
  672                 lif = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  673                     sc->sc_memoff + CNW_EREG_LIF);
  674                 if (lif == 0) {
  675 #ifdef CNW_DEBUG
  676                         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  677                                 printf("%s: link integrity %d\n", lif);
  678 #endif
  679                         break;
  680                 }
  681 
  682                 /* Is there any buffer space available on the card? */
  683                 WAIT_WOC(sc);
  684 #ifndef MEMORY_MAPPED
  685                 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  686 #else
  687                 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  688                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
  689 #endif
  690                 if (!(asr & CNW_ASR_TXBA)) {
  691 #ifdef CNW_DEBUG
  692                         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  693                                 printf("%s: no buffer space\n", ifp->if_xname);
  694 #endif
  695                         break;
  696                 }
  697 
  698                 sc->sc_stats.nws_tx++;
  699 
  700                 IFQ_DEQUEUE(&ifp->if_snd, m0);
  701                 if (m0 == 0)
  702                         break;
  703 
  704 #if NBPFILTER > 0
  705                 if (ifp->if_bpf)
  706                         bpf_mtap(ifp->if_bpf, m0);
  707 #endif
  708                 
  709                 cnw_transmit(sc, m0);
  710                 ++ifp->if_opackets;
  711                 ifp->if_timer = 3; /* start watchdog timer */
  712 
  713                 microtime(&sc->sc_txlast);
  714                 sc->sc_active = 1;
  715         }
  716 
  717         ifp->if_flags &= ~IFF_OACTIVE;
  718 }
  719 
  720 /*
  721  * Transmit a packet.
  722  */
  723 void
  724 cnw_transmit(sc, m0)
  725         struct cnw_softc *sc;
  726         struct mbuf *m0;
  727 {
  728         int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
  729         struct mbuf *m;
  730         u_int8_t *mptr;
  731 
  732         /* Get buffer info from card */
  733         buffer = read16(sc, CNW_EREG_TDP);
  734         bufsize = read16(sc, CNW_EREG_TDP + 2);
  735         bufoffset = read16(sc, CNW_EREG_TDP + 4);
  736 #ifdef CNW_DEBUG
  737         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  738                 printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
  739                     sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
  740 #endif
  741 
  742         /* Copy data from mbuf chain to card buffers */
  743         bufptr = sc->sc_memoff + buffer + bufoffset;
  744         bufspace = bufsize;
  745         len = 0;
  746         for (m = m0; m; ) {
  747                 mptr = mtod(m, u_int8_t *);
  748                 mbytes = m->m_len;
  749                 len += mbytes;
  750                 while (mbytes > 0) {
  751                         if (bufspace == 0) {
  752                                 buffer = read16(sc, buffer);
  753                                 bufptr = sc->sc_memoff + buffer + bufoffset;
  754                                 bufspace = bufsize;
  755 #ifdef CNW_DEBUG
  756                                 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  757                                         printf("%s:   next buffer @0x%x\n",
  758                                             sc->sc_dev.dv_xname, buffer);
  759 #endif
  760                         }
  761                         n = mbytes <= bufspace ? mbytes : bufspace;
  762                         bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
  763                             bufptr, mptr, n);
  764                         bufptr += n;
  765                         bufspace -= n;
  766                         mptr += n;
  767                         mbytes -= n;
  768                 }
  769                 MFREE(m, m0);
  770                 m = m0;
  771         }
  772 
  773         /* Issue transmit command */
  774         CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
  775 }
  776 
  777 
  778 /*
  779  * Pull a packet from the card into an mbuf chain.
  780  */
  781 struct mbuf *
  782 cnw_read(sc)
  783         struct cnw_softc *sc;
  784 {
  785         struct mbuf *m, *top, **mp;
  786         int totbytes, buffer, bufbytes, bufptr, mbytes, n;
  787         u_int8_t *mptr;
  788 
  789         WAIT_WOC(sc);
  790         totbytes = read16(sc, CNW_EREG_RDP);
  791 #ifdef CNW_DEBUG
  792         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  793                 printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
  794 #endif
  795         buffer = CNW_EREG_RDP + 2;
  796         bufbytes = 0;
  797         bufptr = 0; /* XXX make gcc happy */
  798 
  799         MGETHDR(m, M_DONTWAIT, MT_DATA);
  800         if (m == 0)
  801                 return (0);
  802         m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
  803         m->m_pkthdr.len = totbytes;
  804         mbytes = MHLEN;
  805         top = 0;
  806         mp = &top;
  807 
  808         while (totbytes > 0) {
  809                 if (top) {
  810                         MGET(m, M_DONTWAIT, MT_DATA);
  811                         if (m == 0) {
  812                                 m_freem(top);
  813                                 return (0);
  814                         }
  815                         mbytes = MLEN;
  816                 }
  817                 if (totbytes >= MINCLSIZE) {
  818                         MCLGET(m, M_DONTWAIT);
  819                         if ((m->m_flags & M_EXT) == 0) {
  820                                 m_free(m);
  821                                 m_freem(top);
  822                                 return (0);
  823                         }
  824                         mbytes = MCLBYTES;
  825                 }
  826                 if (!top) {
  827                         int pad = ALIGN(sizeof(struct ether_header)) -
  828                             sizeof(struct ether_header);
  829                         m->m_data += pad;
  830                         mbytes -= pad;
  831                 }
  832                 mptr = mtod(m, u_int8_t *);
  833                 mbytes = m->m_len = min(totbytes, mbytes);
  834                 totbytes -= mbytes;
  835                 while (mbytes > 0) {
  836                         if (bufbytes == 0) {
  837                                 buffer = read16(sc, buffer);
  838                                 bufbytes = read16(sc, buffer + 2);
  839                                 bufptr = sc->sc_memoff + buffer +
  840                                     read16(sc, buffer + 4);
  841 #ifdef CNW_DEBUG
  842                                 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
  843                                         printf("%s:   %d bytes @0x%x+0x%x\n",
  844                                             sc->sc_dev.dv_xname, bufbytes,
  845                                             buffer, bufptr - buffer -
  846                                             sc->sc_memoff);
  847 #endif
  848                         }
  849                         n = mbytes <= bufbytes ? mbytes : bufbytes;
  850                         bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
  851                             bufptr, mptr, n);
  852                         bufbytes -= n;
  853                         bufptr += n;
  854                         mbytes -= n;
  855                         mptr += n;
  856                 }
  857                 *mp = m;
  858                 mp = &m->m_next;
  859         }
  860 
  861         return (top);
  862 }
  863 
  864 
  865 /*
  866  * Handle received packets.
  867  */
  868 void
  869 cnw_recv(sc)
  870         struct cnw_softc *sc;
  871 {
  872         int rser;
  873         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  874         struct mbuf *m;
  875 
  876         for (;;) {
  877                 WAIT_WOC(sc);
  878                 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  879                     sc->sc_memoff + CNW_EREG_RSER);
  880                 if (!(rser & CNW_RSER_RXAVAIL))
  881                         return;
  882 
  883                 /* Pull packet off card */
  884                 m = cnw_read(sc);
  885 
  886                 /* Acknowledge packet */
  887                 CNW_CMD0(sc, CNW_CMD_SRP);
  888 
  889                 /* Did we manage to get the packet from the interface? */
  890                 if (m == 0) {
  891                         ++ifp->if_ierrors;
  892                         return;
  893                 }
  894                 ++ifp->if_ipackets;
  895 
  896 #if NBPFILTER > 0
  897                 if (ifp->if_bpf)
  898                         bpf_mtap(ifp->if_bpf, m);
  899 #endif
  900 
  901                 /* Pass the packet up. */
  902                 (*ifp->if_input)(ifp, m);
  903         }
  904 }
  905 
  906 
  907 /*
  908  * Interrupt handler.
  909  */
  910 int
  911 cnw_intr(arg)
  912         void *arg;
  913 {
  914         struct cnw_softc *sc = arg;
  915         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  916         int ret, status, rser, tser;
  917 
  918         if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0 ||
  919             (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
  920                 return (0);
  921         ifp->if_timer = 0;      /* stop watchdog timer */
  922 
  923         ret = 0;
  924         for (;;) {
  925                 WAIT_WOC(sc);
  926 #ifndef MEMORY_MAPPED
  927                 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
  928                     CNW_REG_CCSR);
  929 #else
  930                 status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  931                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_CCSR);
  932 #endif
  933                 if (!(status & 0x02)) {
  934                         if (ret == 0)
  935                                 printf("%s: spurious interrupt\n",
  936                                     sc->sc_dev.dv_xname);
  937                         return (ret);
  938                 }
  939                 ret = 1;
  940 #ifndef MEMORY_MAPPED
  941                 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
  942 #else
  943                 status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  944                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
  945 #endif
  946 
  947                 /* Anything to receive? */
  948                 if (status & CNW_ASR_RXRDY) {
  949                         sc->sc_stats.nws_rx++;
  950                         cnw_recv(sc);
  951                 }
  952 
  953                 /* Receive error */
  954                 if (status & CNW_ASR_RXERR) {
  955                         /*
  956                          * I get a *lot* of spurious receive errors
  957                          * (many per second), even when the interface
  958                          * is quiescent, so we don't increment
  959                          * if_ierrors here.
  960                          */
  961                         rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  962                             sc->sc_memoff + CNW_EREG_RSER);
  963 
  964                         /* RX statistics */
  965                         sc->sc_stats.nws_rxerr++;
  966                         if (rser & CNW_RSER_RXBIG)
  967                                 sc->sc_stats.nws_rxframe++;
  968                         if (rser & CNW_RSER_RXCRC)
  969                                 sc->sc_stats.nws_rxcrcerror++;
  970                         if (rser & CNW_RSER_RXOVERRUN)
  971                                 sc->sc_stats.nws_rxoverrun++;
  972                         if (rser & CNW_RSER_RXOVERFLOW)
  973                                 sc->sc_stats.nws_rxoverflow++;
  974                         if (rser & CNW_RSER_RXERR)
  975                                 sc->sc_stats.nws_rxerrors++;
  976                         if (rser & CNW_RSER_RXAVAIL)
  977                                 sc->sc_stats.nws_rxavail++;
  978 
  979                         /* Clear error bits in RSER */
  980                         WAIT_WOC(sc);
  981                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  982                             sc->sc_memoff + CNW_EREG_RSERW,
  983                             CNW_RSER_RXERR |
  984                             (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
  985                         /* Clear RXERR in ASR */
  986                         WAIT_WOC(sc);
  987                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
  988                             sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
  989                 }
  990 
  991                 /* Transmit done */
  992                 if (status & CNW_ASR_TXDN) {
  993                         tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
  994                                                 CNW_EREG_TSER);
  995 
  996                         /* TX statistics */
  997                         if (tser & CNW_TSER_TXERR)
  998                                 sc->sc_stats.nws_txerrors++;
  999                         if (tser & CNW_TSER_TXNOAP)
 1000                                 sc->sc_stats.nws_txlostcd++;
 1001                         if (tser & CNW_TSER_TXGU)
 1002                                 sc->sc_stats.nws_txabort++;
 1003 
 1004                         if (tser & CNW_TSER_TXOK) {
 1005                                 sc->sc_stats.nws_txokay++;
 1006                                 sc->sc_stats.nws_txretries[status & 0xf]++;
 1007                                 WAIT_WOC(sc);
 1008                                 bus_space_write_1(sc->sc_memt, sc->sc_memh,
 1009                                     sc->sc_memoff + CNW_EREG_TSERW,
 1010                                     CNW_TSER_TXOK | CNW_TSER_RTRY);
 1011                         }
 1012 
 1013                         if (tser & CNW_TSER_ERROR) {
 1014                                 ++ifp->if_oerrors;
 1015                                 WAIT_WOC(sc);
 1016                                 bus_space_write_1(sc->sc_memt, sc->sc_memh,
 1017                                     sc->sc_memoff + CNW_EREG_TSERW,
 1018                                     (tser & CNW_TSER_ERROR) |
 1019                                     CNW_TSER_RTRY);
 1020                         }
 1021 
 1022                         sc->sc_active = 0;
 1023                         ifp->if_flags &= ~IFF_OACTIVE;
 1024 
 1025                         /* Continue to send packets from the queue */
 1026                         cnw_start(&sc->sc_ethercom.ec_if);
 1027                 }
 1028                                 
 1029         }
 1030 }
 1031 
 1032 
 1033 /*
 1034  * Handle device ioctls.
 1035  */
 1036 int
 1037 cnw_ioctl(ifp, cmd, data)
 1038         struct ifnet *ifp;
 1039         u_long cmd;
 1040         caddr_t data;
 1041 {
 1042         struct cnw_softc *sc = ifp->if_softc;
 1043         struct ifaddr *ifa = (struct ifaddr *)data;
 1044         struct ifreq *ifr = (struct ifreq *)data;
 1045         int s, error = 0;
 1046         struct proc *p = curproc;       /*XXX*/
 1047 
 1048         s = splnet();
 1049 
 1050         switch (cmd) {
 1051 
 1052         case SIOCSIFADDR:
 1053                 if (!(ifp->if_flags & IFF_RUNNING) &&
 1054                     (error = cnw_enable(sc)) != 0)
 1055                         break;
 1056                 ifp->if_flags |= IFF_UP;
 1057                 switch (ifa->ifa_addr->sa_family) {
 1058 #ifdef INET
 1059                 case AF_INET:
 1060                         cnw_init(sc);
 1061                         arp_ifinit(&sc->sc_ethercom.ec_if, ifa);
 1062                         break;
 1063 #endif
 1064                 default:
 1065                         cnw_init(sc);
 1066                         break;
 1067                 }
 1068                 break;
 1069 
 1070         case SIOCSIFFLAGS:
 1071                 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
 1072                         /*
 1073                          * The interface is marked down and it is running, so
 1074                          * stop it.
 1075                          */
 1076                         cnw_disable(sc);
 1077                 } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
 1078                         /*
 1079                          * The interface is marked up and it is stopped, so
 1080                          * start it.
 1081                          */
 1082                         error = cnw_enable(sc);
 1083                 } else {
 1084                         /* IFF_PROMISC may be changed */
 1085                         cnw_init(sc);
 1086                 }
 1087                 break;
 1088 
 1089         case SIOCADDMULTI:
 1090         case SIOCDELMULTI:
 1091                 /* Update our multicast list. */
 1092                 error = (cmd == SIOCADDMULTI) ?
 1093                     ether_addmulti(ifr, &sc->sc_ethercom) :
 1094                     ether_delmulti(ifr, &sc->sc_ethercom);
 1095                 if (error == ENETRESET || error == 0) {
 1096                         cnw_init(sc);
 1097                         error = 0;
 1098                 }
 1099                 break;
 1100 
 1101         case SIOCGCNWDOMAIN:
 1102                 ((struct ifreq *)data)->ifr_domain = sc->sc_domain;
 1103                 break;
 1104 
 1105         case SIOCSCNWDOMAIN:
 1106                 error = suser(p->p_ucred, &p->p_acflag);
 1107                 if (error)
 1108                         break;
 1109                 error = cnw_setdomain(sc, ifr->ifr_domain);
 1110                 break;
 1111 
 1112         case SIOCSCNWKEY:
 1113                 error = suser(p->p_ucred, &p->p_acflag);
 1114                 if (error)
 1115                         break;
 1116                 error = cnw_setkey(sc, ifr->ifr_key);
 1117                 break;
 1118 
 1119         case SIOCGCNWSTATUS:
 1120                 error = suser(p->p_ucred, &p->p_acflag);
 1121                 if (error)
 1122                         break;
 1123                 if ((ifp->if_flags & IFF_RUNNING) == 0)
 1124                         break;
 1125                 bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
 1126                     sc->sc_memoff + CNW_EREG_CB,
 1127                     ((struct cnwstatus *)data)->data,
 1128                     sizeof(((struct cnwstatus *)data)->data));
 1129                 break;
 1130 
 1131         case SIOCGCNWSTATS:
 1132                 memcpy((void *)&(((struct cnwistats *)data)->stats),
 1133                     (void *)&sc->sc_stats, sizeof(struct cnwstats));
 1134                         break;
 1135 
 1136         default:
 1137                 error = EINVAL;
 1138                 break;
 1139         }
 1140 
 1141         splx(s);
 1142         return (error);
 1143 }
 1144 
 1145 
 1146 /*
 1147  * Device timeout/watchdog routine. Entered if the device neglects to
 1148  * generate an interrupt after a transmit has been started on it.
 1149  */
 1150 void
 1151 cnw_watchdog(ifp)
 1152         struct ifnet *ifp;
 1153 {
 1154         struct cnw_softc *sc = ifp->if_softc;
 1155 
 1156         printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
 1157         ++ifp->if_oerrors;
 1158         cnw_init(sc);
 1159 }
 1160 
 1161 int
 1162 cnw_setdomain(sc, domain)
 1163         struct cnw_softc *sc;
 1164         int domain;
 1165 {
 1166         int s;
 1167 
 1168         if (domain & ~0x1ff)
 1169                 return EINVAL;
 1170 
 1171         s = splnet();
 1172         CNW_CMD2(sc, CNW_CMD_SMD, domain, domain >> 8);
 1173         splx(s);
 1174 
 1175         sc->sc_domain = domain;
 1176         return 0;
 1177 }
 1178 
 1179 int
 1180 cnw_setkey(sc, key)
 1181         struct cnw_softc *sc;
 1182         int key;
 1183 {
 1184         int s;
 1185 
 1186         if (key & ~0xffff)
 1187                 return EINVAL;
 1188 
 1189         s = splnet();
 1190         CNW_CMD2(sc, CNW_CMD_SSK, key, key >> 8);
 1191         splx(s);
 1192 
 1193         sc->sc_skey = key;
 1194         return 0;
 1195 }
 1196 
 1197 int
 1198 cnw_activate(self, act)
 1199         struct device *self;
 1200         enum devact act;
 1201 {
 1202         struct cnw_softc *sc = (struct cnw_softc *)self;
 1203         int rv = 0, s;
 1204 
 1205         s = splnet();
 1206         switch (act) {
 1207         case DVACT_ACTIVATE:
 1208                 rv = EOPNOTSUPP;
 1209                 break;
 1210 
 1211         case DVACT_DEACTIVATE:
 1212                 if_deactivate(&sc->sc_ethercom.ec_if);
 1213                 break;
 1214         }
 1215         splx(s);
 1216         return (rv);
 1217 }
 1218 
 1219 int
 1220 cnw_detach(self, flags)
 1221         struct device *self;
 1222         int flags;
 1223 {
 1224         struct cnw_softc *sc = (struct cnw_softc *)self;
 1225         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 1226 
 1227         /* cnw_disable() checks IFF_RUNNING */
 1228         cnw_disable(sc);
 1229 
 1230         if ((sc->sc_resource & CNW_RES_NET) != 0) {
 1231                 ether_ifdetach(ifp);
 1232                 if_detach(ifp);
 1233         }
 1234 
 1235 #ifndef MEMORY_MAPPED
 1236         /* unmap and free our i/o windows */
 1237         if ((sc->sc_resource & CNW_RES_IO) != 0) {
 1238                 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
 1239                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
 1240         }
 1241 #endif
 1242 
 1243         /* unmap and free our memory windows */
 1244         if ((sc->sc_resource & CNW_RES_MEM) != 0) {
 1245                 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
 1246                 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
 1247         }
 1248 
 1249         return (0);
 1250 }

Cache object: a4d333472290a3d349a1948fbf1bd5b9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.