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