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