xref: /netbsd-src/sys/dev/pcmcia/if_cnw.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: if_cnw.c,v 1.32 2005/12/11 12:23:23 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 2004 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.32 2005/12/11 12:23:23 christos 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(struct device *, struct cfdata *, void *);
188 void	cnw_attach(struct device *, struct device *, void *);
189 int	cnw_detach(struct device *, int);
190 
191 int	cnw_activate(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(struct cnw_softc *);
228 void cnw_init(struct cnw_softc *);
229 int cnw_enable(struct cnw_softc *sc);
230 void cnw_disable(struct cnw_softc *sc);
231 void cnw_config(struct cnw_softc *sc, u_int8_t *);
232 void cnw_start(struct ifnet *);
233 void cnw_transmit(struct cnw_softc *, struct mbuf *);
234 struct mbuf *cnw_read(struct cnw_softc *);
235 void cnw_recv(struct cnw_softc *);
236 int cnw_intr(void *arg);
237 int cnw_ioctl(struct ifnet *, u_long, caddr_t);
238 void cnw_watchdog(struct ifnet *);
239 static int cnw_setdomain(struct cnw_softc *, int);
240 static int cnw_setkey(struct cnw_softc *, int);
241 
242 /* ---------------------------------------------------------------- */
243 
244 /* Help routines */
245 static int wait_WOC(struct cnw_softc *, int);
246 static int read16(struct cnw_softc *, int);
247 static int cnw_cmd(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("%s: function enable failed\n", self->dv_xname);
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("%s: can't allocate i/o space\n", self->dv_xname);
529 		goto fail;
530 	}
531 	if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, &sc->sc_pcioh,
532 	    &sc->sc_iowin) != 0) {
533 		printf("%s: can't map i/o space\n", self->dv_xname);
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("%s: can't allocate memory\n", self->dv_xname);
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("%s: can't map memory\n", self->dv_xname);
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 
561 	/* Finish setup of softc */
562 	sc->sc_domain = cnw_domain;
563 	sc->sc_skey = cnw_skey;
564 
565 	/* Get MAC address */
566 	cnw_reset(sc);
567 	for (i = 0; i < ETHER_ADDR_LEN; i++)
568 		macaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh,
569 		    sc->sc_memoff + CNW_EREG_PA + i);
570 	printf("%s: address %s\n", sc->sc_dev.dv_xname,
571 	    ether_sprintf(macaddr));
572 
573 	/* Set up ifnet structure */
574 	strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
575 	ifp->if_softc = sc;
576 	ifp->if_start = cnw_start;
577 	ifp->if_ioctl = cnw_ioctl;
578 	ifp->if_watchdog = cnw_watchdog;
579 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX |
580 	    IFF_NOTRAILERS;
581 	IFQ_SET_READY(&ifp->if_snd);
582 
583 	/* Attach the interface */
584 	if_attach(ifp);
585 	ether_ifattach(ifp, macaddr);
586 
587 	sc->sc_resource |= CNW_RES_NET;
588 
589 	ifp->if_baudrate = IF_Mbps(1);
590 
591 	/* Disable the card now, and turn it on when the interface goes up */
592 	pcmcia_function_disable(sc->sc_pf);
593 	sc->sc_resource &= ~CNW_RES_PCIC;
594 	return;
595 
596 fail:
597 #ifndef MEMORY_MAPPED
598 	if ((sc->sc_resource & CNW_RES_IO) != 0) {
599 		pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
600 		pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
601 		sc->sc_resource &= ~CNW_RES_IO;
602 	}
603 #endif
604 	if ((sc->sc_resource & CNW_RES_PCIC) != 0) {
605 		pcmcia_function_disable(sc->sc_pf);
606 		sc->sc_resource &= ~CNW_RES_PCIC;
607 	}
608 }
609 
610 /*
611  * Start outputting on the interface.
612  */
613 void
614 cnw_start(ifp)
615 	struct ifnet *ifp;
616 {
617 	struct cnw_softc *sc = ifp->if_softc;
618 	struct mbuf *m0;
619 	int lif;
620 	int asr;
621 #ifdef ONE_AT_A_TIME
622 	struct timeval now;
623 #endif
624 
625 #ifdef CNW_DEBUG
626 	if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
627 		printf("%s: cnw_start\n", ifp->if_xname);
628 	if (ifp->if_flags & IFF_OACTIVE)
629 		printf("%s: cnw_start reentered\n", ifp->if_xname);
630 #endif
631 
632 	ifp->if_flags |= IFF_OACTIVE;
633 
634 	for (;;) {
635 #ifdef ONE_AT_A_TIME
636 		microtime(&now);
637 		now.tv_sec -= sc->sc_txlast.tv_sec;
638 		now.tv_usec -= sc->sc_txlast.tv_usec;
639 		if (now.tv_usec < 0) {
640 			now.tv_usec += 1000000;
641 			now.tv_sec--;
642 		}
643 
644 		/*
645 		 * Don't ship this packet out until the last
646 		 * packet has left the building.
647 		 * If we have not tried to send a packet for 1/5
648 		 * a second then we assume we lost an interrupt,
649 		 * lets go on and send the next packet anyhow.
650 		 *
651 		 * I suppose we could check to see if it is okay
652 		 * to put additional packets on the card (beyond
653 		 * the one already waiting to be sent) but I don't
654 		 * think we would get any improvement in speed as
655 		 * we should have ample time to put the next packet
656 		 * on while this one is going out.
657 		 */
658 		if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000)
659 			break;
660 #endif
661 
662 		/* Make sure the link integrity field is on */
663 		WAIT_WOC(sc);
664 		lif = bus_space_read_1(sc->sc_memt, sc->sc_memh,
665 		    sc->sc_memoff + CNW_EREG_LIF);
666 		if (lif == 0) {
667 #ifdef CNW_DEBUG
668 			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
669 				printf("%s: link integrity %d\n", lif);
670 #endif
671 			break;
672 		}
673 
674 		/* Is there any buffer space available on the card? */
675 		WAIT_WOC(sc);
676 #ifndef MEMORY_MAPPED
677 		asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
678 #else
679 		asr = bus_space_read_1(sc->sc_memt, sc->sc_memh,
680 		    sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
681 #endif
682 		if (!(asr & CNW_ASR_TXBA)) {
683 #ifdef CNW_DEBUG
684 			if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
685 				printf("%s: no buffer space\n", ifp->if_xname);
686 #endif
687 			break;
688 		}
689 
690 		sc->sc_stats.nws_tx++;
691 
692 		IFQ_DEQUEUE(&ifp->if_snd, m0);
693 		if (m0 == 0)
694 			break;
695 
696 #if NBPFILTER > 0
697 		if (ifp->if_bpf)
698 			bpf_mtap(ifp->if_bpf, m0);
699 #endif
700 
701 		cnw_transmit(sc, m0);
702 		++ifp->if_opackets;
703 		ifp->if_timer = 3; /* start watchdog timer */
704 
705 		microtime(&sc->sc_txlast);
706 		sc->sc_active = 1;
707 	}
708 
709 	ifp->if_flags &= ~IFF_OACTIVE;
710 }
711 
712 /*
713  * Transmit a packet.
714  */
715 void
716 cnw_transmit(sc, m0)
717 	struct cnw_softc *sc;
718 	struct mbuf *m0;
719 {
720 	int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
721 	struct mbuf *m;
722 	u_int8_t *mptr;
723 
724 	/* Get buffer info from card */
725 	buffer = read16(sc, CNW_EREG_TDP);
726 	bufsize = read16(sc, CNW_EREG_TDP + 2);
727 	bufoffset = read16(sc, CNW_EREG_TDP + 4);
728 #ifdef CNW_DEBUG
729 	if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
730 		printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
731 		    sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
732 #endif
733 
734 	/* Copy data from mbuf chain to card buffers */
735 	bufptr = sc->sc_memoff + buffer + bufoffset;
736 	bufspace = bufsize;
737 	len = 0;
738 	for (m = m0; m; ) {
739 		mptr = mtod(m, u_int8_t *);
740 		mbytes = m->m_len;
741 		len += mbytes;
742 		while (mbytes > 0) {
743 			if (bufspace == 0) {
744 				buffer = read16(sc, buffer);
745 				bufptr = sc->sc_memoff + buffer + bufoffset;
746 				bufspace = bufsize;
747 #ifdef CNW_DEBUG
748 				if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
749 					printf("%s:   next buffer @0x%x\n",
750 					    sc->sc_dev.dv_xname, buffer);
751 #endif
752 			}
753 			n = mbytes <= bufspace ? mbytes : bufspace;
754 			bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
755 			    bufptr, mptr, n);
756 			bufptr += n;
757 			bufspace -= n;
758 			mptr += n;
759 			mbytes -= n;
760 		}
761 		MFREE(m, m0);
762 		m = m0;
763 	}
764 
765 	/* Issue transmit command */
766 	CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
767 }
768 
769 
770 /*
771  * Pull a packet from the card into an mbuf chain.
772  */
773 struct mbuf *
774 cnw_read(sc)
775 	struct cnw_softc *sc;
776 {
777 	struct mbuf *m, *top, **mp;
778 	int totbytes, buffer, bufbytes, bufptr, mbytes, n;
779 	u_int8_t *mptr;
780 
781 	WAIT_WOC(sc);
782 	totbytes = read16(sc, CNW_EREG_RDP);
783 #ifdef CNW_DEBUG
784 	if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
785 		printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
786 #endif
787 	buffer = CNW_EREG_RDP + 2;
788 	bufbytes = 0;
789 	bufptr = 0; /* XXX make gcc happy */
790 
791 	MGETHDR(m, M_DONTWAIT, MT_DATA);
792 	if (m == 0)
793 		return (0);
794 	m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
795 	m->m_pkthdr.len = totbytes;
796 	mbytes = MHLEN;
797 	top = 0;
798 	mp = &top;
799 
800 	while (totbytes > 0) {
801 		if (top) {
802 			MGET(m, M_DONTWAIT, MT_DATA);
803 			if (m == 0) {
804 				m_freem(top);
805 				return (0);
806 			}
807 			mbytes = MLEN;
808 		}
809 		if (totbytes >= MINCLSIZE) {
810 			MCLGET(m, M_DONTWAIT);
811 			if ((m->m_flags & M_EXT) == 0) {
812 				m_free(m);
813 				m_freem(top);
814 				return (0);
815 			}
816 			mbytes = MCLBYTES;
817 		}
818 		if (!top) {
819 			int pad = ALIGN(sizeof(struct ether_header)) -
820 			    sizeof(struct ether_header);
821 			m->m_data += pad;
822 			mbytes -= pad;
823 		}
824 		mptr = mtod(m, u_int8_t *);
825 		mbytes = m->m_len = min(totbytes, mbytes);
826 		totbytes -= mbytes;
827 		while (mbytes > 0) {
828 			if (bufbytes == 0) {
829 				buffer = read16(sc, buffer);
830 				bufbytes = read16(sc, buffer + 2);
831 				bufptr = sc->sc_memoff + buffer +
832 				    read16(sc, buffer + 4);
833 #ifdef CNW_DEBUG
834 				if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
835 					printf("%s:   %d bytes @0x%x+0x%x\n",
836 					    sc->sc_dev.dv_xname, bufbytes,
837 					    buffer, bufptr - buffer -
838 					    sc->sc_memoff);
839 #endif
840 			}
841 			n = mbytes <= bufbytes ? mbytes : bufbytes;
842 			bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
843 			    bufptr, mptr, n);
844 			bufbytes -= n;
845 			bufptr += n;
846 			mbytes -= n;
847 			mptr += n;
848 		}
849 		*mp = m;
850 		mp = &m->m_next;
851 	}
852 
853 	return (top);
854 }
855 
856 
857 /*
858  * Handle received packets.
859  */
860 void
861 cnw_recv(sc)
862 	struct cnw_softc *sc;
863 {
864 	int rser;
865 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
866 	struct mbuf *m;
867 
868 	for (;;) {
869 		WAIT_WOC(sc);
870 		rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
871 		    sc->sc_memoff + CNW_EREG_RSER);
872 		if (!(rser & CNW_RSER_RXAVAIL))
873 			return;
874 
875 		/* Pull packet off card */
876 		m = cnw_read(sc);
877 
878 		/* Acknowledge packet */
879 		CNW_CMD0(sc, CNW_CMD_SRP);
880 
881 		/* Did we manage to get the packet from the interface? */
882 		if (m == 0) {
883 			++ifp->if_ierrors;
884 			return;
885 		}
886 		++ifp->if_ipackets;
887 
888 #if NBPFILTER > 0
889 		if (ifp->if_bpf)
890 			bpf_mtap(ifp->if_bpf, m);
891 #endif
892 
893 		/* Pass the packet up. */
894 		(*ifp->if_input)(ifp, m);
895 	}
896 }
897 
898 
899 /*
900  * Interrupt handler.
901  */
902 int
903 cnw_intr(arg)
904 	void *arg;
905 {
906 	struct cnw_softc *sc = arg;
907 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
908 	int ret, status, rser, tser;
909 
910 	if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0 ||
911 	    (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
912 		return (0);
913 	ifp->if_timer = 0;	/* stop watchdog timer */
914 
915 	ret = 0;
916 	for (;;) {
917 		WAIT_WOC(sc);
918 #ifndef MEMORY_MAPPED
919 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
920 		    CNW_REG_CCSR);
921 #else
922 		status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
923 		    sc->sc_memoff + CNW_IOM_OFF + CNW_REG_CCSR);
924 #endif
925 		if (!(status & 0x02)) {
926 			if (ret == 0)
927 				printf("%s: spurious interrupt\n",
928 				    sc->sc_dev.dv_xname);
929 			return (ret);
930 		}
931 		ret = 1;
932 #ifndef MEMORY_MAPPED
933 		status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
934 #else
935 		status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
936 		    sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
937 #endif
938 
939 		/* Anything to receive? */
940 		if (status & CNW_ASR_RXRDY) {
941 			sc->sc_stats.nws_rx++;
942 			cnw_recv(sc);
943 		}
944 
945 		/* Receive error */
946 		if (status & CNW_ASR_RXERR) {
947 			/*
948 			 * I get a *lot* of spurious receive errors
949 			 * (many per second), even when the interface
950 			 * is quiescent, so we don't increment
951 			 * if_ierrors here.
952 			 */
953 			rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
954 			    sc->sc_memoff + CNW_EREG_RSER);
955 
956 			/* RX statistics */
957 			sc->sc_stats.nws_rxerr++;
958 			if (rser & CNW_RSER_RXBIG)
959 				sc->sc_stats.nws_rxframe++;
960 			if (rser & CNW_RSER_RXCRC)
961 				sc->sc_stats.nws_rxcrcerror++;
962 			if (rser & CNW_RSER_RXOVERRUN)
963 				sc->sc_stats.nws_rxoverrun++;
964 			if (rser & CNW_RSER_RXOVERFLOW)
965 				sc->sc_stats.nws_rxoverflow++;
966 			if (rser & CNW_RSER_RXERR)
967 				sc->sc_stats.nws_rxerrors++;
968 			if (rser & CNW_RSER_RXAVAIL)
969 				sc->sc_stats.nws_rxavail++;
970 
971 			/* Clear error bits in RSER */
972 			WAIT_WOC(sc);
973 			bus_space_write_1(sc->sc_memt, sc->sc_memh,
974 			    sc->sc_memoff + CNW_EREG_RSERW,
975 			    CNW_RSER_RXERR |
976 			    (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
977 			/* Clear RXERR in ASR */
978 			WAIT_WOC(sc);
979 			bus_space_write_1(sc->sc_memt, sc->sc_memh,
980 			    sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
981 		}
982 
983 		/* Transmit done */
984 		if (status & CNW_ASR_TXDN) {
985 			tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
986 						CNW_EREG_TSER);
987 
988 			/* TX statistics */
989 			if (tser & CNW_TSER_TXERR)
990 				sc->sc_stats.nws_txerrors++;
991 			if (tser & CNW_TSER_TXNOAP)
992 				sc->sc_stats.nws_txlostcd++;
993 			if (tser & CNW_TSER_TXGU)
994 				sc->sc_stats.nws_txabort++;
995 
996 			if (tser & CNW_TSER_TXOK) {
997 				sc->sc_stats.nws_txokay++;
998 				sc->sc_stats.nws_txretries[status & 0xf]++;
999 				WAIT_WOC(sc);
1000 				bus_space_write_1(sc->sc_memt, sc->sc_memh,
1001 				    sc->sc_memoff + CNW_EREG_TSERW,
1002 				    CNW_TSER_TXOK | CNW_TSER_RTRY);
1003 			}
1004 
1005 			if (tser & CNW_TSER_ERROR) {
1006 				++ifp->if_oerrors;
1007 				WAIT_WOC(sc);
1008 				bus_space_write_1(sc->sc_memt, sc->sc_memh,
1009 				    sc->sc_memoff + CNW_EREG_TSERW,
1010 				    (tser & CNW_TSER_ERROR) |
1011 				    CNW_TSER_RTRY);
1012 			}
1013 
1014 			sc->sc_active = 0;
1015 			ifp->if_flags &= ~IFF_OACTIVE;
1016 
1017 			/* Continue to send packets from the queue */
1018 			cnw_start(&sc->sc_ethercom.ec_if);
1019 		}
1020 
1021 	}
1022 }
1023 
1024 
1025 /*
1026  * Handle device ioctls.
1027  */
1028 int
1029 cnw_ioctl(ifp, cmd, data)
1030 	struct ifnet *ifp;
1031 	u_long cmd;
1032 	caddr_t data;
1033 {
1034 	struct cnw_softc *sc = ifp->if_softc;
1035 	struct ifaddr *ifa = (struct ifaddr *)data;
1036 	struct ifreq *ifr = (struct ifreq *)data;
1037 	int s, error = 0;
1038 	struct proc *p = curproc;	/*XXX*/
1039 
1040 	s = splnet();
1041 
1042 	switch (cmd) {
1043 
1044 	case SIOCSIFADDR:
1045 		if (!(ifp->if_flags & IFF_RUNNING) &&
1046 		    (error = cnw_enable(sc)) != 0)
1047 			break;
1048 		ifp->if_flags |= IFF_UP;
1049 		switch (ifa->ifa_addr->sa_family) {
1050 #ifdef INET
1051 		case AF_INET:
1052 			cnw_init(sc);
1053 			arp_ifinit(&sc->sc_ethercom.ec_if, ifa);
1054 			break;
1055 #endif
1056 		default:
1057 			cnw_init(sc);
1058 			break;
1059 		}
1060 		break;
1061 
1062 	case SIOCSIFFLAGS:
1063 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
1064 			/*
1065 			 * The interface is marked down and it is running, so
1066 			 * stop it.
1067 			 */
1068 			cnw_disable(sc);
1069 		} else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
1070 			/*
1071 			 * The interface is marked up and it is stopped, so
1072 			 * start it.
1073 			 */
1074 			error = cnw_enable(sc);
1075 		} else {
1076 			/* IFF_PROMISC may be changed */
1077 			cnw_init(sc);
1078 		}
1079 		break;
1080 
1081 	case SIOCADDMULTI:
1082 	case SIOCDELMULTI:
1083 		/* Update our multicast list. */
1084 		error = (cmd == SIOCADDMULTI) ?
1085 		    ether_addmulti(ifr, &sc->sc_ethercom) :
1086 		    ether_delmulti(ifr, &sc->sc_ethercom);
1087 		if (error == ENETRESET) {
1088 			if (ifp->if_flags & IFF_RUNNING)
1089 				cnw_init(sc);
1090 			error = 0;
1091 		}
1092 		break;
1093 
1094 	case SIOCGCNWDOMAIN:
1095 		((struct ifreq *)data)->ifr_domain = sc->sc_domain;
1096 		break;
1097 
1098 	case SIOCSCNWDOMAIN:
1099 		error = suser(p->p_ucred, &p->p_acflag);
1100 		if (error)
1101 			break;
1102 		error = cnw_setdomain(sc, ifr->ifr_domain);
1103 		break;
1104 
1105 	case SIOCSCNWKEY:
1106 		error = suser(p->p_ucred, &p->p_acflag);
1107 		if (error)
1108 			break;
1109 		error = cnw_setkey(sc, ifr->ifr_key);
1110 		break;
1111 
1112 	case SIOCGCNWSTATUS:
1113 		error = suser(p->p_ucred, &p->p_acflag);
1114 		if (error)
1115 			break;
1116 		if ((ifp->if_flags & IFF_RUNNING) == 0)
1117 			break;
1118 		bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
1119 		    sc->sc_memoff + CNW_EREG_CB,
1120 		    ((struct cnwstatus *)data)->data,
1121 		    sizeof(((struct cnwstatus *)data)->data));
1122 		break;
1123 
1124 	case SIOCGCNWSTATS:
1125 		memcpy((void *)&(((struct cnwistats *)data)->stats),
1126 		    (void *)&sc->sc_stats, sizeof(struct cnwstats));
1127 			break;
1128 
1129 	default:
1130 		error = EINVAL;
1131 		break;
1132 	}
1133 
1134 	splx(s);
1135 	return (error);
1136 }
1137 
1138 
1139 /*
1140  * Device timeout/watchdog routine. Entered if the device neglects to
1141  * generate an interrupt after a transmit has been started on it.
1142  */
1143 void
1144 cnw_watchdog(ifp)
1145 	struct ifnet *ifp;
1146 {
1147 	struct cnw_softc *sc = ifp->if_softc;
1148 
1149 	printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
1150 	++ifp->if_oerrors;
1151 	cnw_init(sc);
1152 }
1153 
1154 int
1155 cnw_setdomain(sc, domain)
1156 	struct cnw_softc *sc;
1157 	int domain;
1158 {
1159 	int s;
1160 
1161 	if (domain & ~0x1ff)
1162 		return EINVAL;
1163 
1164 	s = splnet();
1165 	CNW_CMD2(sc, CNW_CMD_SMD, domain, domain >> 8);
1166 	splx(s);
1167 
1168 	sc->sc_domain = domain;
1169 	return 0;
1170 }
1171 
1172 int
1173 cnw_setkey(sc, key)
1174 	struct cnw_softc *sc;
1175 	int key;
1176 {
1177 	int s;
1178 
1179 	if (key & ~0xffff)
1180 		return EINVAL;
1181 
1182 	s = splnet();
1183 	CNW_CMD2(sc, CNW_CMD_SSK, key, key >> 8);
1184 	splx(s);
1185 
1186 	sc->sc_skey = key;
1187 	return 0;
1188 }
1189 
1190 int
1191 cnw_activate(self, act)
1192 	struct device *self;
1193 	enum devact act;
1194 {
1195 	struct cnw_softc *sc = (struct cnw_softc *)self;
1196 	int rv = 0, s;
1197 
1198 	s = splnet();
1199 	switch (act) {
1200 	case DVACT_ACTIVATE:
1201 		rv = EOPNOTSUPP;
1202 		break;
1203 
1204 	case DVACT_DEACTIVATE:
1205 		if_deactivate(&sc->sc_ethercom.ec_if);
1206 		break;
1207 	}
1208 	splx(s);
1209 	return (rv);
1210 }
1211 
1212 int
1213 cnw_detach(self, flags)
1214 	struct device *self;
1215 	int flags;
1216 {
1217 	struct cnw_softc *sc = (struct cnw_softc *)self;
1218 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1219 
1220 	/* cnw_disable() checks IFF_RUNNING */
1221 	cnw_disable(sc);
1222 
1223 	if ((sc->sc_resource & CNW_RES_NET) != 0) {
1224 		ether_ifdetach(ifp);
1225 		if_detach(ifp);
1226 	}
1227 
1228 #ifndef MEMORY_MAPPED
1229 	/* unmap and free our i/o windows */
1230 	if ((sc->sc_resource & CNW_RES_IO) != 0) {
1231 		pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
1232 		pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
1233 	}
1234 #endif
1235 
1236 	/* unmap and free our memory windows */
1237 	if ((sc->sc_resource & CNW_RES_MEM) != 0) {
1238 		pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
1239 		pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
1240 	}
1241 
1242 	return (0);
1243 }
1244