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