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