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