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