]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/cnw/if_cnw.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / cnw / if_cnw.c
1 /*      $NetBSD: if_cnw.c,v 1.15 2000/10/16 10:26:41 itojun Exp $       */
2
3
4 #include <sys/cdefs.h>
5 __FBSDID("$FreeBSD$");
6 /*-
7  * Copyright (c) 1998 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Michael Eriksson.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *      This product includes software developed by the NetBSD
24  *      Foundation, Inc. and its contributors.
25  * 4. Neither the name of The NetBSD Foundation nor the names of its
26  *    contributors may be used to endorse or promote products derived
27  *    from this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  */
41
42 /*
43  * Copyright (c) 1996, 1997 Berkeley Software Design, Inc.
44  * All rights reserved.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that this notice is retained,
48  * the conditions in the following notices are met, and terms applying
49  * to contributors in the following notices also apply to Berkeley
50  * Software Design, Inc.
51  *
52  * 1. Redistributions of source code must retain the above copyright
53  *    notice, this list of conditions and the following disclaimer.
54  * 2. Redistributions in binary form must reproduce the above copyright
55  *    notice, this list of conditions and the following disclaimer in the
56  *    documentation and/or other materials provided with the distribution.
57  * 3. All advertising materials mentioning features or use of this software
58  *    must display the following acknowledgement:
59  *      This product includes software developed by
60  *      Berkeley Software Design, Inc.
61  * 4. Neither the name of the Berkeley Software Design, Inc. nor the names
62  *    of its contributors may be used to endorse or promote products derived
63  *    from this software without specific prior written permission.
64  *
65  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
66  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
69  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75  * SUCH DAMAGE.
76  *
77  * Paul Borman, December 1996
78  *
79  * This driver is derived from a generic frame work which is
80  * Copyright(c) 1994,1995,1996
81  * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project
82  * and Foretune.  All rights reserved.
83  *
84  * A linux driver was used as the "hardware reference manual" (i.e.,
85  * to determine registers and a general outline of how the card works)
86  * That driver is publically available and copyright
87  *
88  * John Markus Bjørndalen
89  * Department of Computer Science
90  * University of Tromsø
91  * Norway             
92  * johnm@staff.cs.uit.no, http://www.cs.uit.no/~johnm/
93  */
94
95 /*
96  * This is a driver for the Xircom CreditCard Netwave (also known as
97  * the Netwave Airsurfer) wireless LAN PCMCIA adapter.
98  *
99  * When this driver was developed, the Linux Netwave driver was used
100  * as a hardware manual. That driver is Copyright (c) 1997 University
101  * of Tromsø, Norway. It is part of the Linix pcmcia-cs package that
102  * can be found at
103  * http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html. The most
104  * recent version of the pcmcia-cs package when this driver was
105  * written was 3.0.6.
106  *
107  * Unfortunately, a lot of explicit numeric constants were used in the
108  * Linux driver. I have tried to use symbolic names whenever possible,
109  * but since I don't have any real hardware documentation, there's
110  * still one or two "magic numbers" :-(.
111  *
112  * Driver limitations: This driver doesn't do multicasting or receiver
113  * promiscuity, because of missing hardware documentation. I couldn't
114  * get receiver promiscuity to work, and I haven't even tried
115  * multicast. Volunteers are welcome, of course :-).
116  */
117
118 #if !defined(__FreeBSD__)
119 #include "opt_inet.h"
120 #include "bpfilter.h"
121
122 #include <sys/param.h>
123 #include <sys/systm.h>
124 #include <sys/device.h>
125 #include <sys/socket.h>
126 #include <sys/mbuf.h>
127 #include <sys/ioctl.h>
128 #include <sys/proc.h>
129
130 #include <net/if.h>
131
132 #include <dev/pcmcia/if_cnwreg.h>
133 #include <dev/pcmcia/if_cnwioctl.h>
134
135 #include <dev/pcmcia/pcmciareg.h>
136 #include <dev/pcmcia/pcmciavar.h>
137 #include <dev/pcmcia/pcmciadevs.h>
138
139 #include <net/if_dl.h>
140 #include <net/if_ether.h>
141
142 #ifdef INET
143 #include <netinet/in.h>
144 #include <netinet/in_systm.h>
145 #include <netinet/in_var.h>
146 #include <netinet/ip.h>
147 #include <netinet/if_inarp.h>
148 #endif
149
150 #if NBPFILTER > 0
151 #include <net/bpf.h>
152 #include <net/bpfdesc.h>
153 #endif
154
155 /*
156  * Let these be patchable variables, initialized from macros that can
157  * be set in the kernel config file. Someone with lots of spare time
158  * could probably write a nice Netwave configuration program to do
159  * this a little bit more elegantly :-).
160  */
161 #ifndef CNW_DOMAIN
162 #define CNW_DOMAIN      0x100
163 #endif
164 int cnw_domain = CNW_DOMAIN;            /* Domain */
165 #ifndef CNW_SCRAMBLEKEY
166 #define CNW_SCRAMBLEKEY 0
167 #endif
168 int cnw_skey = CNW_SCRAMBLEKEY;         /* Scramble key */
169
170 /*
171  * The card appears to work much better when we only allow one packet
172  * "in the air" at a time.  This is done by not allowing another packet
173  * on the card, even if there is room.  Turning this off will allow the
174  * driver to stuff packets on the card as soon as a transmit buffer is
175  * available.  This does increase the number of collisions, though.
176  * We can que a second packet if there are transmit buffers available,
177  * but we do not actually send the packet until the last packet has
178  * been written.
179  */
180 #define ONE_AT_A_TIME
181
182 /*
183  * Netwave cards choke if we try to use io memory address >= 0x400.
184  * Even though, CIS tuple does not talk about this.
185  * Use memory mapped access.
186  */
187 #define MEMORY_MAPPED
188
189 int     cnw_match(struct device *, struct cfdata *, void *);
190 void    cnw_attach(struct device *, struct device *, void *);
191 int     cnw_detach(struct device *, int);
192
193 int     cnw_activate(struct device *, enum devact);
194
195 struct cnw_softc {
196         struct device sc_dev;               /* Device glue (must be first) */
197         struct ethercom sc_ethercom;        /* Ethernet common part */
198         int sc_domain;                      /* Netwave domain */
199         int sc_skey;                        /* Netwave scramble key */
200         struct cnwstats sc_stats;
201
202         /* PCMCIA-specific stuff */
203         struct pcmcia_function *sc_pf;      /* PCMCIA function */
204 #ifndef MEMORY_MAPPED
205         struct pcmcia_io_handle sc_pcioh;   /* PCMCIA I/O space handle */
206         int sc_iowin;                       /*   ...window */
207         bus_space_tag_t sc_iot;             /*   ...bus_space tag */
208         bus_space_handle_t sc_ioh;          /*   ...bus_space handle */
209 #endif
210         struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */
211         bus_addr_t sc_memoff;               /*   ...offset */
212         int sc_memwin;                      /*   ...window */
213         bus_space_tag_t sc_memt;            /*   ...bus_space tag */
214         bus_space_handle_t sc_memh;         /*   ...bus_space handle */
215         void *sc_ih;                        /* Interrupt cookie */
216         struct timeval sc_txlast;           /* When the last xmit was made */
217         int sc_active;                      /* Currently xmitting a packet */
218
219         int sc_resource;                    /* Resources alloc'ed on attach */
220 #define CNW_RES_PCIC    1
221 #define CNW_RES_IO      2
222 #define CNW_RES_MEM     4
223 #define CNW_RES_NET     8
224 };
225
226 struct cfattach cnw_ca = {
227         sizeof(struct cnw_softc), cnw_match, cnw_attach, cnw_detach,
228                 cnw_activate
229 };
230
231 #else /* FreeBSD */
232
233 #include <sys/param.h>
234 #include <sys/systm.h>
235 #include <sys/sockio.h>
236 #include <sys/mbuf.h>
237 #include <sys/malloc.h>
238 #include <sys/kernel.h>
239 #include <sys/priv.h>
240 #include <sys/proc.h>
241 #include <sys/ucred.h>
242 #include <sys/socket.h>
243 #include <sys/module.h>
244 #include <sys/bus.h>
245 #include <sys/syslog.h>
246 #include <sys/sysctl.h>
247
248 #include <machine/bus.h>
249 #include <machine/resource.h>
250 #include <machine/md_var.h>
251 #include <sys/rman.h>
252
253 #include <net/if.h>
254 #include <net/if_arp.h>
255 #include <net/ethernet.h>
256 #include <net/if_dl.h>
257 #include <net/if_media.h>
258 #include <net/if_types.h>
259
260 #include <netinet/in.h>
261 #include <netinet/in_systm.h>
262 #include <netinet/in_var.h>
263 #include <netinet/ip.h>
264 #include <netinet/if_ether.h>
265
266 #include <net/bpf.h>
267
268 #include <dev/pccard/pccardvar.h>
269 #include "card_if.h"
270
271 #include <dev/cnw/if_cnwioctl.h>
272 #include <dev/cnw/if_cnwreg.h>
273
274 #ifndef CNW_DOMAIN
275 #define CNW_DOMAIN      0x100
276 #endif
277 int cnw_domain = (int)CNW_DOMAIN;               /* Domain */
278
279 #ifndef CNW_SCRAMBLEKEY
280 #define CNW_SCRAMBLEKEY 0
281 #endif
282 int cnw_skey = CNW_SCRAMBLEKEY;                 /* Scramble key */
283
284 #define ONE_AT_A_TIME
285
286 #ifndef MEMORY_MAPPED
287 #define MEMORY_MAPPED
288 #endif
289
290 struct cnw_softc {
291         struct ifnet    *sc_ifp;
292         struct ifmedia  ifmedia;
293         device_t        dev;
294         struct cnwstats sc_stats;
295         int sc_domain;                      /* Netwave domain */
296         int sc_skey;                            /* Netwave scramble key */
297
298         struct resource *       mem_res;
299         struct resource *       irq;
300
301         bus_addr_t              sc_memoff;      /*   ...offset */
302         bus_space_tag_t         sc_memt;        /*   ...bus_space tag */
303         bus_space_handle_t      sc_memh;        /*   ...bus_space handle */
304
305         void *                  cnw_intrhand;
306         int                     cnw_gone;
307
308         struct timeval sc_txlast;           /* When the last xmit was made */
309         int sc_active;                      /* Currently xmitting a packet */
310 };
311
312
313 static void cnw_freebsd_init    (void *);
314 static void cnw_stop            (struct cnw_softc *);
315
316 static int cnw_pccard_probe     (device_t);
317 static int cnw_pccard_attach    (device_t);
318 static int cnw_pccard_detach    (device_t);
319 static void cnw_shutdown        (device_t);
320 static int cnw_alloc            (device_t);
321 static void cnw_free            (device_t);
322
323 static device_method_t cnw_pccard_methods[] = {
324         /* Device interface */
325         DEVMETHOD(device_probe,         cnw_pccard_probe),
326         DEVMETHOD(device_attach,        cnw_pccard_attach),
327         DEVMETHOD(device_detach,        cnw_pccard_detach),
328         DEVMETHOD(device_shutdown,      cnw_shutdown),
329
330         { 0, 0 }
331 };
332
333 static driver_t cnw_pccard_driver = {
334         "cnw",
335         cnw_pccard_methods,
336         sizeof(struct cnw_softc)
337 };
338
339 static devclass_t cnw_pccard_devclass;
340
341 DRIVER_MODULE(cnw, pccard, cnw_pccard_driver, cnw_pccard_devclass, 0, 0);
342 MODULE_DEPEND(cnw, ether, 1, 1, 1);
343
344 #endif /* !defined(__FreeBSD__) */
345
346 void cnw_reset(struct cnw_softc *);
347 void cnw_init(struct cnw_softc *);
348 #if !defined(__FreeBSD__)
349 int cnw_enable(struct cnw_softc *sc);
350 void cnw_disable(struct cnw_softc *sc);
351 void cnw_config(struct cnw_softc *sc, u_int8_t *);
352 #endif
353 void cnw_start(struct ifnet *);
354 void cnw_transmit(struct cnw_softc *, struct mbuf *);
355 struct mbuf *cnw_read(struct cnw_softc *);
356 void cnw_recv(struct cnw_softc *);
357 #if !defined(__FreeBSD__)
358 int cnw_intr(void *arg);
359 #else
360 void cnw_intr(void *arg);
361 #endif
362 int cnw_ioctl(struct ifnet *, u_long, caddr_t);
363 void cnw_watchdog(struct ifnet *);
364 static int cnw_setdomain(struct cnw_softc *, int);
365 static int cnw_setkey(struct cnw_softc *, int);
366
367 /* ---------------------------------------------------------------- */
368
369 /* Help routines */
370 static int wait_WOC(struct cnw_softc *, int);
371 static int read16(struct cnw_softc *, int);
372 static int cnw_cmd(struct cnw_softc *, int, int, int, int);
373
374 /* 
375  * Wait until the WOC (Write Operation Complete) bit in the 
376  * ASR (Adapter Status Register) is asserted. 
377  */
378 static int
379 wait_WOC(sc, line)
380         struct cnw_softc *sc;
381         int line;
382 {
383         int i, asr;
384
385         for (i = 0; i < 5000; i++) {
386 #ifndef MEMORY_MAPPED
387                 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
388 #else
389                 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh,
390                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
391 #endif
392                 if (asr & CNW_ASR_WOC)
393                         return (0);
394                 DELAY(100);
395         }
396         if (line > 0)
397 #if !defined(__FreeBSD__)
398                 printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line);
399 #else
400                 device_printf(sc->dev, "wedged at line %d\n", line);
401 #endif
402         return (1);
403 }
404 #define WAIT_WOC(sc) wait_WOC(sc, __LINE__)
405
406
407 /*
408  * Read a 16 bit value from the card. 
409  */
410 static int
411 read16(sc, offset)
412         struct cnw_softc *sc;
413         int offset;
414 {
415         int hi, lo;
416         int offs = sc->sc_memoff + offset;
417
418         /* This could presumably be done more efficient with
419          * bus_space_read_2(), but I don't know anything about the
420          * byte sex guarantees... Besides, this is pretty cheap as
421          * well :-)
422          */
423         lo = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs);
424         hi = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs + 1);
425         return ((hi << 8) | lo);
426 }
427
428
429 /*
430  * Send a command to the card by writing it to the command buffer.
431  */
432 int
433 cnw_cmd(sc, cmd, count, arg1, arg2)
434         struct cnw_softc *sc;
435         int cmd, count, arg1, arg2;
436 {
437         int ptr = sc->sc_memoff + CNW_EREG_CB;
438
439         if (wait_WOC(sc, 0)) {
440 #if !defined(__FreeBSD__)
441                 printf("%s: wedged when issuing cmd 0x%x\n",
442                     sc->sc_dev.dv_xname, cmd);
443 #else
444                 device_printf(sc->dev, "wedged when issuing cmd 0x%x\n", cmd);
445 #endif
446                 /*
447                  * We'll continue anyway, as that's probably the best
448                  * thing we can do; at least the user knows there's a
449                  * problem, and can reset the interface with ifconfig
450                  * down/up.
451                  */
452         }
453
454         bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd);
455         if (count > 0) {
456                 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1);
457                 if (count > 1)
458                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
459                             ptr + 2, arg2);
460         }
461         bus_space_write_1(sc->sc_memt, sc->sc_memh,
462             ptr + count + 1, CNW_CMD_EOC);
463         return (0);
464 }
465 #define CNW_CMD0(sc, cmd) \
466     do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0)
467 #define CNW_CMD1(sc, cmd, arg1) \
468     do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0)
469 #define CNW_CMD2(sc, cmd, arg1, arg2) \
470     do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0)
471
472 /* ---------------------------------------------------------------- */
473
474 /*
475  * Reset the hardware.
476  */
477 void
478 cnw_reset(sc)
479         struct cnw_softc *sc;
480 {
481 #ifdef CNW_DEBUG
482         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
483                 printf("%s: resetting\n", sc->sc_dev.dv_xname);
484 #endif
485         wait_WOC(sc, 0);
486 #ifndef MEMORY_MAPPED
487         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET);
488 #else
489         bus_space_write_1(sc->sc_memt, sc->sc_memh,
490             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, CNW_PMR_RESET);
491 #endif
492         bus_space_write_1(sc->sc_memt, sc->sc_memh,
493             sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC);
494 #ifndef MEMORY_MAPPED
495         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0);
496 #else
497         bus_space_write_1(sc->sc_memt, sc->sc_memh,
498             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, 0);
499 #endif
500 }
501
502
503 /*
504  * Initialize the card.
505  */
506 void
507 cnw_init(sc)
508         struct cnw_softc *sc;
509 {
510 #if !defined(__FreeBSD__)
511         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
512 #else   /* FreeBSD */
513         struct ifnet *ifp = sc->sc_ifp;
514 #endif
515         const u_int8_t rxmode =
516             CNW_RXCONF_RXENA | CNW_RXCONF_BCAST | CNW_RXCONF_AMP;
517
518         /* Reset the card */
519         cnw_reset(sc);
520
521         /* Issue a NOP to check the card */
522         CNW_CMD0(sc, CNW_CMD_NOP);
523
524         /* Set up receive configuration */
525         CNW_CMD1(sc, CNW_CMD_SRC,
526             rxmode | ((ifp->if_flags & IFF_PROMISC) ? CNW_RXCONF_PRO : 0));
527
528         /* Set up transmit configuration */
529         CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA);
530
531         /* Set domain */
532         CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8);
533
534         /* Set scramble key */
535         CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8);
536
537         /* Enable interrupts */
538         WAIT_WOC(sc);
539 #ifndef MEMORY_MAPPED
540         bus_space_write_1(sc->sc_iot, sc->sc_ioh,
541             CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1);
542 #else
543         bus_space_write_1(sc->sc_memt, sc->sc_memh,
544             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_IMR,
545             CNW_IMR_IENA | CNW_IMR_RFU1);
546 #endif
547
548         /* Enable receiver */
549         CNW_CMD0(sc, CNW_CMD_ER);
550
551         /* "Set the IENA bit in COR" */
552         WAIT_WOC(sc);
553 #ifndef MEMORY_MAPPED
554         bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR,
555             CNW_COR_IENA | CNW_COR_LVLREQ);
556 #else
557         bus_space_write_1(sc->sc_memt, sc->sc_memh,
558             sc->sc_memoff + CNW_IOM_OFF + CNW_REG_COR,
559             CNW_COR_IENA | CNW_COR_LVLREQ);
560 #endif
561 }
562
563
564 #if !defined(__FreeBSD__)
565 /*
566  * Enable and initialize the card.
567  */
568 int
569 cnw_enable(sc)
570         struct cnw_softc *sc;
571 {
572         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
573
574         if ((ifp->if_flags & IFF_RUNNING) != 0)
575                 return (0);
576
577         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, cnw_intr, sc);
578         if (sc->sc_ih == NULL) {
579                 printf("%s: couldn't establish interrupt handler\n",
580                     sc->sc_dev.dv_xname);
581                 return (EIO);
582         }
583         if (pcmcia_function_enable(sc->sc_pf) != 0) {
584                 printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
585                 return (EIO);
586         }
587         sc->sc_resource |= CNW_RES_PCIC;
588         cnw_init(sc);
589         ifp->if_flags &= ~IFF_OACTIVE;
590         ifp->if_flags |= IFF_RUNNING;
591         return (0);
592 }
593
594
595 /*
596  * Stop and disable the card.
597  */
598 void
599 cnw_disable(sc)
600         struct cnw_softc *sc;
601 {
602         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
603
604         if ((ifp->if_flags & IFF_RUNNING) == 0)
605                 return;
606
607         pcmcia_function_disable(sc->sc_pf);
608         sc->sc_resource &= ~CNW_RES_PCIC;
609         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
610         ifp->if_flags &= ~IFF_RUNNING;
611         ifp->if_timer = 0;
612 }
613
614 /*
615  * Match the hardware we handle.
616  */
617 int
618 cnw_match(parent, match, aux)
619         struct device *parent;
620         struct cfdata *match;
621         void *aux;
622 {
623         struct pcmcia_attach_args *pa = aux;
624
625         if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
626             pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_801)
627                 return 1;
628         if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
629             pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_802)
630                 return 1;
631         return 0;
632 }
633
634
635 /*
636  * Attach the card.
637  */
638 void
639 cnw_attach(parent, self, aux)
640         struct device  *parent, *self;
641         void           *aux;
642 {
643         struct cnw_softc *sc = (void *) self;
644         struct pcmcia_attach_args *pa = aux;
645         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
646         u_int8_t macaddr[ETHER_ADDR_LEN];
647         int i;
648         bus_size_t memsize;
649
650         sc->sc_resource = 0;
651
652         /* Enable the card */
653         sc->sc_pf = pa->pf;
654         pcmcia_function_init(sc->sc_pf, sc->sc_pf->cfe_head.sqh_first);
655         if (pcmcia_function_enable(sc->sc_pf)) {
656                 printf(": function enable failed\n");
657                 return;
658         }
659         sc->sc_resource |= CNW_RES_PCIC;
660
661         /* Map I/O register and "memory" */
662 #ifndef MEMORY_MAPPED
663         if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE,
664             &sc->sc_pcioh) != 0) {
665                 printf(": can't allocate i/o space\n");
666                 goto fail;
667         }
668         if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, 0,
669             CNW_IO_SIZE, &sc->sc_pcioh, &sc->sc_iowin) != 0) {
670                 printf(": can't map i/o space\n");
671                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
672                 goto fail;
673         }
674         sc->sc_iot = sc->sc_pcioh.iot;
675         sc->sc_ioh = sc->sc_pcioh.ioh;
676         sc->sc_resource |= CNW_RES_IO;
677 #endif
678 #ifndef MEMORY_MAPPED
679         memsize = CNW_MEM_SIZE;
680 #else
681         memsize = CNW_MEM_SIZE + CNW_IOM_SIZE;
682 #endif
683         if (pcmcia_mem_alloc(sc->sc_pf, memsize, &sc->sc_pcmemh) != 0) {
684                 printf(": can't allocate memory\n");
685                 goto fail;
686         }
687         if (pcmcia_mem_map(sc->sc_pf, PCMCIA_WIDTH_MEM8|PCMCIA_MEM_COMMON,
688             CNW_MEM_ADDR, memsize, &sc->sc_pcmemh, &sc->sc_memoff,
689             &sc->sc_memwin) != 0) {
690                 printf(": can't map memory\n");
691                 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
692                 goto fail;
693         }
694         sc->sc_memt = sc->sc_pcmemh.memt;
695         sc->sc_memh = sc->sc_pcmemh.memh;
696         sc->sc_resource |= CNW_RES_MEM;
697         switch (pa->product) {
698         case PCMCIA_PRODUCT_XIRCOM_CNW_801:
699                 printf(": %s\n", PCMCIA_STR_XIRCOM_CNW_801);
700                 break;
701         case PCMCIA_PRODUCT_XIRCOM_CNW_802:
702                 printf(": %s\n", PCMCIA_STR_XIRCOM_CNW_802);
703                 break;
704         }
705
706         /* Finish setup of softc */
707         sc->sc_domain = cnw_domain;
708         sc->sc_skey = cnw_skey;
709
710         /* Get MAC address */
711         cnw_reset(sc);
712         for (i = 0; i < ETHER_ADDR_LEN; i++)
713                 macaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh,
714                     sc->sc_memoff + CNW_EREG_PA + i);
715         printf("%s: address %s\n", sc->sc_dev.dv_xname,
716             ether_sprintf(macaddr));
717
718         /* Set up ifnet structure */
719         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
720         ifp->if_softc = sc;
721         ifp->if_start = cnw_start;
722         ifp->if_ioctl = cnw_ioctl;
723         ifp->if_watchdog = cnw_watchdog;
724         ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX |
725             IFF_NOTRAILERS;
726
727         /* Attach the interface */
728         if_attach(ifp);
729         ether_ifattach(ifp, macaddr);
730 #if NBPFILTER > 0
731         bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
732             sizeof(struct ether_header));
733 #endif
734         sc->sc_resource |= CNW_RES_NET;
735
736         ifp->if_baudrate = IF_Mbps(1);
737
738         /* Disable the card now, and turn it on when the interface goes up */
739         pcmcia_function_disable(sc->sc_pf);
740         sc->sc_resource &= ~CNW_RES_PCIC;
741         return;
742
743 fail:
744 #ifndef MEMORY_MAPPED
745         if ((sc->sc_resource & CNW_RES_IO) != 0) {
746                 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
747                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
748                 sc->sc_resource &= ~CNW_RES_IO;
749         }
750 #endif
751         if ((sc->sc_resource & CNW_RES_PCIC) != 0) {
752                 pcmcia_function_disable(sc->sc_pf);
753                 sc->sc_resource &= ~CNW_RES_PCIC;
754         }
755 }
756 #endif /* !defined(__FreeBSD__) */
757
758 /*
759  * Start outputting on the interface.
760  */
761 void
762 cnw_start(ifp)
763         struct ifnet *ifp;
764 {
765         struct cnw_softc *sc = ifp->if_softc;
766         struct mbuf *m0;
767         int lif;
768         int asr;
769 #ifdef ONE_AT_A_TIME
770         struct timeval now;
771 #endif
772
773 #ifdef CNW_DEBUG
774         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
775                 printf("%s: cnw_start\n", ifp->if_xname);
776 #if defined(__FreeBSD__)
777         if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
778 #else
779         if (ifp->if_flags & IFF_OACTIVE)
780 #endif
781                 printf("%s: cnw_start reentered\n", ifp->if_xname);
782 #endif
783
784 #if defined(__FreeBSD__)
785         if (sc->cnw_gone)
786                 return;
787
788         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
789 #else
790         ifp->if_flags |= IFF_OACTIVE;
791 #endif
792
793         for (;;) {
794 #ifdef ONE_AT_A_TIME
795                 microtime(&now);
796                 now.tv_sec -= sc->sc_txlast.tv_sec;
797                 now.tv_usec -= sc->sc_txlast.tv_usec;
798                 if (now.tv_usec < 0) {
799                         now.tv_usec += 1000000;
800                         now.tv_sec--;
801                 }
802
803                 /*
804                  * Don't ship this packet out until the last
805                  * packet has left the building.
806                  * If we have not tried to send a packet for 1/5
807                  * a second then we assume we lost an interrupt,
808                  * lets go on and send the next packet anyhow.
809                  *
810                  * I suppose we could check to see if it is okay
811                  * to put additional packets on the card (beyond
812                  * the one already waiting to be sent) but I don't
813                  * think we would get any improvement in speed as
814                  * we should have ample time to put the next packet
815                  * on while this one is going out.
816                  */
817                 if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000)
818                         break;
819 #endif
820
821                 /* Make sure the link integrity field is on */
822                 WAIT_WOC(sc);
823                 lif = bus_space_read_1(sc->sc_memt, sc->sc_memh,
824                     sc->sc_memoff + CNW_EREG_LIF);
825                 if (lif == 0) {
826 #ifdef CNW_DEBUG
827                         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
828                                 printf("%s: link integrity %d\n", lif);
829 #endif
830                         break;
831                 }
832
833                 /* Is there any buffer space available on the card? */
834                 WAIT_WOC(sc);
835 #ifndef MEMORY_MAPPED
836                 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
837 #else
838                 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh,
839                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
840 #endif
841                 if (!(asr & CNW_ASR_TXBA)) {
842 #ifdef CNW_DEBUG
843                         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
844                                 printf("%s: no buffer space\n", ifp->if_xname);
845 #endif
846                         break;
847                 }
848
849                 sc->sc_stats.nws_tx++;
850
851                 IF_DEQUEUE(&ifp->if_snd, m0);
852                 if (m0 == 0)
853                         break;
854
855 #if !defined(__FreeBSD__)
856 #if NBPFILTER > 0
857                 if (ifp->if_bpf)
858                         bpf_mtap(ifp->if_bpf, m0);
859 #endif
860 #else   /* FreeBSD */
861                 BPF_MTAP(ifp, m0);
862 #endif
863                 
864                 cnw_transmit(sc, m0);
865                 ++ifp->if_opackets;
866                 ifp->if_timer = 3; /* start watchdog timer */
867
868                 microtime(&sc->sc_txlast);
869                 sc->sc_active = 1;
870         }
871
872 #if defined(__FreeBSD__)
873         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
874 #else
875         ifp->if_flags &= ~IFF_OACTIVE;
876 #endif
877 }
878
879 /*
880  * Transmit a packet.
881  */
882 void
883 cnw_transmit(sc, m)
884         struct cnw_softc *sc;
885         struct mbuf *m;
886 {
887         int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
888         u_int8_t *mptr;
889
890         /* Get buffer info from card */
891         buffer = read16(sc, CNW_EREG_TDP);
892         bufsize = read16(sc, CNW_EREG_TDP + 2);
893         bufoffset = read16(sc, CNW_EREG_TDP + 4);
894 #ifdef CNW_DEBUG
895         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
896                 printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
897                     sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
898 #endif
899
900         /* Copy data from mbuf chain to card buffers */
901         bufptr = sc->sc_memoff + buffer + bufoffset;
902         bufspace = bufsize;
903         len = 0;
904         while (m) {
905                 mptr = mtod(m, u_int8_t *);
906                 mbytes = m->m_len;
907                 len += mbytes;
908                 while (mbytes > 0) {
909                         if (bufspace == 0) {
910                                 buffer = read16(sc, buffer);
911                                 bufptr = sc->sc_memoff + buffer + bufoffset;
912                                 bufspace = bufsize;
913 #ifdef CNW_DEBUG
914                                 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
915                                         printf("%s:   next buffer @0x%x\n",
916                                             sc->sc_dev.dv_xname, buffer);
917 #endif
918                         }
919                         n = mbytes <= bufspace ? mbytes : bufspace;
920                         bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
921                             bufptr, mptr, n);
922                         bufptr += n;
923                         bufspace -= n;
924                         mptr += n;
925                         mbytes -= n;
926                 }
927                 m = m_free(m);
928         }
929
930         /* Issue transmit command */
931         CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
932 }
933
934
935 /*
936  * Pull a packet from the card into an mbuf chain.
937  */
938 struct mbuf *
939 cnw_read(sc)
940         struct cnw_softc *sc;
941 {
942         struct mbuf *m, *top, **mp;
943         int totbytes, buffer, bufbytes, bufptr, mbytes, n;
944         u_int8_t *mptr;
945
946         WAIT_WOC(sc);
947         totbytes = read16(sc, CNW_EREG_RDP);
948 #ifdef CNW_DEBUG
949         if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
950                 printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
951 #endif
952         buffer = CNW_EREG_RDP + 2;
953         bufbytes = 0;
954         bufptr = 0; /* XXX make gcc happy */
955
956         MGETHDR(m, M_DONTWAIT, MT_DATA);
957         if (m == 0)
958                 return (0);
959 #if !defined(__FreeBSD__)
960         m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
961 #else   /* FreeBSD */
962         m->m_pkthdr.rcvif = sc->sc_ifp;
963 #endif
964         m->m_pkthdr.len = totbytes;
965         mbytes = MHLEN;
966         top = 0;
967         mp = &top;
968
969         while (totbytes > 0) {
970                 if (top) {
971                         MGET(m, M_DONTWAIT, MT_DATA);
972                         if (m == 0) {
973                                 m_freem(top);
974                                 return (0);
975                         }
976                         mbytes = MLEN;
977                 }
978                 if (totbytes >= MINCLSIZE) {
979                         MCLGET(m, M_DONTWAIT);
980                         if ((m->m_flags & M_EXT) == 0) {
981                                 m_free(m);
982                                 m_freem(top);
983                                 return (0);
984                         }
985                         mbytes = MCLBYTES;
986                 }
987                 if (!top) {
988                         int pad = ALIGN(sizeof(struct ether_header)) -
989                             sizeof(struct ether_header);
990                         m->m_data += pad;
991                         mbytes -= pad;
992                 }
993                 mptr = mtod(m, u_int8_t *);
994                 mbytes = m->m_len = min(totbytes, mbytes);
995                 totbytes -= mbytes;
996                 while (mbytes > 0) {
997                         if (bufbytes == 0) {
998                                 buffer = read16(sc, buffer);
999                                 bufbytes = read16(sc, buffer + 2);
1000                                 bufptr = sc->sc_memoff + buffer +
1001                                     read16(sc, buffer + 4);
1002 #ifdef CNW_DEBUG
1003                                 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
1004                                         printf("%s:   %d bytes @0x%x+0x%x\n",
1005                                             sc->sc_dev.dv_xname, bufbytes,
1006                                             buffer, bufptr - buffer -
1007                                             sc->sc_memoff);
1008 #endif
1009                         }
1010                         n = mbytes <= bufbytes ? mbytes : bufbytes;
1011                         bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
1012                             bufptr, mptr, n);
1013                         bufbytes -= n;
1014                         bufptr += n;
1015                         mbytes -= n;
1016                         mptr += n;
1017                 }
1018                 *mp = m;
1019                 mp = &m->m_next;
1020         }
1021
1022         return (top);
1023 }
1024
1025
1026 /*
1027  * Handle received packets.
1028  */
1029 void
1030 cnw_recv(sc)
1031         struct cnw_softc *sc;
1032 {
1033         int rser;
1034 #if !defined(__FreeBSD__)
1035         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1036 #else
1037         struct ifnet *ifp = sc->sc_ifp;
1038 #endif
1039         struct mbuf *m;
1040
1041         for (;;) {
1042                 WAIT_WOC(sc);
1043                 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1044                     sc->sc_memoff + CNW_EREG_RSER);
1045                 if (!(rser & CNW_RSER_RXAVAIL))
1046                         return;
1047
1048                 /* Pull packet off card */
1049                 m = cnw_read(sc);
1050
1051                 /* Acknowledge packet */
1052                 CNW_CMD0(sc, CNW_CMD_SRP);
1053
1054                 /* Did we manage to get the packet from the interface? */
1055                 if (m == 0) {
1056                         ++ifp->if_ierrors;
1057                         return;
1058                 }
1059                 ++ifp->if_ipackets;
1060
1061 #if !defined(__FreeBSD__)
1062 #if NBPFILTER > 0
1063                 if (ifp->if_bpf)
1064                         bpf_mtap(ifp->if_bpf, m);
1065 #endif
1066 #endif
1067
1068                 /* Pass the packet up. */
1069                 (*ifp->if_input)(ifp, m);
1070         }
1071 }
1072
1073
1074 /*
1075  * Interrupt handler.
1076  */
1077 #if !defined(__FreeBSD__)
1078 int
1079 #else
1080 void
1081 #endif
1082 cnw_intr(arg)
1083         void *arg;
1084 {
1085         struct cnw_softc *sc = arg;
1086 #if !defined(__FreeBSD__)
1087         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1088 #else
1089         struct ifnet *ifp = sc->sc_ifp;
1090 #endif
1091         int ret, status, rser, tser;
1092
1093
1094 #if !defined(__FreeBSD__)
1095         if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0 ||
1096             (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
1097                 return (0);
1098 #else
1099         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1100                 return;
1101 #endif
1102         ifp->if_timer = 0;      /* stop watchdog timer */
1103
1104         ret = 0;
1105         for (;;) {
1106                 WAIT_WOC(sc);
1107 #ifndef MEMORY_MAPPED
1108                 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1109                     CNW_REG_CCSR);
1110 #else
1111                 status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1112                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_CCSR);
1113 #endif
1114
1115 #if !defined(__FreeBSD__)
1116                 if (!(status & 0x02)) {
1117                         if (ret == 0)
1118                                 printf("%s: spurious interrupt\n",
1119                                     sc->sc_dev.dv_xname);
1120                         return (ret);
1121                 }
1122 #else
1123                 if (!(status & 0x02)) {
1124                         if (ret == 0)
1125                                 device_printf(sc->dev, "spurious interrupt\n");
1126                         return;
1127                 }
1128 #endif
1129                 ret = 1;
1130
1131 #ifndef MEMORY_MAPPED
1132                 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
1133 #else
1134                 status = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1135                     sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR);
1136 #endif
1137
1138                 /* Anything to receive? */
1139                 if (status & CNW_ASR_RXRDY) {
1140                         sc->sc_stats.nws_rx++;
1141                         cnw_recv(sc);
1142                 }
1143
1144                 /* Receive error */
1145                 if (status & CNW_ASR_RXERR) {
1146                         /*
1147                          * I get a *lot* of spurious receive errors
1148                          * (many per second), even when the interface
1149                          * is quiescent, so we don't increment
1150                          * if_ierrors here.
1151                          */
1152                         rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1153                             sc->sc_memoff + CNW_EREG_RSER);
1154
1155                         /* RX statistics */
1156                         sc->sc_stats.nws_rxerr++;
1157                         if (rser & CNW_RSER_RXBIG)
1158                                 sc->sc_stats.nws_rxframe++;
1159                         if (rser & CNW_RSER_RXCRC)
1160                                 sc->sc_stats.nws_rxcrcerror++;
1161                         if (rser & CNW_RSER_RXOVERRUN)
1162                                 sc->sc_stats.nws_rxoverrun++;
1163                         if (rser & CNW_RSER_RXOVERFLOW)
1164                                 sc->sc_stats.nws_rxoverflow++;
1165                         if (rser & CNW_RSER_RXERR)
1166                                 sc->sc_stats.nws_rxerrors++;
1167                         if (rser & CNW_RSER_RXAVAIL)
1168                                 sc->sc_stats.nws_rxavail++;
1169
1170                         /* Clear error bits in RSER */
1171                         WAIT_WOC(sc);
1172                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
1173                             sc->sc_memoff + CNW_EREG_RSERW,
1174                             CNW_RSER_RXERR |
1175                             (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
1176                         /* Clear RXERR in ASR */
1177                         WAIT_WOC(sc);
1178                         bus_space_write_1(sc->sc_memt, sc->sc_memh,
1179                             sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
1180                 }
1181
1182                 /* Transmit done */
1183                 if (status & CNW_ASR_TXDN) {
1184                         tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1185                                                 CNW_EREG_TSER);
1186
1187                         /* TX statistics */
1188                         if (tser & CNW_TSER_TXERR)
1189                                 sc->sc_stats.nws_txerrors++;
1190                         if (tser & CNW_TSER_TXNOAP)
1191                                 sc->sc_stats.nws_txlostcd++;
1192                         if (tser & CNW_TSER_TXGU)
1193                                 sc->sc_stats.nws_txabort++;
1194
1195                         if (tser & CNW_TSER_TXOK) {
1196                                 sc->sc_stats.nws_txokay++;
1197                                 sc->sc_stats.nws_txretries[status & 0xf]++;
1198                                 WAIT_WOC(sc);
1199                                 bus_space_write_1(sc->sc_memt, sc->sc_memh,
1200                                     sc->sc_memoff + CNW_EREG_TSERW,
1201                                     CNW_TSER_TXOK | CNW_TSER_RTRY);
1202                         }
1203
1204                         if (tser & CNW_TSER_ERROR) {
1205                                 ++ifp->if_oerrors;
1206                                 WAIT_WOC(sc);
1207                                 bus_space_write_1(sc->sc_memt, sc->sc_memh,
1208                                     sc->sc_memoff + CNW_EREG_TSERW,
1209                                     (tser & CNW_TSER_ERROR) |
1210                                     CNW_TSER_RTRY);
1211                         }
1212
1213                         sc->sc_active = 0;
1214 #if defined(__FreeBSD__)
1215                         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1216 #else
1217                         ifp->if_flags &= ~IFF_OACTIVE;
1218 #endif
1219
1220                         /* Continue to send packets from the queue */
1221 #if !defined(__FreeBSD__)
1222                         cnw_start(&sc->sc_ethercom.ec_if);
1223 #else
1224                         cnw_start(ifp);
1225 #endif
1226                 }
1227                                 
1228         }
1229 }
1230
1231
1232 /*
1233  * Handle device ioctls.
1234  */
1235 int
1236 cnw_ioctl(ifp, cmd, data)
1237         struct ifnet *ifp;
1238         u_long cmd;
1239         caddr_t data;
1240 {
1241         struct cnw_softc *sc = ifp->if_softc;
1242 #if !defined(__FreeBSD__)
1243         struct ifaddr *ifa = (struct ifaddr *)data;
1244 #endif
1245         struct ifreq *ifr = (struct ifreq *)data;
1246         int s, error = 0;
1247 #if __FreeBSD__ >= 5
1248         struct thread *td = curthread;  /* XXX */
1249 #else
1250         struct proc *td = curproc;      /*XXX*/
1251 #endif
1252
1253         s = splnet();
1254
1255 #if defined(__FreeBSD__)
1256         if (sc->cnw_gone) {
1257                 splx(s);
1258                 return(ENODEV);
1259         }
1260 #endif
1261
1262         switch (cmd) {
1263
1264         case SIOCSIFADDR:
1265 #if !defined(__FreeBSD__)
1266                 if (!(ifp->if_flags & IFF_RUNNING) &&
1267                     (error = cnw_enable(sc)) != 0)
1268                         break;
1269                 ifp->if_flags |= IFF_UP;
1270                 switch (ifa->ifa_addr->sa_family) {
1271 #ifdef INET
1272                 case AF_INET:
1273                         cnw_init(sc);
1274                         arp_ifinit(&sc->sc_ethercom.ec_if, ifa);
1275                         break;
1276 #endif
1277                 default:
1278                         cnw_init(sc);
1279                         break;
1280                 }
1281 #else
1282                 error = ether_ioctl(ifp, cmd, data);
1283 #endif
1284                 break;
1285
1286         case SIOCSIFFLAGS:
1287 #if !defined(__FreeBSD__)
1288                 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
1289                         /*
1290                          * The interface is marked down and it is running, so
1291                          * stop it.
1292                          */
1293                         cnw_disable(sc);
1294                 } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
1295                         /*
1296                          * The interface is marked up and it is stopped, so
1297                          * start it.
1298                          */
1299                         error = cnw_enable(sc);
1300                 } else {
1301                         /* IFF_PROMISC may be changed */
1302                         cnw_init(sc);
1303                 }
1304 #else
1305                 if (ifp->if_flags & IFF_UP) {
1306                                 cnw_freebsd_init(sc);
1307                 } else {
1308                         if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1309                                 cnw_stop(sc);
1310                         } else {
1311                                 cnw_freebsd_init(sc);
1312                         }
1313                 }
1314                 
1315 #endif
1316                 break;
1317
1318         case SIOCADDMULTI:
1319         case SIOCDELMULTI:
1320 #if !defined(__FreeBSD__)
1321                 /* Update our multicast list. */
1322                 error = (cmd == SIOCADDMULTI) ?
1323                     ether_addmulti(ifr, &sc->sc_ethercom) :
1324                     ether_delmulti(ifr, &sc->sc_ethercom);
1325                 if (error == ENETRESET || error == 0) {
1326                         cnw_init(sc);
1327                         error = 0;
1328                 }
1329 #else
1330                 /* XXX */
1331                 error = 0;
1332 #endif
1333                 break;
1334
1335         case SIOCGCNWDOMAIN:
1336                 ((struct ifreq *)data)->ifr_domain = sc->sc_domain;
1337                 break;
1338
1339         case SIOCSCNWDOMAIN:
1340 #if !defined(__FreeBSD__)
1341                 error = suser(p->p_ucred, &p->p_acflag);
1342 #else
1343                 error = priv_check(td, PRIV_DRIVER);
1344 #endif
1345                 if (error)
1346                         break;
1347                 error = cnw_setdomain(sc, ifr->ifr_domain);
1348                 break;
1349
1350         case SIOCSCNWKEY:
1351 #if !defined(__FreeBSD__)
1352                 error = suser(p->p_ucred, &p->p_acflag);
1353 #else
1354                 error = priv_check(td, PRIV_DRIVER);
1355 #endif
1356                 if (error)
1357                         break;
1358                 error = cnw_setkey(sc, (int)ifr->ifr_key);
1359                 break;
1360
1361         case SIOCGCNWSTATUS:
1362 #if !defined(__FreeBSD__)
1363                 error = suser(p->p_ucred, &p->p_acflag);
1364 #else
1365                 error = priv_check(td, PRIV_DRIVER);
1366 #endif
1367                 if (error)
1368                         break;
1369 #if !defined(__FreeBSD__)
1370                 if ((ifp->if_flags & IFF_RUNNING) == 0)
1371 #else
1372                 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1373 #endif
1374                         break;
1375                 bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
1376                     sc->sc_memoff + CNW_EREG_CB,
1377                     ((struct cnwstatus *)data)->data,
1378                     sizeof(((struct cnwstatus *)data)->data));
1379                 break;
1380
1381         case SIOCGCNWSTATS:
1382                 bcopy((void *)&sc->sc_stats,
1383                     (void *)&(((struct cnwistats *)data)->stats),
1384                     sizeof(struct cnwstats));
1385                         break;
1386
1387         default:
1388                 error = EINVAL;
1389                 break;
1390         }
1391
1392         splx(s);
1393         return (error);
1394 }
1395
1396
1397 /*
1398  * Device timeout/watchdog routine. Entered if the device neglects to
1399  * generate an interrupt after a transmit has been started on it.
1400  */
1401 void
1402 cnw_watchdog(ifp)
1403         struct ifnet *ifp;
1404 {
1405         struct cnw_softc *sc = ifp->if_softc;
1406
1407 #if !defined(__FreeBSD__)
1408         printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
1409         ++ifp->if_oerrors;
1410         cnw_init(sc);
1411 #else
1412         device_printf(sc->dev, "device timeout; card reset\n");
1413         ++ifp->if_oerrors;
1414         cnw_freebsd_init(sc);
1415 #endif
1416 }
1417
1418 int
1419 cnw_setdomain(sc, domain)
1420         struct cnw_softc *sc;
1421         int domain;
1422 {
1423         int s;
1424
1425         if (domain & ~0x1ff)
1426                 return EINVAL;
1427
1428         s = splnet();
1429         CNW_CMD2(sc, CNW_CMD_SMD, domain, domain >> 8);
1430         splx(s);
1431
1432         sc->sc_domain = domain;
1433         return 0;
1434 }
1435
1436 int
1437 cnw_setkey(sc, key)
1438         struct cnw_softc *sc;
1439         int key;
1440 {
1441         int s;
1442
1443         if (key & ~0xffff)
1444                 return EINVAL;
1445
1446         s = splnet();
1447         CNW_CMD2(sc, CNW_CMD_SSK, key, key >> 8);
1448         splx(s);
1449
1450         sc->sc_skey = key;
1451         return 0;
1452 }
1453
1454 #if !defined(__FreeBSD__)
1455 int
1456 cnw_activate(self, act)
1457         struct device *self;
1458         enum devact act;
1459 {
1460         struct cnw_softc *sc = (struct cnw_softc *)self;
1461         int rv = 0, s;
1462
1463         s = splnet();
1464         switch (act) {
1465         case DVACT_ACTIVATE:
1466                 rv = EOPNOTSUPP;
1467                 break;
1468
1469         case DVACT_DEACTIVATE:
1470                 if_deactivate(&sc->sc_ethercom.ec_if);
1471                 break;
1472         }
1473         splx(s);
1474         return (rv);
1475 }
1476
1477 int
1478 cnw_detach(self, flags)
1479         struct device *self;
1480         int flags;
1481 {
1482         struct cnw_softc *sc = (struct cnw_softc *)self;
1483         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1484
1485         /* cnw_disable() checks IFF_DRV_RUNNING */
1486         cnw_disable(sc);
1487
1488         if ((sc->sc_resource & CNW_RES_NET) != 0) {
1489 #if NBPFILTER > 0
1490                 bpfdetach(ifp);
1491 #endif
1492                 ether_ifdetach(ifp);
1493                 if_detach(ifp);
1494         }
1495
1496 #ifndef MEMORY_MAPPED
1497         /* unmap and free our i/o windows */
1498         if ((sc->sc_resource & CNW_RES_IO) != 0) {
1499                 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin);
1500                 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh);
1501         }
1502 #endif
1503
1504         /* unmap and free our memory windows */
1505         if ((sc->sc_resource & CNW_RES_MEM) != 0) {
1506                 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
1507                 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh);
1508         }
1509
1510         return (0);
1511 }
1512 #endif
1513
1514 #if defined(__FreeBSD__)
1515 static void cnw_freebsd_init(xsc)
1516         void    *xsc;
1517 {
1518         struct cnw_softc        *sc = xsc;
1519         struct ifnet *ifp = sc->sc_ifp;
1520         int s;
1521
1522         if (sc->cnw_gone)
1523                 return;
1524
1525         s = splimp();
1526         cnw_init(sc);
1527
1528 #if 0
1529         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1530                 cnw_stop(sc);
1531 #endif
1532
1533         ifp->if_drv_flags |= IFF_DRV_RUNNING;
1534         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1535
1536 /*      sc->cnw_stat_ch = timeout(cnw_inquire, sc, hz * 60); */
1537
1538         cnw_start(ifp);
1539
1540         splx(s);
1541
1542         return;
1543 }
1544
1545 static void cnw_stop(sc)
1546         struct cnw_softc        *sc;
1547 {
1548         struct ifnet            *ifp;
1549
1550         if (sc->cnw_gone)
1551                 return;
1552
1553         cnw_reset(sc);
1554
1555         ifp = sc->sc_ifp;
1556         ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1557
1558         return;
1559 }
1560
1561 static int cnw_pccard_probe(dev)
1562         device_t        dev;
1563 {
1564         struct cnw_softc        *sc;
1565         int             error;
1566
1567         sc = device_get_softc(dev);
1568         sc->cnw_gone = 0;
1569
1570         error = cnw_alloc(dev);
1571         if (error)
1572                 return (error);
1573
1574         device_set_desc(dev, "Netwave AirSurfer Wireless LAN");
1575         cnw_free(dev);
1576
1577         return (0);
1578 }
1579
1580 static int cnw_pccard_detach(dev)
1581         device_t                dev;
1582 {
1583         struct cnw_softc        *sc;
1584         struct ifnet            *ifp;
1585 #if 0
1586         int                     s;
1587
1588         s = splimp();
1589 #endif
1590
1591         sc = device_get_softc(dev);
1592         ifp = sc->sc_ifp;
1593
1594         if (sc->cnw_gone) {
1595                 device_printf(dev, "already unloaded\n");
1596                 return(ENODEV);
1597         }
1598
1599         cnw_stop(sc);
1600
1601         ether_ifdetach(ifp);
1602         cnw_free(dev);
1603         if_free(ifp);
1604         sc->cnw_gone = 1;
1605
1606 #if 0
1607         splx(s);
1608 #endif
1609         return(0);
1610 }
1611
1612 static int cnw_pccard_attach(device_t dev)
1613 {
1614         struct cnw_softc                *sc;
1615         struct ifnet            *ifp;
1616         int                     i, error;
1617         u_char                  eaddr[6];
1618
1619         sc = device_get_softc(dev);
1620         ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
1621         if (ifp == NULL) {
1622                 device_printf(dev, "if_alloc() failed\n");
1623                 return (ENOSPC);
1624         }
1625
1626
1627         error = cnw_alloc(dev);
1628         if (error) {
1629                 device_printf(dev, "cnw_alloc() failed! (%d)\n", error);
1630                 if_free(ifp);
1631                 return (error);
1632         }
1633
1634         error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, NULL,
1635                                cnw_intr, sc, &sc->cnw_intrhand);
1636
1637         if (error) {
1638                 device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
1639                 cnw_free(dev);
1640                 if_free(ifp);
1641                 return (error);
1642         }
1643
1644         /* Set initial values */
1645         sc->sc_domain = cnw_domain;
1646         sc->sc_skey = cnw_skey;
1647
1648         /* Reset the NIC. */
1649         cnw_reset(sc);
1650
1651         /* Get MAC address */
1652         for (i=0; i< ETHER_ADDR_LEN; i++) {
1653                 eaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh,
1654                                 sc->sc_memoff + CNW_EREG_PA + i);
1655         }
1656
1657         ifp->if_softc = sc;
1658         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1659         ifp->if_timer = 0;
1660         ifp->if_mtu = ETHERMTU;
1661         ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST
1662             | IFF_NEEDSGIANT);
1663         ifp->if_ioctl = cnw_ioctl;
1664         ifp->if_start = cnw_start;
1665 /*      ifp->if_watchdog = 0; */
1666         ifp->if_watchdog = cnw_watchdog;
1667         ifp->if_init = cnw_freebsd_init;
1668         ifp->if_baudrate = 1 * 1000* 1000;
1669         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
1670
1671         cnw_freebsd_init(sc);
1672         cnw_stop(sc);
1673
1674         /*
1675          * Call MI attach routine.
1676          */
1677         ether_ifattach(ifp, eaddr);
1678 /*      callout_handle_init(&sc->cnw_stat_ch); */
1679
1680         return(0);
1681 }
1682
1683 static void cnw_shutdown(dev)
1684         device_t                dev;
1685 {
1686         struct cnw_softc        *sc;
1687
1688         sc = device_get_softc(dev);
1689         cnw_stop(sc);
1690
1691         return;
1692 }
1693
1694 static int cnw_alloc(dev)
1695         device_t                dev;
1696 {
1697         struct cnw_softc        *sc = device_get_softc(dev);
1698         int                     rid;
1699         int error;
1700
1701         rid = 0;
1702         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1703                                              RF_ACTIVE);
1704         if (!sc->mem_res) {
1705                 device_printf(dev, "Cannot allocate attribute memory\n");
1706                 return (ENOMEM);
1707         }
1708         sc->sc_memt = rman_get_bustag(sc->mem_res);
1709         sc->sc_memh = rman_get_bushandle(sc->mem_res);
1710
1711
1712         error = CARD_SET_MEMORY_OFFSET(device_get_parent(dev),
1713             dev, rid, CNW_MEM_ADDR, NULL);
1714         if (error) {
1715                 device_printf(dev,
1716                         "CARD_SET_MEMORY_OFFSET returned 0x%0x", error);
1717                 return(error);
1718         }
1719
1720         error = CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
1721                         SYS_RES_MEMORY, rid, PCCARD_A_MEM_8BIT);
1722         if (error) {
1723                 device_printf(dev,
1724                         "CARD_SET_RES_FLAGS returned 0x%0x\n", error);
1725                 return (error);
1726         }
1727
1728         rid = 0;
1729         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1730         if (!sc->irq) {
1731                 device_printf(dev, "No irq?!\n");
1732                 return (ENXIO);
1733         }
1734
1735         sc->dev = dev;
1736         sc->sc_memoff = 0;
1737         
1738         return (0);
1739 }
1740
1741 static void cnw_free(dev)
1742         device_t                dev;
1743 {
1744         struct cnw_softc        *sc = device_get_softc(dev);
1745
1746         if (sc->mem_res != NULL) {
1747                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1748                 sc->mem_res = 0;
1749         }
1750         if (sc->irq != NULL) {
1751                 bus_teardown_intr(dev, sc->irq, sc->cnw_intrhand);
1752                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
1753                 sc->irq = 0;
1754         }
1755
1756         return;
1757 }
1758
1759 #endif /* FreeBSD */