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