Fix typos in the licenses: withough -> without
[dragonfly.git] / sys / dev / netif / wl / if_wl.c
1 /* $FreeBSD: src/sys/i386/isa/if_wl.c,v 1.27.2.2 2000/07/17 21:24:32 archie Exp $ */
2 /* $DragonFly: src/sys/dev/netif/wl/if_wl.c,v 1.34 2008/08/17 04:32:35 sephe Exp $ */
3 /* 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain all copyright 
8  *    notices, this list of conditions and the following disclaimer.
9  * 2. The names of the authors may not be used to endorse or promote products
10  *    derived from this software without specific prior written permission
11  *
12  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
13  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  * 
23  */
24 /*
25  * if_wl.c - original MACH, then BSDI ISA wavelan driver
26  *      ported to mach by Anders Klemets
27  *      to BSDI by Robert Morris
28  *      to FreeBSD by Jim Binkley
29  *      to FreeBSD 2.2+ by Michael Smith
30  *
31  * 2.2 update:
32  * Changed interface to match 2.1-2.2 differences.
33  * Implement IRQ selection logic in wlprobe()
34  * Implement PSA updating.
35  * Pruned heading comments for relevance.
36  * Ripped out all the 'interface counters' cruft.
37  * Cut the missing-interrupt timer back to 100ms.
38  * 2.2.1 update:
39  * now supports all multicast mode (mrouted will work),
40  *      but unfortunately must do that by going into promiscuous mode
41  * NWID sysctl added so that normally promiscuous mode is NWID-specific
42  *      but can be made NWID-inspecific
43  *                      7/14/97 jrb
44  *
45  * Work done:
46  * Ported to FreeBSD, got promiscuous mode working with bpfs,
47  * and rewired timer routine.  The i82586 will hang occasionally on output 
48  * and the watchdog timer will kick it if so and log an entry.
49  * 2 second timeout there.  Apparently the chip loses an interrupt.
50  * Code borrowed from if_ie.c for watchdog timer.
51  *
52  * The wavelan card is a 2mbit radio modem that emulates ethernet;
53  * i.e., it uses MAC addresses.  This should not be a surprise since
54  * it uses an ethernet controller as a major hw item.
55  * It can broadcast, unicast or apparently multicast in a base cell 
56  * using a omni-directional antennae that is 
57  * about 800 feet around the base cell barring walls and metal.  
58  * With directional antennae, it can be used point to point over a mile
59  * or so apparently (haven't tried that).
60  *
61  * There are ISA and pcmcia versions (not supported by this code).
62  * The ISA card has an Intel 82586 lan controller on it.  It consists
63  * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
64  * The latter has an extra set of controller registers that has nothing
65  * to do with the i82586 and allows setting and monitoring of radio
66  * signal strength, etc.  There is a nvram area called the PSA that
67  * contains a number of setup variables including the IRQ and so-called
68  * NWID or Network ID.  The NWID must be set the same for all radio
69  * cards to communicate (unless you are using the ATT/NCR roaming feature
70  * with their access points.  There is no support for that here. Roaming
71  * involves a link-layer beacon sent out from the access points.  End
72  * stations monitor the signal strength and only use the strongest
73  * access point).  This driver assumes that the base ISA port, IRQ, 
74  * and NWID are first set in nvram via the dos-side "instconf.exe" utility 
75  * supplied with the card. This driver takes the ISA port from 
76  * the kernel configuration setup, and then determines the IRQ either 
77  * from the kernel config (if an explicit IRQ is set) or from the 
78  * PSA on the card if not.
79  * The hw also magically just uses the IRQ set in the nvram.
80  * The NWID is used magically as well by the radio-modem
81  * to determine which packets to keep or throw out.  
82  *
83  * sample config:
84  *
85  * device wl0 at isa? port 0x300 net irq ?
86  *
87  * Ifdefs:
88  * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
89  * 2. MULTICAST (on) - turned on and works up to and including mrouted
90  * 3. WLCACHE (off) -  define to turn on a signal strength 
91  * (and other metric) cache that is indexed by sender MAC address.  
92  * Apps can read this out to learn the remote signal strength of a 
93  * sender.  Note that it has a switch so that it only stores 
94  * broadcast/multicast senders but it could be set to store unicast 
95  * too only.  Size is hardwired in if_wl_wavelan.h
96  *
97  * one further note: promiscuous mode is a curious thing.  In this driver,
98  * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
99  * setting.  This is probably more useful in a sense (for snoopers) if
100  * you are interested in all traffic as opposed to if you are interested
101  * in just your own.  There is a driver specific sysctl to turn promiscuous
102  * from just promiscuous to wildly promiscuous...
103  *
104  * This driver also knows how to load the synthesizers in the 2.4 Gz
105  * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
106  * This product consists of a "mothercard" that contains the 82586,
107  * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC. 
108  * The radio transceiver is a "daughtercard" called the WaveMODEM which
109  * connects to the mothercard through two single-inline connectors: a
110  * 20-pin connector provides DC-power and modem signals, and a 3-pin
111  * connector which exports the antenna connection. The code herein
112  * loads the receive and transmit synthesizers and the corresponding
113  * transmitter output power value from an EEPROM controlled through
114  * additional registers via the MMC. The EEPROM address selected
115  * are those whose values are preset by the DOS utility programs
116  * provided with the product, and this provides compatible operation
117  * with the DOS Packet Driver software. A future modification will
118  * add the necessary functionality to this driver and to the wlconfig
119  * utility to completely replace the DOS Configuration Utilities.
120  * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
121  * and is available through Lucent Technologies OEM supply channels.
122  * --RAB 1997/06/08.
123  */
124
125 #define MULTICAST  1
126
127 /* 
128  *      Olivetti PC586 Mach Ethernet driver v1.0
129  *      Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130  *      All rights reserved.
131  *
132  */ 
133
134 /*
135   Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136 Cupertino, California.
137
138                 All Rights Reserved
139
140   Permission to use, copy, modify, and distribute this software and
141 its documentation for any purpose and without fee is hereby
142 granted, provided that the above copyright notice appears in all
143 copies and that both the copyright notice and this permission notice
144 appear in supporting documentation, and that the name of Olivetti
145 not be used in advertising or publicity pertaining to distribution
146 of the software without specific, written prior permission.
147
148   OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
155 */
156
157 /*
158   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
159
160                 All Rights Reserved
161
162 Permission to use, copy, modify, and distribute this software and
163 its documentation for any purpose and without fee is hereby
164 granted, provided that the above copyright notice appears in all
165 copies and that both the copyright notice and this permission notice
166 appear in supporting documentation, and that the name of Intel
167 not be used in advertising or publicity pertaining to distribution
168 of the software without specific, written prior permission.
169
170 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177 */
178
179 /*
180  * NOTE:
181  *              by rvb:
182  *  1.  The best book on the 82586 is:
183  *              LAN Components User's Manual by Intel
184  *      The copy I found was dated 1984.  This really tells you
185  *      what the state machines are doing
186  *  2.  In the current design, we only do one write at a time,
187  *      though the hardware is capable of chaining and possibly
188  *      even batching.  The problem is that we only make one
189  *      transmit buffer available in sram space.
190  */
191
192 #include "opt_wavelan.h"
193 #include "opt_inet.h"
194
195 #include <sys/param.h>
196 #include <sys/systm.h>
197 #include <sys/kernel.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
203 #include <sys/priv.h>
204 #include <sys/serialize.h>
205 #include <sys/sysctl.h>
206 #include <sys/bus.h>
207 #include <sys/rman.h>
208 #include <sys/thread2.h>
209 #include <sys/interrupt.h>
210
211 #include <net/ethernet.h>
212 #include <net/if.h>
213 #include <net/if_arp.h>
214 #include <net/ifq_var.h>
215 #include <net/if_dl.h>
216
217 #ifdef INET
218 #include <netinet/in.h>
219 #include <netinet/in_systm.h>
220 #include <netinet/ip.h>
221 #include <netinet/if_ether.h>
222 #endif
223
224 #include <net/bpf.h>
225
226 #include <bus/isa/isavar.h>
227 #include <bus/isa/isa_device.h>
228 #include "if_wl_i82586.h"       /* Definitions for the Intel chip */
229
230 /* was 1000 in original, fed to DELAY(x) */
231 #define DELAYCONST      1000
232 #include "if_wl.h"
233 #include <machine/if_wl_wavelan.h>
234
235 static char     t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
236
237 struct wl_softc{ 
238     struct      arpcom  wl_ac;                  /* Ethernet common part */
239 #define wl_if   wl_ac.ac_if                     /* network visible interface */
240 #define wl_addr wl_ac.ac_enaddr                 /* hardware address */
241     u_char      psa[0x40];
242     u_char      nwid[2];        /* current radio modem nwid */
243     short       base;
244     int         flags;
245     int         tbusy;          /* flag to determine if xmit is busy */
246     u_short     begin_fd;
247     u_short     end_fd;
248     u_short     end_rbd;
249     u_short     hacr;           /* latest host adapter CR command */
250     short       mode;
251     u_char      chan24;         /* 2.4 Gz: channel number/EEPROM Area # */
252     u_short     freq24;         /* 2.4 Gz: resulting frequency  */
253     int         rid_ioport;
254     int         rid_irq;
255     struct      resource *res_ioport;
256     struct      resource *res_irq;
257     void        *intr_handle;
258     struct      callout watchdog_ch;
259 #ifdef WLCACHE
260     int         w_sigitems;     /* number of cached entries */
261     /*  array of cache entries */
262     struct w_sigcache w_sigcache[ MAXCACHEITEMS ];            
263     int w_nextcache;            /* next free cache entry */    
264     int w_wrapindex;            /* next "free" cache entry */
265 #endif
266 };
267
268 /*
269  * XXX  The Wavelan appears to be prone to dropping stuff if you talk to
270  * it too fast.  This disgusting hack inserts a delay after each packet
271  * is queued which helps avoid this behaviour on fast systems.
272  */
273 static int      wl_xmit_delay = 250;
274 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
275
276 /* 
277  * not XXX, but ZZZ (bizarre).
278  * promiscuous mode can be toggled to ignore NWIDs.  By default,
279  * it does not.  Caution should be exercised about combining
280  * this mode with IFF_ALLMULTI which puts this driver in
281  * promiscuous mode.
282  */
283 static int      wl_ignore_nwid = 0;
284 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
285
286 /*
287  * Emit diagnostics about transmission problems
288  */
289 static int      xmt_watch = 0;
290 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
291
292 /*
293  * Collect SNR statistics
294  */
295 static int      gathersnr = 0;
296 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
297
298 static int      wlprobe(device_t);
299 static int      wlattach(device_t);
300 static int      wldetach(device_t);
301 static int      wl_alloc_resources(device_t);
302 static void     wl_free_resources(device_t);
303 static void     wlstart(struct ifnet *);
304 static void     wlinit(void *);
305 static int      wlioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
306 static timeout_t wlwatchdog;
307 static void     wlintr(void *);
308 static void     wlxmt(struct wl_softc *, struct mbuf *);
309 static int      wldiag(struct wl_softc *); 
310 static int      wlconfig(struct wl_softc *); 
311 static int      wlcmd(struct wl_softc *, const char *);
312 static void     wlmmcstat(struct wl_softc *);
313 static u_short  wlbldru(struct wl_softc *);
314 static u_short  wlmmcread(u_int, u_short);
315 static void     wlinitmmc(struct wl_softc *);
316 static int      wlhwrst(struct wl_softc *);
317 static void     wlrustrt(struct wl_softc *);
318 static void     wlbldcu(struct wl_softc *);
319 static int      wlack(struct wl_softc *);
320 static int      wlread(struct wl_softc *, u_short);
321 static void     getsnr(struct wl_softc *);
322 static void     wlrcv(struct wl_softc *);
323 static int      wlrequeue(struct wl_softc *, u_short);
324 static void     wlsftwsleaze(u_short *, u_char **, struct mbuf **);
325 static void     wlhdwsleaze(u_short *, u_char **, struct mbuf **);
326 static void     wltbd(struct wl_softc *);
327 static void     wlgetpsa(int, u_char *);
328 static void     wlsetpsa(struct wl_softc *);
329 static u_short  wlpsacrc(u_char *);
330 static void     wldump(struct wl_softc *);
331 #ifdef WLCACHE
332 static void     wl_cache_store(struct wl_softc *, int, struct ether_header *,
333                                struct mbuf *);
334 static void     wl_cache_zero(struct wl_softc *);
335 #endif
336 #ifdef MULTICAST
337 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
338 static int      check_allmulti(struct wl_softc *);
339 # endif
340 #endif
341
342 static device_method_t wl_methods[] = {
343         DEVMETHOD(device_probe,         wlprobe),
344         DEVMETHOD(device_attach,        wlattach),
345         DEVMETHOD(device_detach,        wldetach),
346         { 0, 0 }
347 };
348
349 static driver_t wl_driver = {
350         "wl",
351         wl_methods,
352         sizeof(struct wl_softc)
353 };
354
355 devclass_t wl_devclass;
356 DECLARE_DUMMY_MODULE(if_wl);
357 DRIVER_MODULE(wl, isa, wl_driver, wl_devclass, 0, 0);
358 MODULE_DEPEND(wl, isa, 1, 1, 1);
359
360 static struct isa_pnp_id wl_ids[] = {
361         { 0, NULL }
362 };
363
364 /* array for maping irq numbers to values for the irq parameter register */
365 static int irqvals[16] = { 
366     0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 
367 };
368
369 /*
370  * wlprobe:
371  *
372  *      This function "probes" or checks for the WaveLAN board on the bus to
373  *      see if it is there.  As far as I can tell, the best break between this
374  *      routine and the attach code is to simply determine whether the board
375  *      is configured in properly.  Currently my approach to this is to write
376  *      and read a word from the SRAM on the board being probed.  If the word
377  *      comes back properly then we assume the board is there.  The config
378  *      code expects to see a successful return from the probe routine before
379  *      attach will be called.
380  */
381 static int
382 wlprobe(device_t dev)
383 {
384     struct wl_softc     *sc;
385     short               base;
386     const char          *str = "wl%d: board out of range [0..%d]\n";
387     u_char              inbuf[100];
388     int                 irq, error;
389
390     error = ISA_PNP_PROBE(device_get_parent(dev), dev, wl_ids);
391     if (error == ENXIO || error == 0)
392         return (error);
393
394     sc = device_get_softc(dev);
395     error = wl_alloc_resources(dev);
396     if (error)
397         return error;
398
399     base = rman_get_start(sc->res_ioport);
400
401     /* TBD. not true.
402      * regular CMD() will not work, since no softc yet 
403      */
404 #define PCMD(base, hacr) outw((base), (hacr))
405
406     PCMD(base, HACR_RESET);                     /* reset the board */
407     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
408     PCMD(base, HACR_RESET);                     /* reset the board */
409     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
410
411     /* clear reset command and set PIO#1 in autoincrement mode */
412     PCMD(base, HACR_DEFAULT);
413     PCMD(base, HACR_DEFAULT);
414     outw(PIOR1(base), 0);                       /* go to beginning of RAM */
415     outsw(PIOP1(base), str, strlen(str)/2+1);   /* write string */
416     
417     outw(PIOR1(base), 0);                       /* rewind */
418     insw(PIOP1(base), inbuf, strlen(str)/2+1);  /* read result */
419     
420     if (bcmp(str, inbuf, strlen(str))) {
421         error = ENXIO;
422         goto fail;
423     }
424
425     sc->chan24 = 0;                             /* 2.4 Gz: config channel */
426     sc->freq24 = 0;                             /* 2.4 Gz: frequency    */
427
428     /* read the PSA from the board into temporary storage */
429     wlgetpsa(base, inbuf);
430
431     /* We read the IRQ value from the PSA on the board. */
432     for (irq = 15; irq >= 0; irq--)
433         if (irqvals[irq] == inbuf[WLPSA_IRQNO])
434             break;
435     if ((irq == 0) || (irqvals[irq] == 0)){
436         device_printf(dev, "PSA corrupt (invalid IRQ value)\n");
437     } else {
438         u_long sirq, dummy;
439
440         /*
441          * If the IRQ requested by the PSA is already claimed by another
442          * device, the board won't work, but the user can still access the
443          * driver to change the IRQ.
444          */
445         if (bus_get_resource(dev, SYS_RES_IRQ, 0, &sirq, &dummy))
446             goto fail;
447         if (irq != (int)sirq)
448             device_printf(dev, "board is configured for interrupt %d\n", irq);
449     }
450     error = 0;
451
452 fail:
453     wl_free_resources(dev);
454     return (error);
455 }
456
457 /*
458  * wlattach:
459  *
460  *      This function attaches a WaveLAN board to the "system".  The rest of
461  *      runtime structures are initialized here (this routine is called after
462  *      a successful probe of the board).  Once the ethernet address is read
463  *      and stored, the board's ifnet structure is attached and readied.
464  */
465 static int
466 wlattach(device_t dev)
467 {
468     struct wl_softc     *sc;
469     short               base;
470     int                 i, j, error;
471     struct ifnet        *ifp;
472
473     sc = device_get_softc(dev);
474
475     ifp = &sc->wl_if;
476     if_initname(ifp, device_get_name(dev), device_get_unit(dev));
477
478     error = wl_alloc_resources(dev);
479     if (error)
480         return error;
481
482     base = rman_get_start(sc->res_ioport);
483
484 #ifdef WLDEBUG
485     device_printf(dev, "%s: base %x, unit %d\n",
486                   __func__, base, device_get_unit(dev));
487 #endif
488
489     sc->base = base;
490     sc->flags = 0;
491     sc->mode = 0;
492     sc->hacr = HACR_RESET;
493     callout_init(&sc->watchdog_ch);
494     CMD(sc);                            /* reset the board */
495     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
496         
497     /* clear reset command and set PIO#2 in parameter access mode */
498     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
499     CMD(sc);
500
501     /* Read the PSA from the board for our later reference */
502     wlgetpsa(base, sc->psa);
503
504     /* fetch NWID */
505     sc->nwid[0] = sc->psa[WLPSA_NWID];
506     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
507     
508     /* fetch MAC address - decide which one first */
509     if (sc->psa[WLPSA_MACSEL] & 1) {
510         j = WLPSA_LOCALMAC;
511     } else {
512         j = WLPSA_UNIMAC;
513     }
514     for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
515         sc->wl_addr[i] = sc->psa[j + i];
516     }
517
518     /* enter normal 16 bit mode operation */
519     sc->hacr = HACR_DEFAULT;
520     CMD(sc);
521
522     wlinitmmc(sc);
523     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
524     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
525     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
526     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
527     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
528
529     ifp->if_softc = sc;
530     ifp->if_mtu = WAVELAN_MTU;
531     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
532 #ifdef    WLDEBUG
533     ifp->if_flags |= IFF_DEBUG;
534 #endif
535 #if     MULTICAST
536     ifp->if_flags |= IFF_MULTICAST;
537 #endif  /* MULTICAST */
538     ifp->if_init = wlinit;
539     ifp->if_start = wlstart;
540     ifp->if_ioctl = wlioctl;
541     ifp->if_timer = 0;   /* paranoia */
542     /* no entries
543        ifp->if_watchdog
544        ifp->if_done
545        ifp->if_reset
546        */
547     ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
548     ifq_set_ready(&ifp->if_snd);
549     ether_ifattach(ifp, sc->wl_ac.ac_enaddr, NULL);
550
551     if (sc->freq24) 
552         kprintf(", Freq %d MHz",sc->freq24);            /* 2.4 Gz       */
553     kprintf("\n");                                       /* 2.4 Gz       */
554
555     error = bus_setup_intr(dev, sc->res_irq, INTR_MPSAFE,
556                            wlintr, sc, &sc->intr_handle, 
557                            ifp->if_serializer);
558     if (error) {
559         device_printf(dev, "setup irq fail!\n");
560         ether_ifdetach(ifp);
561         wl_free_resources(dev);
562         return error;
563     }
564
565     ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->res_irq));
566     KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
567
568     if (bootverbose)
569         wldump(sc);
570     return 0;
571 }
572
573 static int
574 wldetach(device_t dev)
575 {
576     struct wl_softc *sc = device_get_softc(dev);
577     device_t parent = device_get_parent(dev);
578     struct ifnet *ifp = &sc->wl_if;
579
580     lwkt_serialize_enter(ifp->if_serializer);
581
582     /* reset the board */
583     sc->hacr = HACR_RESET;
584     CMD(sc);
585     sc->hacr = HACR_DEFAULT;
586     CMD(sc);
587
588     if (sc->intr_handle != NULL) {
589         BUS_TEARDOWN_INTR(parent, dev, sc->res_irq, sc->intr_handle);
590         sc->intr_handle = NULL;
591     }
592
593     lwkt_serialize_exit(ifp->if_serializer);
594
595     ether_ifdetach(ifp);
596     bus_generic_detach(dev);
597     wl_free_resources(dev);
598
599     return (0);
600 }
601
602 static int
603 wl_alloc_resources(device_t dev)
604 {
605     struct wl_softc *sc = device_get_softc(dev);
606     int ports = 16;             /* Number of ports */
607
608     sc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
609         &sc->rid_ioport, 0ul, ~0ul, ports, RF_ACTIVE);
610     if (sc->res_ioport == NULL)
611         goto fail;
612
613     sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
614         &sc->rid_irq, RF_SHAREABLE | RF_ACTIVE);
615     if (sc->res_irq == NULL)
616         goto fail;
617     return (0);
618
619 fail:
620     wl_free_resources(dev);
621     return (ENXIO);
622 }
623
624 static void
625 wl_free_resources(device_t dev)
626 {
627     struct wl_softc *sc = device_get_softc(dev);
628
629     if (sc->res_irq != 0) {
630         bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
631         bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
632         sc->res_irq = 0;
633     }
634     if (sc->res_ioport != 0) {
635         bus_deactivate_resource(dev, SYS_RES_IOPORT,
636             sc->rid_ioport, sc->res_ioport);
637         bus_release_resource(dev, SYS_RES_IOPORT,
638             sc->rid_ioport, sc->res_ioport);
639         sc->res_ioport = 0;
640     }
641 }
642
643 /*
644  * Print out interesting information about the 82596.
645  */
646 static void
647 wldump(struct wl_softc *sc)
648 {
649     int         base = sc->base;
650     int         i;
651         
652     if_printf(&sc->wl_if, "hasr %04x\n", inw(HASR(base)));
653         
654     if_printf(&sc->wl_if, "scb at %04x:\n ", OFFSET_SCB);
655     outw(PIOR1(base), OFFSET_SCB);
656     for(i = 0; i < 8; i++)
657         kprintf("%04x ", inw(PIOP1(base)));
658     kprintf("\n");
659         
660     if_printf(&sc->wl_if, "cu at %04x:\n ", OFFSET_CU);
661     outw(PIOR1(base), OFFSET_CU);
662     for(i = 0; i < 8; i++)
663         kprintf("%04x ", inw(PIOP1(base)));
664     kprintf("\n");
665         
666     if_printf(&sc->wl_if, "tbd at %04x:\n ", OFFSET_TBD);
667     outw(PIOR1(base), OFFSET_TBD);
668     for(i = 0; i < 4; i++)
669         kprintf("%04x ", inw(PIOP1(base)));
670     kprintf("\n");
671 }
672
673 /* Initialize the Modem Management Controller */
674 static void
675 wlinitmmc(struct wl_softc *sc)
676 {
677     int         base = sc->base;
678     int         configured;
679     int         mode = sc->mode;
680     int         i;                              /* 2.4 Gz               */
681         
682     /* enter 8 bit operation */
683     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
684     CMD(sc);
685
686     configured = sc->psa[WLPSA_CONFIGURED] & 1;
687         
688     /*
689      * Set default modem control parameters.  Taken from NCR document
690      *  407-0024326 Rev. A 
691      */
692     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
693     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
694     MMC_WRITE(MMC_IFS, 0x20);
695     MMC_WRITE(MMC_MOD_DELAY, 0x04);
696     MMC_WRITE(MMC_JAM_TIME, 0x38);
697     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
698     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
699     if (!configured) {
700         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
701         if (sc->psa[WLPSA_COMPATNO] & 1) {
702             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
703         } else {
704             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
705         }
706         MMC_WRITE(MMC_QUALITY_THR, 0x03);
707     } else {
708         /* use configuration defaults from parameter storage area */
709         if (sc->psa[WLPSA_NWIDENABLE] & 1) {
710             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
711                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
712             } else {
713                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
714             }
715         } else {
716             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
717         }
718         MMC_WRITE(MMC_THR_PRE_SET, sc->psa[WLPSA_THRESH]);
719         MMC_WRITE(MMC_QUALITY_THR, sc->psa[WLPSA_QUALTHRESH]);
720     }
721     MMC_WRITE(MMC_FREEZE, 0x00);
722     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
723
724     MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);       /* set NWID */
725     MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
726
727     /* enter normal 16 bit mode operation */
728     sc->hacr = HACR_DEFAULT;
729     CMD(sc);
730     CMD(sc);                                    /* virtualpc1 needs this! */
731
732     if (sc->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
733                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
734         i=sc->chan24<<4;                        /* 2.4 Gz: position ch #     */
735         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
736         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
737                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
738         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
739             DELAY(40);                          /* 2.4 Gz             */
740             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
741                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
742                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
743                 break;                          /* 2.4 Gz: download finished */
744         }                                       /* 2.4 Gz                    */
745         if (i==1000) {
746             if_printf(&sc->wl_if,
747                       "synth load failed\n");   /* 2.4 Gz       */
748         }
749         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
750         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
751                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
752         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
753             DELAY(40);                          /* 2.4 Gz             */
754             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
755                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
756                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
757                 break;                          /* 2.4 Gz: download finished */
758         }                                       /* 2.4 Gz                    */
759         if (i==1000) {
760             if_printf(&sc->wl_if,
761                       "xmit pwr load failed\n");/* 2.4 Gz            */
762         }
763         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
764                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
765                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
766         i=sc->chan24<<4;                        /* 2.4 Gz: position ch #     */
767         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
768         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
769                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
770         DELAY(40);                              /* 2.4 Gz                    */
771         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
772           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
773         sc->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
774     }
775 }
776
777 /*
778  * wlinit:
779  *
780  *      Another routine that interfaces the "if" layer to this driver.  
781  *      Simply resets the structures that are used by "upper layers".  
782  *      As well as calling wlhwrst that does reset the WaveLAN board.
783  *
784  * input        : softc pointer for this interface
785  * output       : structures (if structs) and board are reset
786  *
787  */     
788 static void
789 wlinit(void *xsc)
790 {
791     struct wl_softc *sc = xsc;
792     struct ifnet        *ifp = &sc->wl_if;
793
794 #ifdef WLDEBUG
795     if (ifp->if_flags & IFF_DEBUG)
796         if_printf(ifp, "entered wlinit()\n");
797 #endif
798     if (wlhwrst(sc) == TRUE) {
799         ifp->if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
800         /* 
801          * OACTIVE is used by upper-level routines
802          * and must be set
803          */
804         ifp->if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
805                 
806         sc->flags |= DSF_RUNNING;
807         sc->tbusy = 0;
808         callout_stop(&sc->watchdog_ch);
809                 
810         if_devstart(ifp);
811     } else {
812         if_printf(ifp, "init(): trouble resetting board.\n");
813     }
814 }
815
816 /*
817  * wlhwrst:
818  *
819  *      This routine resets the WaveLAN board that corresponds to the 
820  *      board number passed in.
821  *
822  * input        : softc pointer for this interface
823  * output       : board is reset
824  *
825  */
826 static int
827 wlhwrst(struct wl_softc *sc)
828 {
829 #ifdef WLDEBUG
830     if (sc->wl_if.if_flags & IFF_DEBUG)
831         if_printf(&sc->wl_if, "entered wlhwrst()\n");
832 #endif
833     sc->hacr = HACR_RESET;
834     CMD(sc);                    /* reset the board */
835         
836     /* clear reset command and set PIO#1 in autoincrement mode */
837     sc->hacr = HACR_DEFAULT;
838     CMD(sc);
839
840 #ifdef  WLDEBUG
841     if (sc->wl_if.if_flags & IFF_DEBUG)
842         wlmmcstat(sc);          /* Display MMC registers */
843 #endif  /* WLDEBUG */
844     wlbldcu(sc);                /* set up command unit structures */
845     
846     if (wldiag(sc) == 0)
847         return(0);
848     
849     if (wlconfig(sc) == 0)
850             return(0);
851     /* 
852      * insert code for loopback test here
853      */
854     wlrustrt(sc);               /* start receive unit */
855
856     /* enable interrupts */
857     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
858     CMD(sc);
859     
860     return(1);
861 }
862
863 /*
864  * wlbldcu:
865  *
866  *      This function builds up the command unit structures.  It inits
867  *      the scp, iscp, scb, cb, tbd, and tbuf.
868  *
869  */
870 static void
871 wlbldcu(struct wl_softc *sc)
872 {
873     short               base = sc->base;
874     scp_t               scp;
875     iscp_t              iscp;
876     scb_t               scb;
877     ac_t                cb;
878     tbd_t               tbd;
879     int         i;
880
881     bzero(&scp, sizeof(scp));
882     scp.scp_sysbus = 0;
883     scp.scp_iscp = OFFSET_ISCP;
884     scp.scp_iscp_base = 0;
885     outw(PIOR1(base), OFFSET_SCP);
886     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
887
888     bzero(&iscp, sizeof(iscp));
889     iscp.iscp_busy = 1;
890     iscp.iscp_scb_offset = OFFSET_SCB;
891     iscp.iscp_scb = 0;
892     iscp.iscp_scb_base = 0;
893     outw(PIOR1(base), OFFSET_ISCP);
894     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
895
896     scb.scb_status = 0;
897     scb.scb_command = SCB_RESET;
898     scb.scb_cbl_offset = OFFSET_CU;
899     scb.scb_rfa_offset = OFFSET_RU;
900     scb.scb_crcerrs = 0;
901     scb.scb_alnerrs = 0;
902     scb.scb_rscerrs = 0;
903     scb.scb_ovrnerrs = 0;
904     outw(PIOR1(base), OFFSET_SCB);
905     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
906
907     SET_CHAN_ATTN(sc);
908
909     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
910     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
911     if (i <= 0) if_printf(&sc->wl_if, "bldcu(): iscp_busy timeout.\n");
912     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
913     for (i = STATUS_TRIES; i-- > 0; ) {
914         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
915             break;
916     }
917     if (i <= 0)
918         if_printf(&sc->wl_if, "bldcu(): not ready after reset.\n");
919     wlack(sc);
920
921     cb.ac_status = 0;
922     cb.ac_command = AC_CW_EL;           /* NOP */
923     cb.ac_link_offset = OFFSET_CU;
924     outw(PIOR1(base), OFFSET_CU);
925     outsw(PIOP1(base), &cb, 6/2);
926
927     tbd.act_count = 0;
928     tbd.next_tbd_offset = I82586NULL;
929     tbd.buffer_addr = 0;
930     tbd.buffer_base = 0;
931     outw(PIOR1(base), OFFSET_TBD);
932     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
933 }
934
935 /*
936  * wlstart:
937  *
938  *      send a packet
939  *
940  * input        : pointer the appropriate "if" struct
941  * output       : stuff sent to board if any there
942  *
943  */
944 static void
945 wlstart(struct ifnet *ifp)
946 {
947     struct mbuf                 *m;
948     struct wl_softc     *sc = ifp->if_softc;
949     short                       base = sc->base;
950     int                         scb_status, cu_status, scb_command;
951
952 #ifdef WLDEBUG
953     if (ifp->if_flags & IFF_DEBUG)
954         if_printf(ifp, "entered wlstart()\n");
955 #endif
956
957     outw(PIOR1(base), OFFSET_CU);
958     cu_status = inw(PIOP1(base));
959     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
960     scb_status = inw(PIOP0(base));
961     outw(PIOR0(base), OFFSET_SCB + 2);
962     scb_command = inw(PIOP0(base));
963
964     /*
965      * don't need OACTIVE check as tbusy here checks to see
966      * if we are already busy 
967      */
968     if (sc->tbusy) {
969         if((scb_status & 0x0700) == SCB_CUS_IDLE &&
970            (cu_status & AC_SW_B) == 0){
971             sc->tbusy = 0;
972             callout_stop(&sc->watchdog_ch);
973             ifp->if_flags &= ~IFF_OACTIVE;
974             /*
975              * This is probably just a race.  The xmt'r is just
976              * became idle but WE have masked interrupts so ...
977              */
978 #ifdef WLDEBUG
979             if_printf(ifp, "CU idle, scb %04x %04x cu %04x\n",
980                       scb_status, scb_command, cu_status);
981 #endif 
982             if (xmt_watch) if_printf(ifp, "!!\n");
983         } else {
984             return;     /* genuinely still busy */
985         }
986     } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
987               (cu_status & AC_SW_B)){
988 #ifdef WLDEBUG
989         if_printf(ifp, "CU unexpectedly busy; scb %04x cu %04x\n",
990                   scb_status, cu_status);
991 #endif
992         if (xmt_watch) if_printf(ifp, "busy?!");
993         return;         /* hey, why are we busy? */
994     }
995
996     /* get ourselves some data */
997     ifp = &(sc->wl_if);
998     m = ifq_dequeue(&ifp->if_snd, NULL);
999     if (m != NULL) {
1000         BPF_MTAP(ifp, m);
1001         sc->tbusy++;
1002         /* set the watchdog timer so that if the board
1003          * fails to interrupt we will restart
1004          */
1005         /* try 10 ticks, not very long */
1006         callout_reset(&sc->watchdog_ch, 10, wlwatchdog, sc);
1007         ifp->if_flags |= IFF_OACTIVE;
1008         ifp->if_opackets++;
1009         wlxmt(sc, m);
1010     } else {
1011         ifp->if_flags &= ~IFF_OACTIVE;
1012     }
1013 }
1014
1015 /*
1016  * wlread:
1017  *
1018  *      This routine does the actual copy of data (including ethernet header
1019  *      structure) from the WaveLAN to an mbuf chain that will be passed up
1020  *      to the "if" (network interface) layer.  NOTE:  we currently
1021  *      don't handle trailer protocols, so if that is needed, it will
1022  *      (at least in part) be added here.  For simplicities sake, this
1023  *      routine copies the receive buffers from the board into a local (stack)
1024  *      buffer until the frame has been copied from the board.  Once in
1025  *      the local buffer, the contents are copied to an mbuf chain that
1026  *      is then enqueued onto the appropriate "if" queue.
1027  *
1028  * input        : softc pointer for this interface and
1029  *                an frame descriptor address
1030  * output       : the packet is put into an mbuf chain, and passed up
1031  * assumes      : if any errors occur, packet is "dropped on the floor"
1032  *
1033  */
1034 static int
1035 wlread(struct wl_softc *sc, u_short fd_p)
1036 {
1037     struct ifnet        *ifp = &sc->wl_if;
1038     short                       base = sc->base;
1039     fd_t                        fd;
1040     struct ether_header         eh;
1041     struct mbuf                 *m, *tm;
1042     rbd_t                       rbd;
1043     u_char                      *mb_p;
1044     u_short                     mlen, len, clen;
1045     u_short                     bytes_in_msg, bytes_in_mbuf, bytes;
1046
1047
1048 #ifdef WLDEBUG
1049     if (ifp->if_flags & IFF_DEBUG)
1050         if_printf(ifp, "entered wlread()\n");
1051 #endif
1052     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
1053         if_printf(ifp, "read(): board is not running.\n");
1054         sc->hacr &= ~HACR_INTRON;
1055         CMD(sc);                /* turn off interrupts */
1056     }
1057     /* read ether_header info out of device memory. doesn't
1058      * go into mbuf.  goes directly into eh structure
1059      */
1060     len = sizeof(struct ether_header);  /* 14 bytes */
1061     outw(PIOR1(base), fd_p);
1062     insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
1063     insw(PIOP1(base), &eh, (len-2)/2);
1064     eh.ether_type = ntohs(inw(PIOP1(base)));
1065 #ifdef WLDEBUG
1066     if (ifp->if_flags & IFF_DEBUG)
1067         if_printf(ifp, "wlread: rcv packet, type is %x\n", eh.ether_type);
1068 #endif 
1069     /*
1070      * WARNING.  above is done now in ether_input, above may be
1071      * useful for debug. jrb
1072      */
1073     eh.ether_type = htons(eh.ether_type);
1074
1075     if (fd.rbd_offset == I82586NULL) {
1076         if_printf(ifp, "read(): Invalid buffer\n");
1077         if (wlhwrst(sc) != TRUE)
1078             if_printf(ifp, "read(): hwrst trouble.\n");
1079         return 0;
1080     }
1081
1082     outw(PIOR1(base), fd.rbd_offset);
1083     insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1084     bytes_in_msg = rbd.status & RBD_SW_COUNT;
1085     MGETHDR(m, MB_DONTWAIT, MT_DATA);
1086     tm = m;
1087     if (m == NULL) {
1088         /*
1089          * not only do we want to return, we need to drop the packet on
1090          * the floor to clear the interrupt.
1091          *
1092          */
1093         if (wlhwrst(sc) != TRUE) {
1094             sc->hacr &= ~HACR_INTRON;
1095             CMD(sc);            /* turn off interrupts */
1096             if_printf(ifp, "read(): hwrst trouble.\n");
1097         }
1098         return 0;
1099     }
1100     m->m_next = NULL;
1101     m->m_pkthdr.rcvif = ifp;
1102     m->m_pkthdr.len = 0; /* don't know this yet */
1103     m->m_len = MHLEN;
1104
1105     /* always use a cluster. jrb 
1106      */
1107     MCLGET(m, MB_DONTWAIT);
1108     if (m->m_flags & M_EXT) {
1109         m->m_len = MCLBYTES;
1110     }
1111     else {
1112         m_freem(m);
1113         if (wlhwrst(sc) != TRUE) {
1114             sc->hacr &= ~HACR_INTRON;
1115             CMD(sc);            /* turn off interrupts */
1116             if_printf(ifp, "read(): hwrst trouble.\n");
1117         }
1118         return 0;
1119     }
1120
1121     mlen = 0;
1122     clen = mlen;
1123     bytes_in_mbuf = m->m_len - sizeof(eh);
1124     mb_p = mtod(tm, u_char *);
1125     bytes = min(bytes_in_mbuf, bytes_in_msg);
1126     bcopy(&eh, mb_p, sizeof(eh));
1127     mb_p += sizeof(eh);
1128     for (;;) {
1129         if (bytes & 1) {
1130             len = bytes + 1;
1131         } else {
1132             len = bytes;
1133         }
1134         outw(PIOR1(base), rbd.buffer_addr);
1135         insw(PIOP1(base), mb_p, len/2);
1136         clen += bytes;
1137         mlen += bytes;
1138
1139         if (!(bytes_in_mbuf -= bytes)) {
1140             MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1141             tm = tm->m_next;
1142             if (tm == NULL) {
1143                 m_freem(m);
1144                 if_printf(ifp, "read(): No mbuf nth\n");
1145                 if (wlhwrst(sc) != TRUE) {
1146                     sc->hacr &= ~HACR_INTRON;
1147                     CMD(sc);  /* turn off interrupts */
1148                     if_printf(ifp, "read(): hwrst trouble.\n");
1149                 }
1150                 return 0;
1151             }
1152             mlen = 0;
1153             tm->m_len = MLEN;
1154             bytes_in_mbuf = MLEN;
1155             mb_p = mtod(tm, u_char *);
1156         } else {
1157             mb_p += bytes;
1158         }
1159
1160         if (!(bytes_in_msg  -= bytes)) {
1161             if (rbd.status & RBD_SW_EOF ||
1162                 rbd.next_rbd_offset == I82586NULL) {
1163                 tm->m_len = mlen;
1164                 break;
1165             } else {
1166                 outw(PIOR1(base), rbd.next_rbd_offset);
1167                 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1168                 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1169             }
1170         } else {
1171             rbd.buffer_addr += bytes;
1172         }
1173
1174         bytes = min(bytes_in_mbuf, bytes_in_msg);
1175     }
1176
1177     m->m_pkthdr.len = clen;
1178
1179     /*
1180      * If hw is in promiscuous mode (note that I said hardware, not if
1181      * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1182      * packet and the MAC dst is not us, drop it.  This check in normally
1183      * inside ether_input(), but IFF_MULTI causes hw promisc without
1184      * a bpf listener, so this is wrong.
1185      *          Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1186      */
1187     /*
1188      * TBD: also discard packets where NWID does not match.
1189      * However, there does not appear to be a way to read the nwid
1190      * for a received packet.  -gdt 1998-08-07
1191      */
1192     if (
1193 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1194         (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1195 #else
1196         /* hw is in promisc mode if this is true */
1197         (sc->mode & (MOD_PROM | MOD_ENAL))
1198 #endif
1199         &&
1200         (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1201         bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1202              sizeof(eh.ether_dhost)) != 0 ) {
1203       m_freem(m);
1204       return 1;
1205     }
1206
1207 #ifdef WLDEBUG
1208     if (ifp->if_flags & IFF_DEBUG)
1209         if_printf(ifp, "wlrecv %d bytes\n", clen);
1210 #endif
1211
1212 #ifdef WLCACHE
1213     wl_cache_store(sc, base, &eh, m);
1214 #endif
1215
1216     /*
1217      * received packet is now in a chain of mbuf's.  next step is
1218      * to pass the packet upwards.
1219      *
1220      */
1221     ifp->if_input(ifp, m);
1222     return 1;
1223 }
1224
1225 /*
1226  * wlioctl:
1227  *
1228  *      This routine processes an ioctl request from the "if" layer
1229  *      above.
1230  *
1231  * input        : pointer the appropriate "if" struct, command and data
1232  * output       : based on command appropriate action is taken on the
1233  *                WaveLAN board(s) or related structures
1234  * return       : error is returned containing exit conditions
1235  *
1236  */
1237 static int
1238 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1239 {
1240     struct ifreq        *ifr = (struct ifreq *)data;
1241     struct wl_softc     *sc = ifp->if_softc;
1242     short               base = sc->base;
1243     short               mode = 0;
1244     int                 error = 0;
1245     int                 irq, irqval, i, isroot, size;
1246     caddr_t             up;
1247     char *              cpt;
1248     struct thread *td = curthread; /* XXX */
1249         
1250
1251 #ifdef WLDEBUG
1252     if (ifp->if_flags & IFF_DEBUG)
1253         if_printf(ifp, "entered wlioctl()\n");
1254 #endif
1255     switch (cmd) {
1256     case SIOCSIFFLAGS:
1257         if (ifp->if_flags & IFF_ALLMULTI) {
1258             mode |= MOD_ENAL;
1259         }
1260         if (ifp->if_flags & IFF_PROMISC) {
1261             mode |= MOD_PROM;
1262         }
1263         if(ifp->if_flags & IFF_LINK0) {
1264             mode |= MOD_PROM;
1265         }
1266         /*
1267          * force a complete reset if the recieve multicast/
1268          * promiscuous mode changes so that these take 
1269          * effect immediately.
1270          *
1271          */
1272         if (sc->mode != mode) {
1273             sc->mode = mode;
1274             if (sc->flags & DSF_RUNNING) {
1275                 sc->flags &= ~DSF_RUNNING;
1276                 wlinit(sc);
1277             }
1278         }
1279         /* if interface is marked DOWN and still running then
1280          * stop it.
1281          */
1282         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1283             if_printf(ifp, "ioctl(): board is not running\n");
1284             sc->flags &= ~DSF_RUNNING;
1285             sc->hacr &= ~HACR_INTRON;
1286             CMD(sc);              /* turn off interrupts */
1287         } 
1288         /* else if interface is UP and RUNNING, start it
1289                 */
1290         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1291             wlinit(sc);
1292         }
1293   
1294         /* if WLDEBUG set on interface, then kprintf rf-modem regs
1295         */
1296         if(ifp->if_flags & IFF_DEBUG)
1297             wlmmcstat(sc);
1298         break;
1299 #if     MULTICAST
1300     case SIOCADDMULTI:
1301     case SIOCDELMULTI:
1302
1303 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1304         if (cmd == SIOCADDMULTI) {
1305             error = ether_addmulti(ifr, &sc->wl_ac);
1306         }
1307         else {
1308             error = ether_delmulti(ifr, &sc->wl_ac);
1309         }
1310
1311         /* see if we should be in all multicast mode
1312          * note that 82586 cannot do that, must simulate with
1313          * promiscuous mode
1314          */
1315         if (check_allmulti(sc)) {
1316                 ifp->if_flags |=  IFF_ALLMULTI;
1317                 sc->mode |= MOD_ENAL;
1318                 sc->flags &= ~DSF_RUNNING;
1319                 wlinit(sc);
1320                 error = 0;
1321                 break;
1322         }
1323
1324         if (error == ENETRESET) {
1325             if(sc->flags & DSF_RUNNING) {
1326                 sc->flags &= ~DSF_RUNNING;
1327                 wlinit(sc);
1328             }
1329             error = 0;
1330         }
1331 #else
1332         wlinit(sc);
1333 #endif
1334         break;
1335 #endif  /* MULTICAST */
1336
1337     /* DEVICE SPECIFIC */
1338
1339
1340         /* copy the PSA out to the caller */
1341     case SIOCGWLPSA:
1342         /* pointer to buffer in user space */
1343         up = (void *)ifr->ifr_data;
1344         /* work out if they're root */
1345         isroot = (priv_check(td, PRIV_ROOT) == 0);
1346         
1347         for (i = 0; i < 0x40; i++) {
1348             /* don't hand the DES key out to non-root users */
1349             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1350                 continue;
1351             if (subyte((up + i), sc->psa[i]))
1352                 return(EFAULT);
1353         }
1354         break;
1355
1356
1357         /* copy the PSA in from the caller; we only copy _some_ values */
1358     case SIOCSWLPSA:
1359         /* root only */
1360         if ((error = priv_check(td, PRIV_ROOT)))
1361             break;
1362         error = EINVAL; /* assume the worst */
1363         /* pointer to buffer in user space containing data */
1364         up = (void *)ifr->ifr_data;
1365         
1366         /* check validity of input range */
1367         for (i = 0; i < 0x40; i++)
1368             if (fubyte(up + i) < 0)
1369                 return(EFAULT);
1370
1371         /* check IRQ value */
1372         irqval = fubyte(up+WLPSA_IRQNO);
1373         for (irq = 15; irq >= 0; irq--)
1374             if(irqvals[irq] == irqval)
1375                 break;
1376         if (irq == 0)                   /* oops */
1377             break;
1378         /* new IRQ */
1379         sc->psa[WLPSA_IRQNO] = irqval;
1380
1381         /* local MAC */
1382         for (i = 0; i < 6; i++)
1383             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1384                 
1385         /* MAC select */        
1386         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1387         
1388         /* default nwid */
1389         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1390         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1391
1392         error = 0;
1393         wlsetpsa(sc);           /* update the PSA */
1394         break;
1395
1396
1397         /* get the current NWID out of the sc since we stored it there */
1398     case SIOCGWLCNWID:
1399         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1400         break;
1401
1402
1403         /*
1404          * change the nwid dynamically.  This
1405          * ONLY changes the radio modem and does not
1406          * change the PSA.
1407          *
1408          * 2 steps:
1409          *      1. save in softc "soft registers"
1410          *      2. save in radio modem (MMC)
1411          */
1412     case SIOCSWLCNWID:
1413         /* root only */
1414         if ((error = priv_check(td, PRIV_ROOT)))
1415             break;
1416         if (!(ifp->if_flags & IFF_UP)) {
1417             error = EIO;        /* only allowed while up */
1418         } else {
1419             /* 
1420              * soft c nwid shadows radio modem setting
1421              */
1422             sc->nwid[0] = (int)ifr->ifr_data >> 8;
1423             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1424             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1425             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1426         }
1427         break;
1428
1429         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
1430     case SIOCGWLEEPROM:
1431         /* root only */
1432         if ((error = priv_check(td, PRIV_ROOT)))
1433             break;
1434         /* pointer to buffer in user space */
1435         up = (void *)ifr->ifr_data;
1436         
1437         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
1438             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
1439             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
1440                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
1441             DELAY(40);                          /* 2.4 Gz                   */
1442             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
1443                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1444                ) return(EFAULT);                /* 2.4 Gz:                  */
1445             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
1446                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
1447                ) return(EFAULT);                /* 2.4 Gz:                  */
1448         }
1449         break;
1450
1451 #ifdef WLCACHE
1452         /* zero (Delete) the wl cache */
1453     case SIOCDWLCACHE:
1454         /* root only */
1455         if ((error = priv_check(td, PRIV_ROOT)))
1456             break;
1457         wl_cache_zero(sc);
1458         break;
1459
1460         /* read out the number of used cache elements */
1461     case SIOCGWLCITEM:
1462         ifr->ifr_data = (caddr_t) sc->w_sigitems;
1463         break;
1464
1465         /* read out the wl cache */
1466     case SIOCGWLCACHE:
1467         /* pointer to buffer in user space */
1468         up = (void *)ifr->ifr_data;
1469         cpt = (char *) &sc->w_sigcache[0];
1470         size = sc->w_sigitems * sizeof(struct w_sigcache);
1471         
1472         for (i = 0; i < size; i++) {
1473             if (subyte((up + i), *cpt++))
1474                 return(EFAULT);
1475         }
1476         break;
1477 #endif
1478
1479     default:
1480         error = ether_ioctl(ifp, cmd, data);
1481         break;
1482     }
1483     return (error);
1484 }
1485
1486 /*
1487  * wlwatchdog():
1488  *
1489  * Called if the timer set in wlstart expires before an interrupt is received
1490  * from the wavelan.   It seems to lose interrupts sometimes.
1491  * The watchdog routine gets called if the transmitter failed to interrupt
1492  *
1493  * input        : which board is timing out
1494  * output       : board reset 
1495  *
1496  */
1497 static void
1498 wlwatchdog(void *vsc)
1499 {
1500     struct wl_softc *sc = vsc;
1501     struct ifnet *ifp = &sc->wl_if;
1502
1503     lwkt_serialize_enter(ifp->if_serializer);
1504     log(LOG_ERR, "%s: wavelan device timeout on xmit\n", sc->wl_if.if_xname);
1505     sc->wl_if.if_oerrors++;
1506     wlinit(sc);
1507     lwkt_serialize_exit(ifp->if_serializer);
1508 }
1509
1510 /*
1511  * wlintr:
1512  *
1513  *      This function is the interrupt handler for the WaveLAN
1514  *      board.  This routine will be called whenever either a packet
1515  *      is received, or a packet has successfully been transfered and
1516  *      the unit is ready to transmit another packet.
1517  *
1518  * input        : softc pointer for this interface
1519  * output       : either a packet is received, or a packet is transfered
1520  *
1521  */
1522 static void
1523 wlintr(void *arg)
1524 {
1525     struct wl_softc *sc = arg;
1526     struct ifnet *ifp = &sc->wl_if;
1527     short               base = sc->base;
1528     int                 ac_status;
1529     u_short             int_type, int_type1;
1530
1531 #ifdef WLDEBUG
1532     if (ifp->if_flags & IFF_DEBUG)
1533         if_printf(ifp, "wlintr() called\n");
1534 #endif
1535
1536     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1537         /* handle interrupt from the modem management controler */
1538         /* This will clear the interrupt condition */ 
1539         wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1540     }
1541
1542     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
1543         /* commented out. jrb.  it happens when reinit occurs
1544            if_printf(ifp, "%s: int_type %x, dump follows\n",
1545                      __func__, int_type);
1546            wldump(sc);
1547            */
1548         return;
1549     }
1550
1551     if (gathersnr)
1552         getsnr(sc);
1553     for(;;) {
1554         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
1555         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1556         if (int_type == 0)                      /* no interrupts left */
1557             break;
1558
1559         int_type1 = wlack(sc);                  /* acknowledge interrupt(s) */
1560         /* make sure no bits disappeared (others may appear) */
1561         if ((int_type & int_type1) != int_type) {
1562             if_printf(ifp, "wlack() int bits disappeared: "
1563                       "%04x != int_type %04x\n", int_type1, int_type);
1564         }
1565         int_type = int_type1;                   /* go with the new status */
1566         /* 
1567          * incoming packet
1568          */
1569         if (int_type & SCB_SW_FR) {
1570             ifp->if_ipackets++;
1571             wlrcv(sc);
1572         }
1573         /*
1574          * receiver not ready
1575          */
1576         if (int_type & SCB_SW_RNR) {
1577             ifp->if_ierrors++;
1578 #ifdef  WLDEBUG
1579             if (ifp->if_flags & IFF_DEBUG) {
1580                 if_printf(ifp, "intr(): receiver overrun! begin_fd = %x\n",
1581                           sc->begin_fd);
1582             }
1583 #endif
1584             wlrustrt(sc);
1585         }
1586         /*
1587          * CU not ready
1588          */
1589         if (int_type & SCB_SW_CNA) {
1590             /*
1591              * At present, we don't care about CNA's.  We
1592              * believe they are a side effect of XMT.
1593              */
1594         }
1595         if (int_type & SCB_SW_CX) {
1596             /*
1597              * At present, we only request Interrupt for
1598              * XMT.
1599              */
1600             outw(PIOR1(base), OFFSET_CU);       /* get command status */
1601             ac_status = inw(PIOP1(base));
1602
1603             if (xmt_watch) {                    /* report some anomalies */
1604
1605                 if (sc->tbusy == 0) {
1606                     if_printf(ifp, "xmt intr but not busy, CU %04x\n",
1607                               ac_status);
1608                 }
1609                 if (ac_status == 0) {
1610                     if_printf(ifp, "xmt intr but ac_status == 0\n");
1611                 }
1612                 if (ac_status & AC_SW_A) {
1613                     if_printf(ifp, "xmt aborted\n");
1614                 }
1615 #ifdef  notdef
1616                 if (ac_status & TC_CARRIER) {
1617                     if_printf(ifp, "no carrier\n");
1618                 }
1619 #endif  /* notdef */
1620                 if (ac_status & TC_CLS) {
1621                     if_printf(ifp, "no CTS\n");
1622                 }
1623                 if (ac_status & TC_DMA) {
1624                     if_printf(ifp, "DMA underrun\n");
1625                 }
1626                 if (ac_status & TC_DEFER) {
1627                     if_printf(ifp, "xmt deferred\n");
1628                 }
1629                 if (ac_status & TC_SQE) {
1630                     if_printf(ifp, "heart beat\n");
1631                 }
1632                 if (ac_status & TC_COLLISION) {
1633                     if_printf(ifp, "too many collisions\n");
1634                 }
1635             }
1636             /* if the transmit actually failed, or returned some status */
1637             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1638                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1639                     ifp->if_oerrors++;
1640                 }
1641
1642                 /* count collisions */
1643                 ifp->if_collisions += (ac_status & 0xf);
1644                 /* if TC_COLLISION set and collision count zero, 16 collisions */
1645                 if ((ac_status & 0x20) == 0x20) {
1646                     ifp->if_collisions += 0x10;
1647                 }
1648             }
1649             sc->tbusy = 0;
1650             callout_stop(&sc->watchdog_ch);
1651             ifp->if_flags &= ~IFF_OACTIVE;
1652             if_devstart(ifp);
1653         }
1654     }
1655 }
1656
1657 /*
1658  * wlrcv:
1659  *
1660  *      This routine is called by the interrupt handler to initiate a
1661  *      packet transfer from the board to the "if" layer above this
1662  *      driver.  This routine checks if a buffer has been successfully
1663  *      received by the WaveLAN.  If so, the routine wlread is called
1664  *      to do the actual transfer of the board data (including the
1665  *      ethernet header) into a packet (consisting of an mbuf chain).
1666  *
1667  * input        : softc pointer for this interface
1668  * output       : if a packet is available, it is "sent up"
1669  *
1670  */
1671 static void
1672 wlrcv(struct wl_softc *sc)
1673 {
1674     short       base = sc->base;
1675     u_short     fd_p, status, offset, link_offset;
1676
1677 #ifdef WLDEBUG
1678     if (sc->wl_if.if_flags & IFF_DEBUG)
1679         if_printf(&sc->wl_if, "entered wlrcv()\n");
1680 #endif
1681     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1682
1683         outw(PIOR0(base), fd_p + 0);    /* address of status */
1684         status = inw(PIOP0(base));
1685         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
1686         link_offset = inw(PIOP1(base));
1687         offset = inw(PIOP1(base));      /* rbd_offset */
1688         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1689             if (wlhwrst(sc) != TRUE)
1690                 if_printf(&sc->wl_if, "rcv(): hwrst ffff trouble.\n");
1691             return;
1692         } else if (status & AC_SW_C) {
1693             if (status == (RFD_DONE|RFD_RSC)) {
1694                 /* lost one */
1695 #ifdef  WLDEBUG
1696                 if (sc->wl_if.if_flags & IFF_DEBUG)
1697                     if_printf(&sc->wl_if, "RCV: RSC %x\n", status);
1698 #endif
1699                 sc->wl_if.if_ierrors++;
1700             } else if (!(status & RFD_OK)) {
1701                 if_printf(&sc->wl_if, "RCV: !OK %x\n", status);
1702                 sc->wl_if.if_ierrors++;
1703             } else if (status & 0xfff) {        /* can't happen */
1704                 if_printf(&sc->wl_if, "RCV: ERRs %x\n", status);
1705                 sc->wl_if.if_ierrors++;
1706             } else if (!wlread(sc, fd_p))
1707                 return;
1708
1709             if (!wlrequeue(sc, fd_p)) {
1710                 /* abort on chain error */
1711                 if (wlhwrst(sc) != TRUE)
1712                     if_printf(&sc->wl_if, "rcv(): hwrst trouble.\n");
1713                 return;
1714             }
1715             sc->begin_fd = link_offset;
1716         } else {
1717             break;
1718         }
1719     }
1720 }
1721
1722 /*
1723  * wlrequeue:
1724  *
1725  *      This routine puts rbd's used in the last receive back onto the
1726  *      free list for the next receive.
1727  *
1728  */
1729 static int
1730 wlrequeue(struct wl_softc *sc, u_short fd_p)
1731 {
1732     short               base = sc->base;
1733     fd_t                fd;
1734     u_short             l_rbdp, f_rbdp, rbd_offset;
1735
1736     outw(PIOR0(base), fd_p + 6);
1737     rbd_offset = inw(PIOP0(base));
1738     if ((f_rbdp = rbd_offset) != I82586NULL) {
1739         l_rbdp = f_rbdp;
1740         for(;;) {
1741             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
1742             if(inw(PIOP0(base)) & RBD_SW_EOF)
1743                 break;
1744             outw(PIOP0(base), 0);
1745             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
1746             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1747                 break;
1748         }
1749         outw(PIOP0(base), 0);
1750         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
1751         outw(PIOP0(base), I82586NULL);
1752         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
1753         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1754         outw(PIOR0(base), sc->end_rbd + 2);
1755         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
1756         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
1757         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1758         sc->end_rbd = l_rbdp;
1759     }
1760
1761     fd.status = 0;
1762     fd.command = AC_CW_EL;
1763     fd.link_offset = I82586NULL;
1764     fd.rbd_offset = I82586NULL;
1765     outw(PIOR1(base), fd_p);
1766     outsw(PIOP1(base), &fd, 8/2);
1767     
1768     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
1769     outw(PIOP1(base), 0);               /* command = 0 */
1770     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
1771     sc->end_fd = fd_p;
1772
1773     return 1;
1774 }
1775
1776 #ifdef  WLDEBUG
1777 static int xmt_debug = 0;
1778 #endif  /* WLDEBUG */
1779
1780 /*
1781  * wlxmt:
1782  *
1783  *      This routine fills in the appropriate registers and memory
1784  *      locations on the WaveLAN board and starts the board off on
1785  *      the transmit.
1786  *
1787  * input        : softc pointer for this interface, and a pointer to the mbuf
1788  * output       : board memory and registers are set for xfer and attention
1789  *
1790  */
1791 static void
1792 wlxmt(struct wl_softc *sc, struct mbuf *m)
1793 {
1794     u_short             xmtdata_p = OFFSET_TBUF;
1795     struct      mbuf                    *tm_p = m;
1796     struct ether_header *eh_p = mtod(m, struct ether_header *);
1797     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1798     u_short                             count = m->m_len - sizeof(struct ether_header);
1799     ac_t                                cb;
1800     u_short                             tbd_p = OFFSET_TBD;
1801     u_short                             len, clen = 0;
1802     short                               base = sc->base;
1803     int                                 spin;
1804         
1805 #ifdef WLDEBUG
1806     if (sc->wl_if.if_flags & IFF_DEBUG)
1807         if_printf(&sc->wl_if, "entered wlxmt()\n");
1808 #endif
1809
1810     cb.ac_status = 0;
1811     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1812     cb.ac_link_offset = I82586NULL;
1813     outw(PIOR1(base), OFFSET_CU);
1814     outsw(PIOP1(base), &cb, 6/2);
1815     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
1816     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1817     outw(PIOP1(base), eh_p->ether_type);
1818
1819 #ifdef  WLDEBUG
1820     if (sc->wl_if.if_flags & IFF_DEBUG) {
1821         if (xmt_debug) {
1822             if_printf(&sc->wl_if, "XMT    mbuf: L%d @%p ", count, (void *)mb_p);
1823             kprintf("ether type %x\n", eh_p->ether_type);
1824         }
1825     }
1826 #endif  /* WLDEBUG */
1827     outw(PIOR0(base), OFFSET_TBD);
1828     outw(PIOP0(base), 0);               /* act_count */
1829     outw(PIOR1(base), OFFSET_TBD + 4);
1830     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
1831     outw(PIOP1(base), 0);               /* buffer_base */
1832     for (;;) {
1833         if (count) {
1834             if (clen + count > WAVELAN_MTU)
1835                 break;
1836             if (count & 1)
1837                 len = count + 1;
1838             else
1839                 len = count;
1840             outw(PIOR1(base), xmtdata_p);
1841             outsw(PIOP1(base), mb_p, len/2);
1842             clen += count;
1843             outw(PIOR0(base), tbd_p);  /* address of act_count */
1844             outw(PIOP0(base), inw(PIOP0(base)) + count);
1845             xmtdata_p += len;
1846             if ((tm_p = tm_p->m_next) == NULL)
1847                 break;
1848             if (count & 1) {
1849                 /* go to the next descriptor */
1850                 outw(PIOR0(base), tbd_p + 2);
1851                 tbd_p += sizeof (tbd_t);
1852                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1853                 outw(PIOR0(base), tbd_p);
1854                 outw(PIOP0(base), 0);   /* act_count */
1855                 outw(PIOR1(base), tbd_p + 4);
1856                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1857                 outw(PIOP1(base), 0);         /* buffer_base */
1858                 /* at the end -> coallesce remaining mbufs */
1859                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1860                     wlsftwsleaze(&count, &mb_p, &tm_p);
1861                     continue;
1862                 }
1863                 /* next mbuf short -> coallesce as needed */
1864                 if ( (tm_p->m_next == NULL) ||
1865 #define HDW_THRESHOLD 55
1866                      tm_p->m_len > HDW_THRESHOLD)
1867                     /* ok */;
1868                 else {
1869                     wlhdwsleaze(&count, &mb_p, &tm_p);
1870                     continue;
1871                 }
1872             }
1873         } else if ((tm_p = tm_p->m_next) == NULL)
1874             break;
1875         count = tm_p->m_len;
1876         mb_p = mtod(tm_p, u_char *);
1877 #ifdef  WLDEBUG
1878         if (sc->wl_if.if_flags & IFF_DEBUG)
1879             if (xmt_debug)
1880                 if_printf(&sc->wl_if, "mbuf+ L%d @%p ", count, (void *)mb_p);
1881 #endif  /* WLDEBUG */
1882     }
1883 #ifdef  WLDEBUG
1884     if (sc->wl_if.if_flags & IFF_DEBUG)
1885         if (xmt_debug)
1886             if_printf(&sc->wl_if, "CLEN = %d\n", clen);
1887 #endif  /* WLDEBUG */
1888     outw(PIOR0(base), tbd_p);
1889     if (clen < ETHERMIN) {
1890         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1891         outw(PIOR1(base), xmtdata_p);
1892         while (clen < ETHERMIN) {
1893             outw(PIOP1(base), 0);
1894             clen += 2;
1895         }
1896     }   
1897     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1898     outw(PIOR0(base), tbd_p + 2);
1899     outw(PIOP0(base), I82586NULL);
1900 #ifdef  WLDEBUG
1901     if (sc->wl_if.if_flags & IFF_DEBUG) {
1902         if (xmt_debug) {
1903             wltbd(sc);
1904             kprintf("\n");
1905         }
1906     }
1907 #endif  /* WLDEBUG */
1908
1909     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
1910     /* 
1911      * wait for 586 to clear previous command, complain if it takes
1912      * too long
1913      */
1914     for (spin = 1;;spin = (spin + 1) % 10000) {
1915         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
1916             break;
1917         }
1918         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
1919             if_printf(&sc->wl_if, "slow accepting xmit\n");
1920         }
1921     }
1922     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
1923     SET_CHAN_ATTN(sc);
1924     
1925     m_freem(m);
1926
1927     /* XXX 
1928      * Pause to avoid transmit overrun problems.
1929      * The required delay tends to vary with platform type, and may be
1930      * related to interrupt loss.
1931      */
1932     if (wl_xmit_delay) {
1933         DELAY(wl_xmit_delay);
1934     }
1935 }
1936
1937 /*
1938  * wlbldru:
1939  *
1940  *      This function builds the linear linked lists of fd's and
1941  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
1942  *
1943  */
1944 static u_short
1945 wlbldru(struct wl_softc *sc)
1946 {
1947     short       base = sc->base;
1948     fd_t        fd;
1949     rbd_t       rbd;
1950     u_short     fd_p = OFFSET_RU;
1951     u_short     rbd_p = OFFSET_RBD;
1952     int         i;
1953
1954     sc->begin_fd = fd_p;
1955     for(i = 0; i < N_FD; i++) {
1956         fd.status = 0;
1957         fd.command = 0;
1958         fd.link_offset = fd_p + sizeof(fd_t);
1959         fd.rbd_offset = I82586NULL;
1960         outw(PIOR1(base), fd_p);
1961         outsw(PIOP1(base), &fd, 8/2);
1962         fd_p = fd.link_offset;
1963     }
1964     fd_p -= sizeof(fd_t);
1965     sc->end_fd = fd_p;
1966     outw(PIOR1(base), fd_p + 2);
1967     outw(PIOP1(base), AC_CW_EL);        /* command */
1968     outw(PIOP1(base), I82586NULL);      /* link_offset */
1969     fd_p = OFFSET_RU;
1970     
1971     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
1972     outw(PIOP0(base), rbd_p);
1973     outw(PIOR1(base), rbd_p);
1974     for(i = 0; i < N_RBD; i++) {
1975         rbd.status = 0;
1976         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1977         rbd.buffer_base = 0;
1978         rbd.size = RCVBUFSIZE;
1979         if (i != N_RBD-1) {
1980             rbd_p += sizeof(ru_t);
1981             rbd.next_rbd_offset = rbd_p;
1982         } else {
1983             rbd.next_rbd_offset = I82586NULL;
1984             rbd.size |= AC_CW_EL;
1985             sc->end_rbd = rbd_p;
1986         }
1987         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1988         outw(PIOR1(base), rbd_p);
1989     }
1990     return sc->begin_fd;
1991 }
1992
1993 /*
1994  * wlrustrt:
1995  *
1996  *      This routine starts the receive unit running.  First checks if the
1997  *      board is actually ready, then the board is instructed to receive
1998  *      packets again.
1999  *
2000  */
2001 static void
2002 wlrustrt(struct wl_softc *sc)
2003 {
2004     short               base = sc->base;
2005     u_short             rfa;
2006
2007 #ifdef WLDEBUG
2008     if (sc->wl_if.if_flags & IFF_DEBUG)
2009         if_printf(&sc->wl_if, "entered wlrustrt()\n");
2010 #endif
2011     outw(PIOR0(base), OFFSET_SCB);
2012     if (inw(PIOP0(base)) & SCB_RUS_READY){
2013         if_printf(&sc->wl_if, "wlrustrt: RUS_READY\n");
2014         return;
2015     }
2016
2017     outw(PIOR0(base), OFFSET_SCB + 2);
2018     outw(PIOP0(base), SCB_RU_STRT);             /* command */
2019     rfa = wlbldru(sc);
2020     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
2021     outw(PIOP0(base), rfa);
2022
2023     SET_CHAN_ATTN(sc);
2024 }
2025
2026 /*
2027  * wldiag:
2028  *
2029  *      This routine does a 586 op-code number 7, and obtains the
2030  *      diagnose status for the WaveLAN.
2031  *
2032  */
2033 static int
2034 wldiag(struct wl_softc *sc)
2035 {
2036     short base = sc->base;
2037     short status;
2038
2039 #ifdef WLDEBUG
2040     if (sc->wl_if.if_flags & IFF_DEBUG)
2041         if_printf(&sc->wl_if, "entered wldiag()\n");
2042 #endif
2043     outw(PIOR0(base), OFFSET_SCB);
2044     status = inw(PIOP0(base));
2045     if (status & SCB_SW_INT) {
2046                 /* state is 2000 which seems ok
2047                    if_printf(&sc->wl_if, "diag(): unexpected initial state %\n",
2048                    inw(PIOP0(base)));
2049                 */
2050         wlack(sc);
2051     }
2052     outw(PIOR1(base), OFFSET_CU);
2053     outw(PIOP1(base), 0);                       /* ac_status */
2054     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
2055     if(wlcmd(sc, "diag()") == 0)
2056         return 0;
2057     outw(PIOR0(base), OFFSET_CU);
2058     if (inw(PIOP0(base)) & 0x0800) {
2059         if_printf(&sc->wl_if, "i82586 Self Test failed!\n");
2060         return 0;
2061     }
2062     return TRUE;
2063 }
2064
2065 /*
2066  * wlconfig:
2067  *
2068  *      This routine does a standard config of the WaveLAN board.
2069  *
2070  */
2071 static int
2072 wlconfig(struct wl_softc *sc)
2073 {
2074     configure_t configure;
2075     short base = sc->base;
2076
2077 #if     MULTICAST
2078 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2079     struct ifmultiaddr *ifma;
2080     u_char *addrp;
2081 #else
2082     struct ether_multi *enm;
2083     struct ether_multistep step;
2084 #endif
2085     int cnt = 0;
2086 #endif  /* MULTICAST */
2087
2088 #ifdef WLDEBUG
2089     if (sc->wl_if.if_flags & IFF_DEBUG)
2090         if_printf(&sc->wl_if, "entered wlconfig()\n");
2091 #endif
2092     outw(PIOR0(base), OFFSET_SCB);
2093     if (inw(PIOP0(base)) & SCB_SW_INT) {
2094         /*
2095           if_printf(&sc->wl_if, "config(): unexpected initial state %x\n",
2096           inw(PIOP0(base)));
2097           */
2098     }
2099     wlack(sc);
2100
2101     outw(PIOR1(base), OFFSET_CU);
2102     outw(PIOP1(base), 0);                               /* ac_status */
2103     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
2104
2105 /* jrb hack */
2106     configure.fifolim_bytecnt   = 0x080c;
2107     configure.addrlen_mode      = 0x0600;
2108     configure.linprio_interframe        = 0x2060;
2109     configure.slot_time         = 0xf200;
2110     configure.hardware          = 0x0008;       /* tx even w/o CD */
2111     configure.min_frame_len     = 0x0040;
2112 #if 0
2113     /* This is the configuration block suggested by Marc Meertens
2114      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2115      * Ioannidis on 10 Nov 92.
2116      */
2117     configure.fifolim_bytecnt   = 0x040c;
2118     configure.addrlen_mode      = 0x0600;
2119     configure.linprio_interframe        = 0x2060;
2120     configure.slot_time         = 0xf000;
2121     configure.hardware          = 0x0008;       /* tx even w/o CD */
2122     configure.min_frame_len     = 0x0040;
2123 #else
2124     /*
2125      * below is the default board configuration from p2-28 from 586 book
2126      */
2127     configure.fifolim_bytecnt   = 0x080c;
2128     configure.addrlen_mode      = 0x2600;
2129     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
2130     configure.slot_time         = 0xf00c;       /* slottime=12    */
2131     configure.hardware          = 0x0008;       /* tx even w/o CD */
2132     configure.min_frame_len     = 0x0040;
2133 #endif
2134     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2135         configure.hardware |= 1;
2136     }
2137     outw(PIOR1(base), OFFSET_CU + 6);
2138     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2139
2140     if(wlcmd(sc, "config()-configure") == 0)
2141         return 0;
2142 #if     MULTICAST
2143     outw(PIOR1(base), OFFSET_CU);
2144     outw(PIOP1(base), 0);                               /* ac_status */
2145     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
2146     outw(PIOR1(base), OFFSET_CU + 8);
2147 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2148     TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
2149         if (ifma->ifma_addr->sa_family != AF_LINK)
2150             continue;
2151         
2152         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2153         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2154         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2155         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2156         ++cnt;
2157     }
2158 #else
2159     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2160     while (enm != NULL) {
2161         unsigned int lo, hi;
2162         /* break if setting a multicast range, else we would crash */
2163         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2164                 break;
2165         }
2166         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2167             + enm->enm_addrlo[5];
2168         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2169             + enm->enm_addrhi[5];
2170         while(lo <= hi) {
2171             outw(PIOP1(base),enm->enm_addrlo[0] +
2172                  (enm->enm_addrlo[1] << 8));
2173             outw(PIOP1(base),enm->enm_addrlo[2] +
2174                  ((lo >> 8) & 0xff00));
2175             outw(PIOP1(base), ((lo >> 8) & 0xff) +
2176                  ((lo << 8) & 0xff00));
2177 /* #define MCASTDEBUG */
2178 #ifdef MCASTDEBUG
2179 kprintf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2180                 enm->enm_addrlo[0],
2181                 enm->enm_addrlo[1],
2182                 enm->enm_addrlo[2],
2183                 enm->enm_addrlo[3],
2184                 enm->enm_addrlo[4],
2185                 enm->enm_addrlo[5]);
2186 #endif
2187             ++cnt;
2188             ++lo;
2189         }
2190         ETHER_NEXT_MULTI(step, enm);
2191     }
2192 #endif
2193     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
2194     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2195     if(wlcmd(sc, "config()-mcaddress") == 0)
2196         return 0;
2197 #endif  /* MULTICAST */
2198
2199     outw(PIOR1(base), OFFSET_CU);
2200     outw(PIOP1(base), 0);                               /* ac_status */
2201     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
2202     outw(PIOR1(base), OFFSET_CU + 6);
2203     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2204
2205     if(wlcmd(sc, "config()-address") == 0)
2206         return(0);
2207
2208     wlinitmmc(sc);
2209
2210     return(1);
2211 }
2212
2213 /*
2214  * wlcmd:
2215  *
2216  * Set channel attention bit and busy wait until command has
2217  * completed. Then acknowledge the command completion.
2218  */
2219 static int
2220 wlcmd(struct wl_softc *sc, const char *str)
2221 {
2222     short base = sc->base;
2223     int i;
2224         
2225     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2226     outw(PIOP0(base), SCB_CU_STRT);
2227     
2228     SET_CHAN_ATTN(sc);
2229     
2230     outw(PIOR0(base), OFFSET_CU);
2231     for(i = 0; i < 0xffff; i++)
2232         if (inw(PIOP0(base)) & AC_SW_C)
2233             break;
2234     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2235         if_printf(&sc->wl_if, "%s failed; status = %d, inw = %x, outw = %x\n",
2236                   str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)),
2237                   inw(PIOR0(base)));
2238         outw(PIOR0(base), OFFSET_SCB);
2239         kprintf("scb_status %x\n", inw(PIOP0(base)));
2240         outw(PIOR0(base), OFFSET_SCB+2);
2241         kprintf("scb_command %x\n", inw(PIOP0(base)));
2242         outw(PIOR0(base), OFFSET_SCB+4);
2243         kprintf("scb_cbl %x\n", inw(PIOP0(base)));
2244         outw(PIOR0(base), OFFSET_CU+2);
2245         kprintf("cu_cmd %x\n", inw(PIOP0(base)));
2246         return(0);
2247     }
2248
2249     outw(PIOR0(base), OFFSET_SCB);
2250     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2251         /*
2252           if_printf(&sc->wl_if, "%s: unexpected final state %x\n",
2253           str, inw(PIOP0(base)));
2254           */
2255     }
2256     wlack(sc);
2257     return(TRUE);
2258 }       
2259
2260 /*
2261  * wlack: if the 82596 wants attention because it has finished
2262  * sending or receiving a packet, acknowledge its desire and
2263  * return bits indicating the kind of attention. wlack() returns
2264  * these bits so that the caller can service exactly the
2265  * conditions that wlack() acknowledged.
2266  */
2267 static int
2268 wlack(struct wl_softc *sc)
2269 {
2270     int i;
2271     u_short cmd;
2272     short base = sc->base;
2273
2274     outw(PIOR1(base), OFFSET_SCB);
2275     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2276         return(0);
2277 #ifdef WLDEBUG
2278     if (sc->wl_if.if_flags & IFF_DEBUG)
2279         if_printf(&sc->wl_if, "doing a wlack()\n");
2280 #endif
2281     outw(PIOP1(base), cmd);
2282     SET_CHAN_ATTN(sc);
2283     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
2284     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2285     if (i < 1)
2286         if_printf(&sc->wl_if, "wlack(): board not accepting command.\n");
2287     return(cmd);
2288 }
2289
2290 static void
2291 wltbd(struct wl_softc *sc)
2292 {
2293     short               base = sc->base;
2294     u_short             tbd_p = OFFSET_TBD;
2295     tbd_t               tbd;
2296     int                 i = 0;
2297     int                 sum = 0;
2298
2299     for (;;) {
2300         outw(PIOR1(base), tbd_p);
2301         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2302         sum += (tbd.act_count & ~TBD_SW_EOF);
2303         kprintf("%d: addr %x, count %d (%d), next %x, base %x\n",
2304                i++, tbd.buffer_addr,
2305                (tbd.act_count & ~TBD_SW_EOF), sum,
2306                tbd.next_tbd_offset, tbd.buffer_base);
2307         if (tbd.act_count & TBD_SW_EOF)
2308             break;
2309         tbd_p = tbd.next_tbd_offset;
2310     }
2311 }
2312
2313 static void
2314 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp)
2315 {
2316     struct mbuf *tm_p = *tm_pp;
2317     u_char              *mb_p;
2318     u_short             count = 0;
2319     u_char              *cp;
2320     int         len;
2321
2322     /*
2323      * can we get a run that will be coallesced or
2324      * that terminates before breaking
2325      */
2326     do {
2327         count += tm_p->m_len;
2328         if (tm_p->m_len & 1)
2329             break;
2330     } while ((tm_p = tm_p->m_next) != NULL);
2331     if ( (tm_p == NULL) ||
2332          count > HDW_THRESHOLD) {
2333         *countp = (*tm_pp)->m_len;
2334         *mb_pp = mtod((*tm_pp), u_char *);
2335         return;
2336     }
2337
2338     /* we need to copy */
2339     tm_p = *tm_pp;
2340     mb_p = *mb_pp;
2341     count = 0;
2342     cp = (u_char *) t_packet;
2343     for (;;) {
2344         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2345         count += len;
2346         if (count > HDW_THRESHOLD)
2347                         break;
2348         cp += len;
2349         if (tm_p->m_next == NULL)
2350             break;
2351         tm_p = tm_p->m_next;
2352     }
2353     *countp = count;
2354     *mb_pp = (u_char *) t_packet;
2355     *tm_pp = tm_p;
2356 }
2357
2358 static void
2359 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp)
2360 {
2361     struct mbuf *tm_p = *tm_pp;
2362     u_short             count = 0;
2363     u_char              *cp = (u_char *) t_packet;
2364     int                 len;
2365
2366     /* we need to copy */
2367     for (;;) {
2368         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2369         count += len;
2370         cp += len;
2371         if (tm_p->m_next == NULL)
2372             break;
2373         tm_p = tm_p->m_next;
2374     }
2375
2376     *countp = count;
2377     *mb_pp = (u_char *) t_packet;
2378     *tm_pp = tm_p;
2379 }
2380
2381 static void
2382 wlmmcstat(struct wl_softc *sc)
2383 {
2384     short       base = sc->base;
2385     u_short tmp;
2386
2387     if_printf(&sc->wl_if, "DCE_STATUS: 0x%x, ",
2388               wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2389     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2390     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2391     kprintf("Correct NWID's: %d, ", tmp);
2392     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2393     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2394     kprintf("Wrong NWID's: %d\n", tmp);
2395     kprintf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2396     kprintf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
2397            wlmmcread(base,MMC_SIGNAL_LVL),
2398            wlmmcread(base,MMC_SILENCE_LVL));
2399     kprintf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2400            wlmmcread(base,MMC_SIGN_QUAL),
2401            wlmmcread(base,MMC_NETW_ID_H),
2402            wlmmcread(base,MMC_NETW_ID_L),
2403            wlmmcread(base,MMC_DES_AVAIL));
2404 }
2405
2406 static u_short
2407 wlmmcread(u_int base, u_short reg)
2408 {
2409     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2410     outw(MMCR(base),reg << 1);
2411     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2412     return (u_short)inw(MMCR(base)) >> 8;
2413 }
2414
2415 static void
2416 getsnr(struct wl_softc *sc)
2417 {
2418     MMC_WRITE(MMC_FREEZE,1);
2419     /* 
2420      * SNR retrieval procedure :
2421      *
2422      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2423      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2424      */
2425     MMC_WRITE(MMC_FREEZE,0);
2426     /*
2427      * SNR is signal:silence ratio.
2428      */
2429 }
2430
2431 /*
2432 ** wlgetpsa
2433 **
2434 ** Reads the psa for the wavelan at (base) into (buf)
2435 */
2436 static void
2437 wlgetpsa(int base, u_char *buf)
2438 {
2439     int i;
2440
2441     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2442     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2443
2444     for (i = 0; i < 0x40; i++) {
2445         outw(PIOR2(base), i);
2446         buf[i] = inb(PIOP2(base));
2447     }
2448     PCMD(base, HACR_DEFAULT);
2449     PCMD(base, HACR_DEFAULT);
2450 }
2451
2452 /*
2453 ** wlsetpsa
2454 **
2455 ** Writes the psa for wavelan (unit) from the softc back to the
2456 ** board.  Updates the CRC and sets the CRC OK flag.
2457 **
2458 ** Do not call this when the board is operating, as it doesn't 
2459 ** preserve the hacr.
2460 */
2461 static void
2462 wlsetpsa(struct wl_softc *sc)
2463 {
2464     short       base = sc->base;
2465     int         i;
2466     u_short     crc;
2467
2468     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
2469     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2470     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2471     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
2472
2473     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2474     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2475     
2476     for (i = 0; i < 0x40; i++) {
2477         DELAY(DELAYCONST);
2478         outw(PIOR2(base),i);  /* write param memory */
2479         DELAY(DELAYCONST);
2480         outb(PIOP2(base), sc->psa[i]);
2481     }
2482     DELAY(DELAYCONST);
2483     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
2484     DELAY(DELAYCONST);
2485     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
2486     outb(PIOP2(base), 0xaa);    /* all OK */
2487     DELAY(DELAYCONST);
2488     
2489     PCMD(base, HACR_DEFAULT);
2490     PCMD(base, HACR_DEFAULT);
2491 }
2492
2493 /* 
2494 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2495 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2496 */
2497
2498 static u_int crc16_table[16] = { 
2499     0x0000, 0xCC01, 0xD801, 0x1400,
2500     0xF001, 0x3C00, 0x2800, 0xE401,
2501     0xA001, 0x6C00, 0x7800, 0xB401,
2502     0x5000, 0x9C01, 0x8801, 0x4400 
2503 };
2504
2505 static u_short
2506 wlpsacrc(u_char *buf)
2507 {
2508     u_short     crc = 0;
2509     int         i, r1;
2510     
2511     for (i = 0; i < 0x3d; i++, buf++) {
2512         /* lower 4 bits */
2513         r1 = crc16_table[crc & 0xF];
2514         crc = (crc >> 4) & 0x0FFF;
2515         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2516         
2517         /* upper 4 bits */
2518         r1 = crc16_table[crc & 0xF];
2519         crc = (crc >> 4) & 0x0FFF;
2520         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2521     }
2522     return(crc);
2523 }
2524 #ifdef WLCACHE
2525
2526 /*
2527  * wl_cache_store
2528  *
2529  * take input packet and cache various radio hw characteristics
2530  * indexed by MAC address.
2531  *
2532  * Some things to think about:
2533  *      note that no space is malloced. 
2534  *      We might hash the mac address if the cache were bigger.
2535  *      It is not clear that the cache is big enough.
2536  *              It is also not clear how big it should be.
2537  *      The cache is IP-specific.  We don't care about that as
2538  *              we want it to be IP-specific.
2539  *      The last N recv. packets are saved.  This will tend
2540  *              to reward agents and mobile hosts that beacon.
2541  *              That is probably fine for mobile ip.
2542  */
2543
2544 /* globals for wavelan signal strength cache */
2545 /* this should go into softc structure above. 
2546 */
2547
2548 /* set true if you want to limit cache items to broadcast/mcast 
2549  * only packets (not unicast)
2550  */
2551 static int wl_cache_mcastonly = 1;
2552 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
2553         &wl_cache_mcastonly, 0, "");
2554
2555 /* set true if you want to limit cache items to IP packets only
2556 */
2557 static int wl_cache_iponly = 1;
2558 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
2559         &wl_cache_iponly, 0, "");
2560
2561 /* zero out the cache
2562 */
2563 static void
2564 wl_cache_zero(struct wl_softc *sc)
2565 {
2566         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2567         sc->w_sigitems = 0;
2568         sc->w_nextcache = 0;
2569         sc->w_wrapindex = 0;
2570 }
2571
2572 /* store hw signal info in cache.
2573  * index is MAC address, but an ip src gets stored too
2574  * There are two filters here controllable via sysctl:
2575  *      throw out unicast (on by default, but can be turned off)
2576  *      throw out non-ip (on by default, but can be turned off)
2577  */
2578 static void
2579 wl_cache_store(struct wl_softc *sc, int base, struct ether_header *eh,
2580                struct mbuf *m)
2581 {
2582         struct ip *ip = NULL;   /* Avoid GCC warning */
2583         int i;
2584         int signal, silence;
2585         int w_insertcache;   /* computed index for cache entry storage */
2586         int ipflag = wl_cache_iponly;
2587
2588         /* filters:
2589          * 1. ip only
2590          * 2. configurable filter to throw out unicast packets,
2591          * keep multicast only.
2592          */
2593  
2594 #ifdef INET
2595         /* reject if not IP packet
2596         */
2597         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2598                 return;
2599         }
2600
2601         /* check if broadcast or multicast packet.  we toss
2602          * unicast packets
2603          */
2604         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2605                 return;
2606         }
2607
2608         /* find the ip header.  we want to store the ip_src
2609          * address.  use the mtod macro(in mbuf.h) 
2610          * to typecast m to struct ip *
2611          */
2612         if (ipflag) {
2613                 ip = mtod(m, struct ip *);
2614         }
2615         
2616         /* do a linear search for a matching MAC address 
2617          * in the cache table
2618          * . MAC address is 6 bytes,
2619          * . var w_nextcache holds total number of entries already cached
2620          */
2621         for(i = 0; i < sc->w_nextcache; i++) {
2622                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
2623                         /* Match!,
2624                          * so we already have this entry,
2625                          * update the data, and LRU age
2626                          */
2627                         break;  
2628                 }
2629         }
2630
2631         /* did we find a matching mac address?
2632          * if yes, then overwrite a previously existing cache entry
2633          */
2634         if (i <  sc->w_nextcache )   {
2635                 w_insertcache = i; 
2636         }
2637         /* else, have a new address entry,so
2638          * add this new entry,
2639          * if table full, then we need to replace entry
2640          */
2641         else    {                          
2642
2643                 /* check for space in cache table 
2644                  * note: w_nextcache also holds number of entries
2645                  * added in the cache table 
2646                  */
2647                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2648                         w_insertcache = sc->w_nextcache;
2649                         sc->w_nextcache++;                 
2650                         sc->w_sigitems = sc->w_nextcache;
2651                 }
2652                 /* no space found, so simply wrap with wrap index
2653                  * and "zap" the next entry
2654                  */
2655                 else {
2656                         if (sc->w_wrapindex == MAXCACHEITEMS) {
2657                                 sc->w_wrapindex = 0;
2658                         }
2659                         w_insertcache = sc->w_wrapindex++;
2660                 }
2661         }
2662
2663         /* invariant: w_insertcache now points at some slot
2664          * in cache.
2665          */
2666         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2667                 log(LOG_ERR, 
2668                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2669                         w_insertcache, MAXCACHEITEMS);
2670                 return;
2671         }
2672
2673         /*  store items in cache
2674          *  .ipsrc
2675          *  .macsrc
2676          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
2677          */
2678         if (ipflag) {
2679                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2680         }
2681         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
2682         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2683         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2684         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2685         if (signal > 0)
2686                 sc->w_sigcache[w_insertcache].snr = 
2687                         signal - silence;
2688         else
2689                 sc->w_sigcache[w_insertcache].snr = 0;
2690 #endif /* INET */
2691
2692 }
2693 #endif /* WLCACHE */
2694
2695 /*
2696  * determine if in all multicast mode or not
2697  * 
2698  * returns: 1 if IFF_ALLMULTI should be set
2699  *          else 0
2700  */
2701 #ifdef MULTICAST
2702
2703 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
2704 static int
2705 check_allmulti(struct wl_softc *sc)
2706 {
2707     short  base = sc->base;
2708     struct ether_multi *enm;
2709     struct ether_multistep step;
2710
2711     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2712     while (enm != NULL) {
2713         unsigned int lo, hi;
2714 #ifdef MDEBUG
2715                 kprintf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2716                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2717                 enm->enm_addrlo[5]);
2718                 kprintf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2719                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2720                 enm->enm_addrhi[5]);
2721 #endif
2722         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2723                 return(1);
2724         }
2725         ETHER_NEXT_MULTI(step, enm);
2726     }
2727     return(0);
2728 }
2729 #endif
2730 #endif