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